X

The leading edge of scripting languages and Oracle Database brought to you by the Data Access Development team

  • php |
    Wednesday, October 2, 2013

DTrace PHP Using Oracle Linux 'playground' Pre-Built Packages

By: Christopher Jones | Senior Principal Product Manager

We've released DTrace-enabled PHP 5.5.4 RPMs to make testing DTrace on Oracle Linux easier. As a result, the manual PHP install steps listed in Using PHP DTrace on Oracle Linux can be skipped. There are updated Betas of the "UEK3" Linux Kernel 3.8.13-16 and the dtrace-utils tools available too. With these, you now can DTrace PHP applications under Apache or with php-fpm, as well as command line PHP scripts.

This post updates the install instructions, and show some of the probe changes in the latest PHP OCI8 2.0 extension.

Install Oracle Linux and the UEK3 Kernel

  1. Follow the steps to install Oracle Linux and the UEK3 Kernel given in the earlier blog post Using PHP DTrace on Oracle Linux

  2. Once the 3.8.13-16 Linux Kernel is installed and booted, enable user space tracing:

    # modprobe fasttrap
    # chmod 666 /dev/dtrace/helper

    Instead of the chmod, you could instead use an acl package rule to limit device access to a specific user.

Pre-installation for PHP

  1. Install the Oracle client libraries that PHP will use, oracle-instantclient12.1-basic-12.1.0.1.0-1.x86_64.rpm.

    Users with a ULN subscription can get this package from the "Oracle Software for Oracle Linux 6 (x86_64)" channel.

    If you don't have a ULN support subscription, and instead use public-yum.oracle.com, then manually download and install the free Instant Client RPM from OTN:

    # rpm -i oracle-instantclient12.1-basic-12.1.0.1.0-1.x86_64.rpm
  2. Add the "playground" channel via the ULN interface (for ULN subscribers), or for public-yum users, manually edit /etc/yum.repos.d/public-yum-ol6.repo and add:

    [public_ol6_playground_latest]
    name=Latest mainline stable kernel for Oracle Linux 6 ($basearch) - Unsupported
    baseurl=http://public-yum.oracle.com/repo/OracleLinux/OL6/playground/latest/$basearch/
    gpgkey=http://public-yum.oracle.com/RPM-GPG-KEY-oracle-ol6
    gpgcheck=1
    enabled=1

    Note "playground" is an unsupported channel and NOT for PRODUCTION use. It contains the DTrace-enabled PHP 5.5.4 RPMS.

Install PHP

  1. Install PHP and the PHP OCI8 extension:

    # yum install php55 php55-oci8-12cR1
    [. . .]
    ================================================================================
    Package Arch Version Repository Size
    ================================================================================
    Installing:
    php55 x86_64 5.5.4-1.el6 public_ol6_playground_latest 1.4 M
    php55-oci8-12cR1 x86_64 5.5.4-3.el6 public_ol6_playground_latest 148 k
    Installing for dependencies:
    php55-cli x86_64 5.5.4-1.el6 public_ol6_playground_latest 2.7 M
    php55-common x86_64 5.5.4-1.el6 public_ol6_playground_latest 538 k
    Transaction Summary
    ================================================================================
    Install 4 Package(s)
    Total download size: 4.8 M
    Installed size: 17 M
    Is this ok [y/N]: y

    Other PHP packages are available too, but only core PHP and the PHP OCI8 extension have DTrace probes.

    Note that with the playground channel enabled, yum update will install a 3.11 kernel. If you reboot, make sure to select the 3.8.13 kernel for DTrace testing.

  2. Restart Apache:

    # service httpd restart

Use PHP and DTrace

  1. Create a PHP script, /var/www/html/oci8.php

    <?php
    error_reporting(E_ALL);
    ini_set('display_errors', 'On');
    function do_query($c, $sql)
    {
    $s = oci_parse($c, $sql);
    if (!$s)
    return;
    $r = oci_execute($s);
    if (!$r)
    return;
    echo "<table>\n";
    while (($row = oci_fetch_row($s)) != false) {
    echo "<tr>\n";
    foreach ($row as $item) {
    echo "<td>";
    echo $item!==null?htmlentities($item, ENT_QUOTES|ENT_SUBSTITUTE):"&nbsp;";
    echo "</td>\n";
    }
    echo "</tr>\n";
    }
    echo "</table>\n";
    }
    $c = oci_connect('hr', 'welcome', 'localhost/pdborcl');
    oci_set_client_identifier($c, "Chris");
    do_query($c, "select city from locations where rownum < 5 order by 1");
    ?>

    Change the connection credentials to those of your existing Oracle Database.

  2. Create a D script to trace the PHP OCI8 2.0.4 Probes, user_oci8.d:

    #!/usr/sbin/dtrace -Zqs
    php*:::oci8-connect-entry
    {
    printf("%lld: PHP connect-entry ", walltimestamp);
    printf("credentials=\"%s@", arg0 ? copyinstr(arg0) : "");
    printf("dbname=%s\" ", arg1 ? copyinstr(arg1) : "");
    printf("charset=\"%s\" ", arg2 ? copyinstr(arg2) : "");
    printf("session_mode=%ld ", (long)arg3);
    printf("persistent=%d ", (int)arg4);
    printf("exclusive=%d\n", (int)arg5);
    }
    php*:::oci8-connect-return
    {
    printf("%lld: PHP oci8-connect-return ", walltimestamp);
    printf("connection=0x%p\n", (void *)arg0);
    }
    php*:::oci8-connection-close
    {
    printf("%lld: PHP oci8-connect-close ", walltimestamp);
    printf("connection=0x%p\n", (void *)arg0);
    }
    php*:::oci8-error
    {
    printf("%lld: PHP oci8-error ", walltimestamp);
    printf("status=%d ", (int)arg0);
    printf("errcode=%ld\n", (long)arg1);
    }
    php*:::oci8-check-connection
    {
    printf("%lld: PHP oci8-check-connection ", walltimestamp);
    printf("connection=0x%p ", (void *)arg0);
    printf("client_id=\"%s\" ", arg1 ? copyinstr(arg1) : "");
    printf("is_open=%d ", arg2);
    printf("errcode=%ld ", (long)arg3);
    printf("server_status=%lu\n", (unsigned long)arg4);
    }
    php*:::oci8-sqltext
    {
    printf("%lld: PHP oci8-sqltext ", walltimestamp);
    printf("connection=0x%p ", (void *)arg0);
    printf("client_id=\"%s\" ", arg1 ? copyinstr(arg1) : "");
    printf("statement=0x%p ", (void *)arg2);
    printf("sql=\"%s\"\n", arg3 ? copyinstr(arg3) : "");
    }
    php*:::oci8-execute-mode
    {
    printf("%lld: PHP oci8-execute-mode ", walltimestamp);
    printf("connection=0x%p ", (void *)arg0);
    printf("client_id=\"%s\" ", arg1 ? copyinstr(arg1) : "");
    printf("statement=0x%p ", (void *)arg2);
    printf("mode=0x%x\n", arg3);
    }

    This prints each probe's arguments on a single, timestamp-prefixed line, which helps post-sorting the output in time order.

    The PHP OCI8 2.0.4 probe arguments have been enhanced from the PHP OCI8 2.0.2 probes described in Using PHP DTrace on Oracle Linux .

    If you want to trace the core PHP probes, they are described here.

  3. Start the D script:

    # ./user_oci8.d

    This will wait for probes to be fired. When you have finished testing, you can ^C this window.

  4. In a browser, load the PHP file: http://localhost/oci8.php. The web page will show query results. The probes that the D script used will fire and generate output (which I've manually wrapped to display cleanly in this blog post):

    # ./user_oci8.d
    1380749137317414976: PHP connect-entry
    credentials="hr@localhost/pdborcl"
    charset="" session_mode=0 persistent=0 exclusive=0
    1380749137354121877: PHP oci8-connect-return
    connection=0x7f453c087b68
    1380749137354326373: PHP oci8-sqltext
    connection=0x7f453c087b68 client_id="Chris"
    statement=0x7f453c086f08
    sql="select city from locations where rownum < 5 order by 1"
    1380749137354467732: PHP oci8-execute-mode
    connection=0x7f453c087b68 client_id="Chris"
    statement=0x7f453c086f08 mode=0x20
    1380749137355886348: PHP oci8-connect-close
    connection=0x7f453c087b68
    ^C

    The client identifier ("Chris") is a way for the application to tell the database which web user is executing statements, since commonly the database user ("hr") is the same for all web users.

    In addition to all the database monitoring that you do for a given client identifier, with DTrace you can use the client identifier to trace a particular user on the PHP side of the DB connection. To do this, your D script might contain::

    #!/usr/sbin/dtrace -Zqs
    php*:::oci8-sqltext
    / (char *)arg1 == "Chris" /
    {
    printf("%lld: PHP oci8-sqltext ", walltimestamp);
    printf("connection=0x%p ", (void *)arg0);
    printf("client_id=\"%s\" ", arg1 ? copyinstr(arg1) : "");
    printf("statement=0x%p ", (void *)arg2);
    printf("sql=\"%s\"\n", arg3 ? copyinstr(arg3) : "");
    }
    php*:::oci8-execute-mode
    / (char *)arg1 == "Chris" /
    {
    printf("%lld: PHP oci8-execute-mode ", walltimestamp);
    printf("connection=0x%p ", (void *)arg0);
    printf("client_id=\"%s\" ", arg1 ? copyinstr(arg1) : "");
    printf("statement=0x%p ", (void *)arg2);
    printf("mode=0x%x\n", arg3);
    }

    The probes will only fire when the specified client identifier was "Chris". This will be useful for debugging on a busy production machine (once UEK3 becomes "production"). You can trace only the statements that your test user is running.

Summary

DTrace is an 'always available' tracing utility useful for identifying performance and behavior issues in applications on Solaris and Oracle Linux. The PHP core and PHP OCI8 extensions have user probes that can be traced to efficiently identify PHP scripting problems.

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha
Oracle

Integrated Cloud Applications & Platform Services