├── xhprof_html ├── css │ ├── xh.css │ ├── tablesorter.pager.css │ └── xhprof.css ├── img │ ├── bg.gif │ ├── asc.gif │ └── desc.gif ├── favicon.ico ├── docs │ ├── sample-flat-view.jpg │ ├── sample-callgraph-image.jpg │ ├── sample-parent-child-view.jpg │ ├── sample-diff-report-flat-view.jpg │ └── sample-diff-report-parent-child-view.jpg ├── third-party │ ├── jquery │ │ ├── indicator.gif │ │ ├── LICENSE │ │ ├── jquery.tooltip.css │ │ ├── jquery.autocomplete.css │ │ ├── tablesorter.pager.js │ │ ├── jquery.tooltip.js │ │ └── tablesorter.min.js │ └── highcharts │ │ ├── highcharts.js │ │ └── LICENSE ├── callgraph.php └── index.php ├── extension ├── win32 │ ├── INSTALL │ ├── CONFIGURE │ ├── xhprof.dsw │ ├── deploy.bat │ ├── php_xhprof_win32.c │ ├── php_xhprof_win32.h │ ├── configure.vbs │ ├── xhprof.example.dsp │ └── README ├── config.m4 ├── tests │ ├── xhprof_004_inc.php │ ├── xhprof_004_require.php │ ├── common.php │ ├── xhprof_003.phpt │ ├── xhprof_008.phpt │ ├── xhprof_005.phpt │ ├── xhprof_002.phpt │ ├── xhprof_004.phpt │ ├── xhprof_006.phpt │ ├── xhprof_001.phpt │ └── xhprof_007.phpt └── php_xhprof.h ├── xhprof_lib ├── .gitignore ├── templates │ ├── footer.phtml │ ├── emptyBody.phtml │ ├── profTable.phtml │ ├── print_flat_data.phtml │ ├── profChart.phtml │ ├── header.phtml │ ├── chart.phtml │ ├── single_run_header_block.phtml │ └── diff_run_header_block.phtml ├── utils │ ├── xhprof_runs.php │ ├── common.php │ ├── xhprof_runs_pdo.php │ └── xhprof_runs_mysql.php ├── display │ └── typeahead_common.php └── config.sample.php ├── CREDITS ├── external ├── footer.php └── header.php ├── .gitignore ├── README.HIGHCHARTS ├── INSTALL ├── examples └── sample.php ├── README.markdown ├── CHANGELOG ├── package.xml └── LICENSE /xhprof_html/css/xh.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/win32/INSTALL: -------------------------------------------------------------------------------- 1 | see README -------------------------------------------------------------------------------- /extension/win32/CONFIGURE: -------------------------------------------------------------------------------- 1 | see README -------------------------------------------------------------------------------- /xhprof_lib/.gitignore: -------------------------------------------------------------------------------- 1 | config.php 2 | -------------------------------------------------------------------------------- /xhprof_lib/templates/footer.phtml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /xhprof_lib/utils/xhprof_runs.php: -------------------------------------------------------------------------------- 1 | xhprof_runs_mysql.php -------------------------------------------------------------------------------- /xhprof_lib/templates/emptyBody.phtml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /xhprof_html/img/bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgdm/xhprof/master/xhprof_html/img/bg.gif -------------------------------------------------------------------------------- /xhprof_html/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgdm/xhprof/master/xhprof_html/favicon.ico -------------------------------------------------------------------------------- /xhprof_html/img/asc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgdm/xhprof/master/xhprof_html/img/asc.gif -------------------------------------------------------------------------------- /xhprof_html/img/desc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgdm/xhprof/master/xhprof_html/img/desc.gif -------------------------------------------------------------------------------- /xhprof_html/docs/sample-flat-view.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgdm/xhprof/master/xhprof_html/docs/sample-flat-view.jpg -------------------------------------------------------------------------------- /xhprof_html/docs/sample-callgraph-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgdm/xhprof/master/xhprof_html/docs/sample-callgraph-image.jpg -------------------------------------------------------------------------------- /xhprof_html/third-party/jquery/indicator.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgdm/xhprof/master/xhprof_html/third-party/jquery/indicator.gif -------------------------------------------------------------------------------- /xhprof_html/docs/sample-parent-child-view.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgdm/xhprof/master/xhprof_html/docs/sample-parent-child-view.jpg -------------------------------------------------------------------------------- /xhprof_html/docs/sample-diff-report-flat-view.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgdm/xhprof/master/xhprof_html/docs/sample-diff-report-flat-view.jpg -------------------------------------------------------------------------------- /xhprof_html/third-party/highcharts/highcharts.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgdm/xhprof/master/xhprof_html/third-party/highcharts/highcharts.js -------------------------------------------------------------------------------- /xhprof_html/docs/sample-diff-report-parent-child-view.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgdm/xhprof/master/xhprof_html/docs/sample-diff-report-parent-child-view.jpg -------------------------------------------------------------------------------- /extension/config.m4: -------------------------------------------------------------------------------- 1 | 2 | PHP_ARG_ENABLE(xhprof, whether to enable xhprof support, 3 | [ --enable-xhprof Enable xhprof support]) 4 | 5 | if test "$PHP_XHPROF" != "no"; then 6 | PHP_NEW_EXTENSION(xhprof, xhprof.c, $ext_shared) 7 | fi 8 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | Originally developed at Facebook, XHProf was open sourced in Mar, 2009. 2 | 3 | Creators: 4 | Changhao Jiang 5 | Kannan Muthukkaruppan 6 | Venkat Venkataramani 7 | Haiping Zhao 8 | 9 | Additional Contributors: 10 | George Cabrera - UI enhancements 11 | Paul Saab - FreeBSD port 12 | 13 | -------------------------------------------------------------------------------- /xhprof_html/third-party/jquery/LICENSE: -------------------------------------------------------------------------------- 1 | JQuery: 2 | http://jquery.com/ 3 | Copyright 2010, John Resig 4 | Dual licensed under the MIT or GPL Version 2 licenses. 5 | http://jquery.org/license 6 | 7 | 8 | Tablesorter: 9 | http://tablesorter.com/docs/ 10 | Copyright 2008, Christian Bach 11 | Dual licensed under MIT or GPL licenses. 12 | http://www.opensource.org/licenses/mit-license.php 13 | http://www.opensource.org/licenses/gpl-license.php 14 | -------------------------------------------------------------------------------- /extension/tests/xhprof_004_inc.php: -------------------------------------------------------------------------------- 1 | " 13 | // which represents the initialization block of a file. 14 | // 15 | 16 | $result1 = explode(" ", "abc def ghi"); 17 | 18 | $result2 = implode(",", $result1); 19 | 20 | echo $result2 . "\n"; 21 | 22 | foo(); 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /extension/tests/xhprof_004_require.php: -------------------------------------------------------------------------------- 1 | " 13 | // which represents the initialization block of a file. 14 | // 15 | 16 | $result1 = explode(" ", "abc def ghi"); 17 | 18 | $result2 = implode(",", $result1); 19 | 20 | $result3 = strlen($result2); 21 | 22 | echo $result3 . "\n"; 23 | 24 | bar(); 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /extension/win32/xhprof.dsw: -------------------------------------------------------------------------------- 1 | Microsoft Developer Studio Workspace File, Format Version 6.00 2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! 3 | 4 | ############################################################################### 5 | 6 | Project: "xhprof"=".\xhprof.dsp" - Package Owner=<4> 7 | 8 | Package=<5> 9 | {{{ 10 | }}} 11 | 12 | Package=<4> 13 | {{{ 14 | }}} 15 | 16 | ############################################################################### 17 | 18 | Global: 19 | 20 | Package=<5> 21 | {{{ 22 | }}} 23 | 24 | Package=<3> 25 | {{{ 26 | }}} 27 | 28 | ############################################################################### 29 | 30 | -------------------------------------------------------------------------------- /external/footer.php: -------------------------------------------------------------------------------- 1 | save_run($xhprof_data, $profiler_namespace, null, $_xhprof); 7 | if ($_xhprof['display'] === true) 8 | { 9 | // url to the XHProf UI libraries (change the host name and path) 10 | $profiler_url = sprintf($_xhprof['url'].'/index.php?run=%s&source=%s', $run_id, $profiler_namespace); 11 | echo 'Profiler output'; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /xhprof_html/third-party/jquery/jquery.tooltip.css: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Tooltip plugin 1.3 3 | * 4 | * http://bassistance.de/jquery-plugins/jquery-plugin-tooltip/ 5 | * http://docs.jquery.com/Plugins/Tooltip 6 | * 7 | * Copyright (c) 2006 - 2008 Jörn Zaefferer 8 | * 9 | * $Id: jquery.tooltip.css,v 1.1.1.1 2009/03/17 18:35:18 kannan Exp $ 10 | * 11 | * Dual licensed under the MIT and GPL licenses: 12 | * http://www.opensource.org/licenses/mit-license.php 13 | * http://www.gnu.org/licenses/gpl.html 14 | */ 15 | 16 | #tooltip { 17 | position: absolute; 18 | z-index: 3000; 19 | border: 1px solid #111; 20 | background-color: lightyellow; 21 | padding: 5px; 22 | opacity: 0.9; 23 | } 24 | #tooltip h3, #tooltip div { margin: 0; } 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | extension/.deps 2 | extension/.libs/ 3 | extension/Makefile 4 | extension/Makefile.fragments 5 | extension/Makefile.global 6 | extension/Makefile.objects 7 | extension/acinclude.m4 8 | extension/aclocal.m4 9 | extension/autom4te.cache/ 10 | extension/build/ 11 | extension/config.guess 12 | extension/config.h 13 | extension/config.h.in 14 | extension/config.log 15 | extension/config.nice 16 | extension/config.status 17 | extension/config.sub 18 | extension/configure 19 | extension/configure.in 20 | extension/install-sh 21 | extension/libtool 22 | extension/ltmain.sh 23 | extension/missing 24 | extension/mkinstalldirs 25 | extension/modules/ 26 | extension/run-tests.php 27 | extension/xhprof.la 28 | extension/xhprof.lo 29 | xhprof_lib/utils/xhprof_runs.php 30 | -------------------------------------------------------------------------------- /README.HIGHCHARTS: -------------------------------------------------------------------------------- 1 | The HighCharts graphing library is a kick ass JS graping library, free for non-commercial use. 2 | 3 | Since you may be using XHProf to aid the performance of a commercial site, a single blanket license 4 | has already been purchased. You can use XHProf with Highcharts on any site, you do _not_ need to 5 | purchase another license for Highcharts. If you decide to use HighCharts within another aspect 6 | of your site, you will need to handle licensing that seperately. 7 | 8 | 9 | 10 | The decision to use HighCharts was made as it easily supports multiple scales per axis, which makes 11 | displaying information on PMU, CPU, and WT easy on the main display pages (this is hard/impossible 12 | in the google graphs we looked at). 13 | 14 | 15 | Enjoy 16 | paul 17 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | -- This document is as yet incomplete -- 2 | 3 | 0. Install the XHProf extension for PHP 4 | 1. Extract everything into a directory somewhere 5 | 2. Create a symlink from xhprof_runs.php to the xprof_runs_.php directory in xhprof_lib\utils\ 6 | 3. Create the table required for xhprof_runs.php, there should be sample instructions inside that document alongside 7 | the constructor. 8 | 4. Edit xhprof_lib/config.php with your database credentials, control IPs, and other fun stuff 9 | 5. Load up index.php, ensure happiness 10 | 6. Edit the virtual host configuration for the site you'd like to profile to 11 | php_admin_value auto_prepend_file="/external/header.php" 12 | php_admin_value auto_append_file="/external/footer.php" 13 | 7. Bump your server, hope for the best 14 | 8. Hitting a file with ?_profile=1 should profile the page and give you a link at the bottom 15 | 16 | There's a decent blog post on setting this up, as well as tips on how to use it at: http://phpadvent.org/2010/profiling-with-xhgui-by-paul-reinheimer -------------------------------------------------------------------------------- /extension/tests/common.php: -------------------------------------------------------------------------------- 1 | $metrics) { 17 | echo str_pad($func, 40) . ":"; 18 | ksort($metrics); 19 | foreach ($metrics as $name => $value) { 20 | 21 | // Only call counts are stable. 22 | // Wild card everything else. We still print 23 | // the metric name to ensure it was collected. 24 | if ($name != "ct") { 25 | $value = "*"; 26 | } else { 27 | $value = str_pad($value, 8, " ", STR_PAD_LEFT); 28 | } 29 | 30 | echo " {$name}={$value};"; 31 | } 32 | echo "\n"; 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /xhprof_html/css/tablesorter.pager.css: -------------------------------------------------------------------------------- 1 | div.tablesorterPager { 2 | padding: 10px 0 10px 0; 3 | background-color: #D6D2C2; 4 | text-align: center; 5 | } 6 | div.tablesorterPager span { 7 | padding: 0 5px 0 5px; 8 | } 9 | div.tablesorterPager input.prev { 10 | width: auto; 11 | margin-right: 10px; 12 | } 13 | div.tablesorterPager input.next { 14 | width: auto; 15 | margin-left: 10px; 16 | } 17 | div.tablesorterPager input { 18 | font-size: 8px; 19 | width: 50px; 20 | border: 1px solid #330000; 21 | text-align: center; 22 | } 23 | table.tablesorter thead tr .header { 24 | background-image: url(../img/bg.gif); 25 | background-position:left center; 26 | background-repeat:no-repeat; 27 | cursor:pointer; 28 | padding-left:55px; 29 | } 30 | table.tablesorter thead tr .headerSortUp { 31 | background-image: url(../img/asc.gif); 32 | background-repeat:no-repeat; 33 | background-position:left center; 34 | } 35 | table.tablesorter thead tr .headerSortDown { 36 | background-image: url(../img/desc.gif); 37 | background-repeat:no-repeat; 38 | background-position:left center; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /xhprof_html/third-party/highcharts/LICENSE: -------------------------------------------------------------------------------- 1 | HighCharts Open Source License 2 | 3 | Copyright (c) 2010 Highslide Software 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software; and 14 | 15 | The Software may only be used in connection with XHProf, including any 16 | derivatives or forks of XHProf. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. -------------------------------------------------------------------------------- /examples/sample.php: -------------------------------------------------------------------------------- 1 | 0) { 5 | bar($x - 1); 6 | } 7 | } 8 | 9 | function foo() { 10 | for ($idx = 0; $idx < 5; $idx++) { 11 | bar($idx); 12 | $x = strlen("abc"); 13 | } 14 | } 15 | 16 | // start profiling 17 | xhprof_enable(); 18 | 19 | // run program 20 | foo(); 21 | 22 | // stop profiler 23 | $xhprof_data = xhprof_disable(); 24 | 25 | // display raw xhprof data for the profiler run 26 | echo "
";
32 | print_r($xhprof_data);
33 | echo "
"; 34 | 35 | 36 | $XHPROF_ROOT = realpath(dirname(__FILE__) .'/..'); 37 | include_once $XHPROF_ROOT . "/xhprof_lib/config.php"; 38 | include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_lib.php"; 39 | include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_runs.php"; 40 | 41 | // save raw data for this profiler run using default 42 | // implementation of iXHProfRuns. 43 | $xhprof_runs = new XHProfRuns_Default(); 44 | 45 | // save the run under a namespace "xhprof_foo" 46 | $run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_foo"); 47 | 48 | echo "
".
49 |      "".
50 |      "View the XH GUI for this run".
51 |      "\n".
52 |      "
\n"; 53 | -------------------------------------------------------------------------------- /xhprof_lib/templates/profTable.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 36 | 37 |
FunctionCall CountWall TimeCPUMemory UsagePeak Memory UsageExclusive Wall TimeExclusive CPUExclusive Memory UsageExclusive Peak Memory Usage
38 | -------------------------------------------------------------------------------- /xhprof_html/third-party/jquery/jquery.autocomplete.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Autocomplete - jQuery plugin 1.0.2 3 | * 4 | * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer 5 | * 6 | * Dual licensed under the MIT and GPL licenses: 7 | * http://www.opensource.org/licenses/mit-license.php 8 | * http://www.gnu.org/licenses/gpl.html 9 | * 10 | * Revision: $Id: jquery.autocomplete.css,v 1.1.1.1 2009/03/17 18:35:18 kannan Exp $ 11 | * 12 | */ 13 | 14 | .ac_results { 15 | padding: 0px; 16 | border: 1px solid black; 17 | background-color: white; 18 | overflow: hidden; 19 | z-index: 99999; 20 | } 21 | 22 | .ac_results ul { 23 | width: 100%; 24 | list-style-position: outside; 25 | list-style: none; 26 | padding: 0; 27 | margin: 0; 28 | } 29 | 30 | .ac_results li { 31 | margin: 0px; 32 | padding: 2px 5px; 33 | cursor: default; 34 | display: block; 35 | /* 36 | if width will be 100% horizontal scrollbar will apear 37 | when scroll mode will be used 38 | */ 39 | /*width: 100%;*/ 40 | font: menu; 41 | font-size: 12px; 42 | /* 43 | it is very important, if line-height not setted or setted 44 | in relative units scroll will be broken in firefox 45 | */ 46 | line-height: 16px; 47 | overflow: hidden; 48 | } 49 | 50 | .ac_loading { 51 | background: white url('indicator.gif') right center no-repeat; 52 | } 53 | 54 | .ac_odd { 55 | background-color: #eee; 56 | } 57 | 58 | .ac_over { 59 | background-color: #0A246A; 60 | color: white; 61 | } 62 | -------------------------------------------------------------------------------- /xhprof_lib/templates/print_flat_data.phtml: -------------------------------------------------------------------------------- 1 |


2 | 3 | 4 | $header"); 17 | else 18 | print(""); 19 | } 20 | print("\n"); 21 | 22 | if ($limit >= 0) { 23 | $limit = min($size, $limit); 24 | for($i=0; $i < $limit; $i++) { 25 | print_function_info($url_params, $flat_data[$i], $sort, $run1, $run2); 26 | } 27 | } else { 28 | // if $limit is negative, print abs($limit) items starting from the end 29 | $limit = min($size, abs($limit)); 30 | for($i=0; $i < $limit; $i++) { 31 | print_function_info($url_params, $flat_data[$size - $i - 1], $sort, $run1, $run2); 32 | } 33 | } 34 | print("
$header
"); 35 | 36 | // let's print the display all link at the bottom as well... 37 | if ($display_link) { 38 | echo '
' . $display_link . '
'; 39 | } -------------------------------------------------------------------------------- /extension/php_xhprof.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Facebook 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | #ifndef PHP_XHPROF_H 19 | #define PHP_XHPROF_H 20 | 21 | extern zend_module_entry xhprof_module_entry; 22 | #define phpext_xhprof_ptr &xhprof_module_entry 23 | 24 | #ifdef PHP_WIN32 25 | #define PHP_XHPROF_API __declspec(dllexport) 26 | #include "win32/php_xhprof_win32.h" 27 | #include "win32/php_xhprof_win32.c" 28 | #else 29 | #define PHP_XHPROF_API 30 | #endif 31 | 32 | #ifdef ZTS 33 | #include "TSRM.h" 34 | #endif 35 | 36 | /** 37 | * PHP default module methods 38 | */ 39 | PHP_MINIT_FUNCTION(xhprof); 40 | PHP_MSHUTDOWN_FUNCTION(xhprof); 41 | PHP_RINIT_FUNCTION(xhprof); 42 | PHP_RSHUTDOWN_FUNCTION(xhprof); 43 | PHP_MINFO_FUNCTION(xhprof); 44 | 45 | /** 46 | * declare methods available in PHP 47 | */ 48 | PHP_FUNCTION(xhprof_enable); 49 | PHP_FUNCTION(xhprof_disable); 50 | PHP_FUNCTION(xhprof_sample_enable); 51 | PHP_FUNCTION(xhprof_sample_disable); 52 | 53 | #endif /* PHP_XHPROF_H */ 54 | 55 | -------------------------------------------------------------------------------- /extension/tests/xhprof_003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | XHPRrof: Test Class Methods, Constructors, Destructors. 3 | Author: Kannan 4 | --FILE-- 5 | _attr = $attr; 15 | } 16 | 17 | private static function inner_static() { 18 | return C::$_static_attr; 19 | } 20 | 21 | public static function outer_static() { 22 | return C::inner_static(); 23 | } 24 | 25 | public function get_attr() { 26 | return $this->_attr; 27 | } 28 | 29 | function __destruct() { 30 | echo "Destroying class {$this->_attr}\n"; 31 | } 32 | } 33 | 34 | 35 | xhprof_enable(); 36 | 37 | // static methods 38 | echo C::outer_static() . "\n"; 39 | 40 | // constructor 41 | $obj = new C("Hello World"); 42 | 43 | // instance methods 44 | $obj->get_attr(); 45 | 46 | // destructor 47 | $obj = null; 48 | 49 | 50 | $output = xhprof_disable(); 51 | 52 | echo "Profiler data for 'Class' tests:\n"; 53 | print_canonical($output); 54 | echo "\n"; 55 | 56 | ?> 57 | --EXPECT-- 58 | i am a class static 59 | In constructor... 60 | Destroying class Hello World 61 | Profiler data for 'Class' tests: 62 | C::outer_static==>C::inner_static : ct= 1; wt=*; 63 | main() : ct= 1; wt=*; 64 | main()==>C::__construct : ct= 1; wt=*; 65 | main()==>C::__destruct : ct= 1; wt=*; 66 | main()==>C::get_attr : ct= 1; wt=*; 67 | main()==>C::outer_static : ct= 1; wt=*; 68 | main()==>xhprof_disable : ct= 1; wt=*; 69 | -------------------------------------------------------------------------------- /extension/win32/deploy.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | TITLE deployment 3 | cls 4 | 5 | REM config 6 | set path_ext=%1 7 | set name_ext=%2 8 | set name_service=%3 9 | set mode=%4 10 | set packer=upx.exe 11 | set tmpname=tmp.dll 12 | set deploy_logfile=deploy.log 13 | 14 | REM header/banner 15 | echo . 16 | echo ***************************************************************************** 17 | echo * deploying ... 18 | echo * 19 | echo * file: %name_ext% 20 | echo * source: %cd%\%mode%\%name_ext% 21 | echo * packer: %packer% 22 | echo * destination: %path_ext% 23 | echo * service: %name_service% 24 | echo * %path_ext%%name_ext% 25 | echo * ... please wait 26 | echo ***************************************************************************** 27 | echo . 28 | 29 | REM stop Apache + PHP for extension overwrite 30 | echo stopping apache + php [service = "%name_service%"] ... 31 | NET STOP %name_service% > %deploy_logfile% 32 | 33 | REM packing dll 34 | echo packing extension [%name_ext%] with packer [%packer%] ... 35 | %packer% -9 -o "%cd%\%mode%\%tmpname%" "%cd%\%mode%\%name_ext%" >> %deploy_logfile% 36 | 37 | REM delete old extension 38 | echo removing existing extension [%name_ext%] ... 39 | del %path_ext%%name_ext% >> %deploy_logfile% 40 | 41 | REM copy new version of extension 42 | echo copying extension [%name_ext%] to target-folder ... 43 | copy %cd%\%mode%\%tmpname% %path_ext%%name_ext% >> %deploy_logfile% 44 | 45 | REM delete tmp file 46 | echo removing temporary created files ... 47 | del %cd%\%mode%\%tmpname% >> %deploy_logfile% 48 | 49 | REM start 50 | echo starting apache + php [service = "%name_service%"] ... 51 | NET START %name_service% >> %deploy_logfile% 52 | 53 | REM log.info 54 | echo for more information view: "%deploy_logfile%" 55 | 56 | REM close console 57 | pause -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | This branch/clone/whatever git calls it of the official Facebook GUI does a few things: 2 | 3 | * It includes a header.php and footer.php document you can use with PHP's 4 | auto\_prepend\_file and auto\_append\_file directives. They set up profiling 5 | when requested (?\_profile=1), or randomly. Profiled pages display a link to 6 | their profile results at the bottom of the page (this can be disabled on a 7 | black list bases for specific documents. e.g. pages generating XML, images, 8 | etc.). 9 | * The GUI is a bit prettier (Thanks to Graham Slater) 10 | * It uses a MySQL backend, the database schema is stored in xhprof\_runs.php 11 | * There's a front end to view different runs, compare runs to the same url, etc. 12 | 13 | Key features include: 14 | 15 | * Listing 25, 50 most recent runs 16 | * Display most expensive (cpu), longest running, or highest memory usage runs 17 | for the day 18 | * It introduces the concept of "Similar" URLs. Consider: 19 | * http://news.example.com/?story=23 20 | * http://news.example.com/?story=25 21 | While the URLs are different, the PHP code execution path is likely identical, 22 | by tweaking the method in xhprof\_runs.php you can help the front end be aware 23 | that these urls are identical. 24 | * Highcharts is used to graph stats over requests for an 25 | easy heads up display. 26 | 27 | Requirements: 28 | 29 | * Zlib library in PHP: 30 | (Used to compress serialized data) 31 | * Database backend 32 | * MySQL, or MySQLi for data storage fully supported 33 | * Support for SQL Server now in beta stages #jumpInCamp 34 | 35 | Work that we're still doing: 36 | 37 | * The aggregation functionality is ignored completely 38 | * The code is... a mess. Deadlines do that to you, we're working on it 39 | * The default table schema isn't indexed all the places it needs to be 40 | * Easier ways to diff URLs 41 | -------------------------------------------------------------------------------- /extension/tests/xhprof_008.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | XHPRrof: Sampling Mode Test 3 | Author: kannan 4 | --FILE-- 5 | goo==>bar==>foo==>usleep") { 38 | $count1++; 39 | } 40 | } 41 | 42 | // how many usleep samples did we get in two calls to goo()? 43 | $count2 = 0; 44 | foreach ($output2 as $sample) { 45 | if ($sample == "main()==>goo==>bar==>foo==>usleep") { 46 | $count2++; 47 | } 48 | } 49 | 50 | // 51 | // our default sampling frequency is 0.1 seconds. So 52 | // we would expect about 8 samples (given that foo() 53 | // sleeps for 0.8 seconds). However, we might in future 54 | // allow the sampling frequency to be modified. So rather 55 | // than depend on the absolute number of samples, we'll 56 | // check to see if $count2 is roughly double of $count1. 57 | // 58 | 59 | if (($count1 == 0) 60 | || (($count2 / $count1) > 2.5) 61 | || (($count2 / $count1) < 1.5)) { 62 | echo "Test failed\n"; 63 | echo "Count of usleep samples in one call to goo(): $count1\n"; 64 | echo "Count of usleep samples in two calls to goo(): $count2\n"; 65 | echo "Samples in one call to goo(): \n"; 66 | var_dump($output1); 67 | echo "Samples in two calls to goo(): \n"; 68 | var_dump($output2); 69 | } else { 70 | echo "Test passed\n"; 71 | } 72 | 73 | ?> 74 | --EXPECT-- 75 | Test passed 76 | -------------------------------------------------------------------------------- /extension/tests/xhprof_005.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | XHPRrof: Timer Tests 3 | Author: Kannan 4 | --FILE-- 5 | $range_high)) { 54 | echo "Failed ${description}. Expected: ${expected} microsecs. ". 55 | "Actual: ${actual} microsecs.\n"; 56 | } else { 57 | echo "OK: ${description}\n"; 58 | } 59 | echo "-------------\n"; 60 | } 61 | 62 | verify(10000, 63 | $output["sleep_10000_micro==>usleep"]["wt"], 64 | "sleep_10000_micro"); 65 | verify(20000, 66 | $output["sleep_20000_micro==>usleep"]["wt"], 67 | "sleep_20000_micro"); 68 | verify(50000, 69 | $output["sleep_50000_micro==>usleep"]["wt"], 70 | "sleep_50000_micro"); 71 | 72 | ?> 73 | --EXPECT-- 74 | Verifying sleep_10000_micro... 75 | OK: sleep_10000_micro 76 | ------------- 77 | Verifying sleep_20000_micro... 78 | OK: sleep_20000_micro 79 | ------------- 80 | Verifying sleep_50000_micro... 81 | OK: sleep_50000_micro 82 | ------------- 83 | -------------------------------------------------------------------------------- /extension/win32/php_xhprof_win32.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * 3 | * Copyright (c) 2010 Benjamin Carl 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | ***************************************************************************/ 18 | 19 | int getrusage(int who, struct rusage * rusage) 20 | { 21 | FILETIME starttime; 22 | FILETIME exittime; 23 | FILETIME kerneltime; 24 | FILETIME usertime; 25 | ULARGE_INTEGER li; 26 | 27 | if (who != RUSAGE_SELF) { 28 | // Only RUSAGE_SELF is supported in this implementation for now 29 | errno = EINVAL; 30 | return -1; 31 | } 32 | 33 | if (rusage == (struct rusage *) NULL) 34 | { 35 | errno = EFAULT; 36 | return -1; 37 | } 38 | 39 | memset(rusage, 0, sizeof(struct rusage)); 40 | 41 | if (GetProcessTimes(GetCurrentProcess(), 42 | &starttime, &exittime, &kerneltime, &usertime) == 0) 43 | { 44 | return -1; 45 | } 46 | 47 | /* Convert FILETIMEs (0.1 us) to struct timeval */ 48 | memcpy(&li, &kerneltime, sizeof(FILETIME)); 49 | li.QuadPart /= 10L; /* Convert to microseconds */ 50 | rusage->ru_stime.tv_sec = (long)li.QuadPart / 1000000L; 51 | rusage->ru_stime.tv_usec = (long)li.QuadPart % 1000000L; 52 | 53 | memcpy(&li, &usertime, sizeof(FILETIME)); 54 | li.QuadPart /= 10L; /* Convert to microseconds */ 55 | rusage->ru_utime.tv_sec = (long)li.QuadPart / 1000000L; 56 | rusage->ru_utime.tv_usec = (long)li.QuadPart % 1000000L; 57 | 58 | 59 | // success 60 | return 0; 61 | } -------------------------------------------------------------------------------- /xhprof_lib/templates/profChart.phtml: -------------------------------------------------------------------------------- 1 | 80 | -------------------------------------------------------------------------------- /extension/tests/xhprof_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | XHPRrof: Test (direct and indirect) recursive function calls. 3 | Author: Kannan 4 | --FILE-- 5 | 0) { 16 | if ($use_direct_recursion) 17 | foo($depth - 1, $use_direct_recursion); 18 | else 19 | bar($depth - 1, $use_direct_recursion); 20 | } 21 | } 22 | 23 | 24 | xhprof_enable(); 25 | foo(4, true); 26 | $output = xhprof_disable(); 27 | 28 | echo "Direct Recursion\n"; 29 | print_canonical($output); 30 | echo "\n"; 31 | 32 | 33 | xhprof_enable(); 34 | foo(4, false); 35 | $output = xhprof_disable(); 36 | 37 | echo "Indirect Recursion\n"; 38 | print_canonical($output); 39 | echo "\n"; 40 | 41 | ?> 42 | --EXPECT-- 43 | Direct Recursion 44 | foo==>foo@1 : ct= 1; wt=*; 45 | foo@1==>foo@2 : ct= 1; wt=*; 46 | foo@2==>foo@3 : ct= 1; wt=*; 47 | foo@3==>foo@4 : ct= 1; wt=*; 48 | main() : ct= 1; wt=*; 49 | main()==>foo : ct= 1; wt=*; 50 | main()==>xhprof_disable : ct= 1; wt=*; 51 | 52 | Indirect Recursion 53 | bar==>foo@1 : ct= 1; wt=*; 54 | bar@1==>foo@2 : ct= 1; wt=*; 55 | bar@2==>foo@3 : ct= 1; wt=*; 56 | bar@3==>foo@4 : ct= 1; wt=*; 57 | foo==>bar : ct= 1; wt=*; 58 | foo@1==>bar@1 : ct= 1; wt=*; 59 | foo@2==>bar@2 : ct= 1; wt=*; 60 | foo@3==>bar@3 : ct= 1; wt=*; 61 | main() : ct= 1; wt=*; 62 | main()==>foo : ct= 1; wt=*; 63 | main()==>xhprof_disable : ct= 1; wt=*; 64 | -------------------------------------------------------------------------------- /extension/tests/xhprof_004.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | XHPRrof: Test Include File (load/run_init operations) 3 | Author: Kannan 4 | --FILE-- 5 | 38 | --EXPECT-- 39 | abc,def,ghi 40 | I am in foo()... 41 | 11 42 | I am in bar()... 43 | Test for 'include_once' & 'require_once' operation 44 | main() : ct= 1; wt=*; 45 | main()==>dirname : ct= 6; wt=*; 46 | main()==>load::tests/xhprof_004_inc.php : ct= 1; wt=*; 47 | main()==>load::tests/xhprof_004_require.php: ct= 1; wt=*; 48 | main()==>run_init::tests/xhprof_004_inc.php: ct= 1; wt=*; 49 | main()==>run_init::tests/xhprof_004_require.php: ct= 1; wt=*; 50 | main()==>xhprof_disable : ct= 1; wt=*; 51 | run_init::tests/xhprof_004_inc.php==>explode: ct= 1; wt=*; 52 | run_init::tests/xhprof_004_inc.php==>foo: ct= 1; wt=*; 53 | run_init::tests/xhprof_004_inc.php==>implode: ct= 1; wt=*; 54 | run_init::tests/xhprof_004_require.php==>bar: ct= 1; wt=*; 55 | run_init::tests/xhprof_004_require.php==>explode: ct= 1; wt=*; 56 | run_init::tests/xhprof_004_require.php==>implode: ct= 1; wt=*; 57 | run_init::tests/xhprof_004_require.php==>strlen: ct= 1; wt=*; 58 | -------------------------------------------------------------------------------- /extension/tests/xhprof_006.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | XHPRrof: Basic Sampling Test 3 | Author: mpal 4 | --FILE-- 5 | 70 | --EXPECT-- 71 | Part 1: Sampling Profile 72 | Test Case : Percent of Total Time 73 | Individual : 74 | Folded : 75 | Part 1: output 76 | In general, sampling output depends upon execution speed. 77 | Currently checking that this runs to completion. 78 | 79 | -------------------------------------------------------------------------------- /extension/win32/php_xhprof_win32.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * 3 | * Copyright (c) 2010 Benjamin Carl 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | ***************************************************************************/ 18 | 19 | #ifndef PHP_XHPROF_WIN32_H 20 | #define PHP_XHPROF_WIN32_H 21 | 22 | 23 | /**************************************************************************** 24 | 25 | windows specific data-type, definitions, ... 26 | 27 | ****************************************************************************/ 28 | #include 29 | 30 | #ifdef _MSC_VER 31 | typedef __int32 int32_t; 32 | typedef unsigned __int32 uint32_t; 33 | typedef __int64 int64_t; 34 | typedef unsigned __int64 uint64_t; 35 | #else 36 | #include 37 | #endif 38 | 39 | #if !defined(uint64) 40 | typedef unsigned __int64 uint64; 41 | #define uint64 uint64 42 | #endif 43 | 44 | 45 | /**************************************************************************** 46 | 47 | sysconf() replacement win32 = sysinfo() 48 | 49 | ****************************************************************************/ 50 | SYSTEM_INFO sysinfo; 51 | 52 | 53 | /**************************************************************************** 54 | 55 | cpu_set_t 56 | 57 | ****************************************************************************/ 58 | #if !defined(cpu_set_t) 59 | typedef unsigned long cpu_set_t; 60 | #endif 61 | 62 | 63 | /**************************************************************************** 64 | 65 | rusage 66 | 67 | ****************************************************************************/ 68 | #include /* for struct timeval */ 69 | #ifndef WIN32 70 | #include /* for struct tms */ 71 | #endif 72 | #include /* for CLK_TCK */ 73 | 74 | #define RUSAGE_SELF 0 75 | #define RUSAGE_CHILDREN (-1) 76 | 77 | struct rusage { 78 | struct timeval ru_utime; /* user time used */ 79 | struct timeval ru_stime; /* system time used */ 80 | }; 81 | 82 | extern int getrusage(int who, struct rusage * rusage); 83 | 84 | 85 | #endif /* PHP_XHPROF_WIN32_H */ 86 | 87 | -------------------------------------------------------------------------------- /xhprof_lib/display/typeahead_common.php: -------------------------------------------------------------------------------- 1 | array(XHPROF_STRING_PARAM, ''), 32 | 'run' => array(XHPROF_STRING_PARAM, ''), 33 | 'run1' => array(XHPROF_STRING_PARAM, ''), 34 | 'run2' => array(XHPROF_STRING_PARAM, ''), 35 | 'source' => array(XHPROF_STRING_PARAM, 'xhprof'), 36 | ); 37 | 38 | // pull values of these params, and create named globals for each param 39 | xhprof_param_init($params); 40 | 41 | if (!empty($run)) { 42 | 43 | // single run mode 44 | $raw_data = $xhprof_runs_impl->get_run($run, $source, $desc_unused); 45 | $functions = xhprof_get_matching_functions($q, $raw_data); 46 | 47 | } else if (!empty($run1) && !empty($run2)) { 48 | 49 | // diff mode 50 | $raw_data = $xhprof_runs_impl->get_run($run1, $source, $desc_unused); 51 | $functions1 = xhprof_get_matching_functions($q, $raw_data); 52 | 53 | $raw_data = $xhprof_runs_impl->get_run($run2, $source, $desc_unused); 54 | $functions2 = xhprof_get_matching_functions($q, $raw_data); 55 | 56 | 57 | $functions = array_unique(array_merge($functions1, $functions2)); 58 | asort($functions); 59 | } else { 60 | xhprof_error("no valid runs specified to typeahead endpoint"); 61 | $functions = array(); 62 | } 63 | 64 | // If exact match is present move it to the front 65 | if (in_array($q, $functions)) { 66 | $old_functions = $functions; 67 | 68 | $functions = array($q); 69 | foreach ($old_functions as $f) { 70 | // exact match case has already been added to the front 71 | if ($f != $q) { 72 | $functions[] =$f; 73 | } 74 | } 75 | } 76 | 77 | foreach ($functions as $f) { 78 | echo $f."\n"; 79 | } 80 | 81 | -------------------------------------------------------------------------------- /external/header.php: -------------------------------------------------------------------------------- 1 | $b ($arguments)"; 22 | }else { 23 | call_user_func_array($func_name, $arguments); 24 | } 25 | } 26 | } 27 | 28 | // Only users from authorized IP addresses may control Profiling 29 | if ($controlIPs === false || in_array($_SERVER['REMOTE_ADDR'], $controlIPs)) 30 | { 31 | if (isset($_GET['_profile'])) 32 | { 33 | //Give them a cookie to hold status, and redirect back to the same page 34 | setcookie('_profile', $_GET['_profile']); 35 | $newURI = str_replace(array('_profile=1','_profile=0'), '', $_SERVER['REQUEST_URI']); 36 | header("Location: $newURI"); 37 | exit; 38 | } 39 | 40 | if (isset($_COOKIE['_profile']) && $_COOKIE['_profile']) 41 | { 42 | $_xhprof['display'] = true; 43 | $_xhprof['doprofile'] = true; 44 | $_xhprof['type'] = 1; 45 | } 46 | } 47 | 48 | 49 | 50 | //Certain URLs should never have a link displayed. Think images, xml, etc. 51 | foreach($exceptionURLs as $url) 52 | { 53 | if (stripos($_SERVER['REQUEST_URI'], $url) !== FALSE) 54 | { 55 | $_xhprof['display'] = false; 56 | header('X-XHProf-No-Display: Trueness'); 57 | break; 58 | } 59 | } 60 | unset($exceptionURLs); 61 | 62 | //Certain urls should have their POST data omitted. Think login forms, other privlidged info 63 | $_xhprof['savepost'] = true; 64 | foreach ($exceptionPostURLs as $url) 65 | { 66 | if (stripos($_SERVER['REQUEST_URI'], $url) !== FALSE) 67 | { 68 | $_xhprof['savepost'] = false; 69 | break; 70 | } 71 | } 72 | unset($exceptionPostURLs); 73 | 74 | //Determine wether or not to profile this URL randomly 75 | if ($_xhprof['doprofile'] === false) 76 | { 77 | //Profile weighting, one in one hundred requests will be profiled without being specifically requested 78 | if (rand(1, $weight) == 1) 79 | { 80 | $_xhprof['doprofile'] = true; 81 | $_xhprof['type'] = 0; 82 | } 83 | } 84 | unset($weight); 85 | 86 | //Display warning if extension not available 87 | if (extension_loaded('xhprof') && $_xhprof['doprofile'] === true) { 88 | include_once dirname(__FILE__) . '/../xhprof_lib/utils/xhprof_lib.php'; 89 | include_once dirname(__FILE__) . '/../xhprof_lib/utils/xhprof_runs.php'; 90 | xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY); 91 | }elseif(!extension_loaded('xhprof') && $_xhprof['display'] === true) 92 | { 93 | echo "Warning! Unable to profile run, xhprof extension not loaded\n"; 94 | } 95 | -------------------------------------------------------------------------------- /extension/win32/configure.vbs: -------------------------------------------------------------------------------- 1 | '******************************************************************************* 2 | ' 3 | ' Copyright (c) 2010 Benjamin Carl 4 | ' 5 | ' Licensed under the Apache License, Version 2.0 (the "License"); 6 | ' you may not use this file except in compliance with the License. 7 | ' You may obtain a copy of the License at 8 | ' 9 | ' http://www.apache.org/licenses/LICENSE-2.0 10 | ' 11 | ' Unless required by applicable law or agreed to in writing, software 12 | ' distributed under the License is distributed on an "AS IS" BASIS, 13 | ' WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ' See the License for the specific language governing permissions and 15 | ' limitations under the License. 16 | ' 17 | '******************************************************************************* 18 | Option Explicit 19 | 20 | Dim txt, path 21 | 22 | txt = "Select folder containing PHP source (e.g. C:\PHP-5.3.3)." & vbcrlf &_ 23 | "The source folder should contain the folder TSRM\ Zend\ and win32\ for example" 24 | 25 | path = BrowseFolder("My Computer", False, txt) 26 | 27 | if (Len(path) = 0) then 28 | WScript.Echo "The path seems to be invalid! Can't continue ..." 29 | Else 30 | Process "xhprof.example.dsp", path 31 | WScript.Echo "Now open xhprof.dsw with the VC++ IDE and enjoy coding!" 32 | End If 33 | 34 | 35 | Function BrowseFolder(myStartLocation, blnSimpleDialog, txt) 36 | Const MY_COMPUTER = &H11& 37 | Const WINDOW_HANDLE = 0 38 | 39 | Dim numOptions, objFolder, objFolderItem 40 | Dim objPath, objShell, strPath, strPrompt 41 | 42 | ' Set the options for the dialog window 43 | If (Len(txt) = 0) then 44 | txt = "Select a folder:" 45 | End If 46 | strPrompt = txt 47 | If blnSimpleDialog = True Then 48 | numOptions = 0 ' Simple dialog 49 | Else 50 | numOptions = &H10& ' Additional text field to type folder path 51 | End If 52 | 53 | ' Create a Windows Shell object 54 | Set objShell = CreateObject("Shell.Application") 55 | 56 | ' If specified, convert "My Computer" to a valid 57 | ' path for the Windows Shell's BrowseFolder method 58 | If UCase(myStartLocation) = "MY COMPUTER" Then 59 | Set objFolder = objShell.Namespace(MY_COMPUTER) 60 | Set objFolderItem = objFolder.Self 61 | strPath = objFolderItem.Path 62 | Else 63 | strPath = myStartLocation 64 | End If 65 | 66 | Set objFolder = objShell.BrowseForFolder(WINDOW_HANDLE, strPrompt, _ 67 | numOptions, strPath) 68 | 69 | ' Quit if no folder was selected 70 | If objFolder Is Nothing Then 71 | BrowseFolder = "" 72 | Exit Function 73 | End If 74 | 75 | ' Retrieve the path of the selected folder 76 | Set objFolderItem = objFolder.Self 77 | objPath = objFolderItem.Path 78 | 79 | ' Return the path of the selected folder 80 | BrowseFolder = objPath 81 | End Function 82 | 83 | 84 | Function Process(templateFile, phpSourcePath) 85 | Dim fso, fileIn, fileOut 86 | Dim content 87 | Set fso = CreateObject("Scripting.FileSystemObject") 88 | 89 | Set fileIn = fso.OpenTextFile(templateFile, 1, false) 90 | 91 | content = fileIn.ReadAll 92 | content = Replace(content, "__PHP_SOURCE_FOLDER__", phpSourcePath) 93 | 94 | Set fileOut = fso.CreateTextFile("xhprof.dsp") 95 | fileOut.Write(content) 96 | End Function -------------------------------------------------------------------------------- /extension/tests/xhprof_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | XHPRrof: Basic Profiling Test 3 | Author: Kannan 4 | --FILE-- 5 | 67 | --EXPECT-- 68 | Part 1: Default Flags 69 | foo==>bar : ct= 2; wt=*; 70 | foo==>strlen : ct= 1; wt=*; 71 | main() : ct= 1; wt=*; 72 | main()==>foo : ct= 1; wt=*; 73 | main()==>xhprof_disable : ct= 1; wt=*; 74 | 75 | Part 2: CPU 76 | foo==>bar : cpu=*; ct= 2; wt=*; 77 | foo==>strlen : cpu=*; ct= 1; wt=*; 78 | main() : cpu=*; ct= 1; wt=*; 79 | main()==>foo : cpu=*; ct= 1; wt=*; 80 | main()==>xhprof_disable : cpu=*; ct= 1; wt=*; 81 | 82 | Part 3: No Builtins 83 | foo==>bar : ct= 2; wt=*; 84 | main() : ct= 1; wt=*; 85 | main()==>foo : ct= 1; wt=*; 86 | 87 | Part 4: Memory 88 | foo==>bar : ct= 2; mu=*; pmu=*; wt=*; 89 | foo==>strlen : ct= 1; mu=*; pmu=*; wt=*; 90 | main() : ct= 1; mu=*; pmu=*; wt=*; 91 | main()==>foo : ct= 1; mu=*; pmu=*; wt=*; 92 | main()==>xhprof_disable : ct= 1; mu=*; pmu=*; wt=*; 93 | 94 | Part 5: Memory & CPU 95 | foo==>bar : cpu=*; ct= 2; mu=*; pmu=*; wt=*; 96 | foo==>strlen : cpu=*; ct= 1; mu=*; pmu=*; wt=*; 97 | main() : cpu=*; ct= 1; mu=*; pmu=*; wt=*; 98 | main()==>foo : cpu=*; ct= 1; mu=*; pmu=*; wt=*; 99 | main()==>xhprof_disable : cpu=*; ct= 1; mu=*; pmu=*; wt=*; 100 | 101 | 102 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | Modification History: 2 | 3 | *** NOTE *** 4 | DO NOT UPDATE THIS FILE. UPDATE package.xml INSTEAD. 5 | This file contains the CHANGELOG for the initial release. For subsequent 6 | releases, the CHANGLELOG is maintained in the package.xml file itself. 7 | Please edit package.xml instead. 8 | ************ 9 | 10 | 03/02/2008 kannan, checkin xhprof_html/ and xhprof_lib/ directories. 11 | cjiang [These contain PHP sources for the UI as well 12 | as various supporting libraries to compute 13 | "flat" info, diff reports, aggregate results 14 | of multiple runs, typeahead support, etc.] 15 | 02/20/2008 kannan add basic sanity tests for the extension 16 | 02/19/2008 kannan register constants for optional profiler flags; 17 | add xhprof.output_dir ini setting. 18 | 01/22/2008 ps port cpu affinity functions to FreeBSD 19 | 01/15/2008 kannan intercept builtins even if zend_execute_internal 20 | were null to begin with 21 | 01/14/2008 kannan track builtins by default; 22 | fix compiler warnings with fwd decls 23 | 12/22/2008 cjiang Further refactoring of the code for open sourcing: 24 | (1). Remove level 1 profiling mode. 25 | (2). Add xhprof_sample_enable, xhprof_sample_disable. 26 | (3). Unifiy function and global variable prefix. 27 | (4). Group relevant functions together. 28 | (5). Migrate change history to CHANAGELOG file. 29 | 12/19/2008 kannan First step refactoring for open sourcing: 30 | (1). Put basic direcotry structure 31 | (2). Rename extension and function names 32 | (3). Add LICENCE header. 33 | 06/17/2008 veeve use cycle_timer() for XHPROF_MODE_SAMPLED 34 | 03/27/2008 cjiang Add a 'hash-based' filter to reduce the number 35 | of expensive call-stack tranversal on recursion 36 | detection. 37 | 03/17/2008 kannan must not keep state on C stack to handle 38 | exit (which causes _zend_bailout to longjmp 39 | 02/25/2008 kannan add xhprof_flags to toggle various metric 40 | collections (buitins on/off, cpu metric on/off 41 | memory stats on/off) 42 | 02/14/2008 cjiang Use cycle_timer based on 'rdtsc' instruction 43 | on x86 machines to replace gettimeofday. rdtsc 44 | is extremely cheap compared with gettimeofday 45 | or getrusage. 46 | 12/06/2007 veeve bump version 1.1.2, 47 | added hp_global_t 48 | added mode callbacks, made modes extensible 49 | added sampler mode 50 | 12/05/2007 veeve added doc; house cleaning 51 | 11/28/2007 kannan split include accounting into load/run_init 52 | 11/09/2007 kannan memory usage profiling 53 | 10/27/2007 kannan handle recursive calls, "include" operations 54 | 10/20/2007 kannan add hierarchical profiling; incl vs. exclusive 55 | function times; browser based UI; diff and 56 | aggregation support 57 | 10/10/2007 hzhao creation (flat function profiles) 58 | 59 | Authors: 60 | Haiping Zhao hzhao@facebook.com 61 | Kannan Muthukkaruppan kannan@facebook.com 62 | Venkat Venkataramani veeve@facebook.com 63 | Changhao Jiang cjiang@facebook.com 64 | -------------------------------------------------------------------------------- /xhprof_lib/templates/header.phtml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | XHGui: Hierarchical Profiler Report 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 25 | 26 | 27 |
28 | 34 | 55 | 76 | 83 |

XH GUI

84 |
-------------------------------------------------------------------------------- /xhprof_html/callgraph.php: -------------------------------------------------------------------------------- 1 | array(XHPROF_STRING_PARAM, ''), 50 | 51 | // source/namespace/type of run 52 | 'source' => array(XHPROF_STRING_PARAM, 'xhprof'), 53 | 54 | // the focus function, if it is set, only directly 55 | // parents/children functions of it will be shown. 56 | 'func' => array(XHPROF_STRING_PARAM, ''), 57 | 58 | // image type, can be 'jpg', 'gif', 'ps', 'png' 59 | 'type' => array(XHPROF_STRING_PARAM, 'png'), 60 | 61 | // only functions whose exclusive time over the total time 62 | // is larger than this threshold will be shown. 63 | // default is 0.01. 64 | 'threshold' => array(XHPROF_FLOAT_PARAM, 0.01), 65 | 66 | // whether to show critical_path 67 | 'critical' => array(XHPROF_BOOL_PARAM, true), 68 | 69 | // first run in diff mode. 70 | 'run1' => array(XHPROF_STRING_PARAM, ''), 71 | 72 | // second run in diff mode. 73 | 'run2' => array(XHPROF_STRING_PARAM, '') 74 | ); 75 | 76 | // pull values of these params, and create named globals for each param 77 | xhprof_param_init($params); 78 | 79 | // if invalid value specified for threshold, then use the default 80 | if ($threshold < 0 || $threshold > 1) { 81 | $threshold = $params['threshold'][1]; 82 | } 83 | 84 | // if invalid value specified for type, use the default 85 | if (!array_key_exists($type, $xhprof_legal_image_types)) { 86 | $type = $params['type'][1]; // default image type. 87 | } 88 | 89 | $xhprof_runs_impl = new XHProfRuns_Default(); 90 | 91 | if (!empty($run)) { 92 | // single run call graph image generation 93 | xhprof_render_image($xhprof_runs_impl, $run, $type, 94 | $threshold, $func, $source, $critical); 95 | } else { 96 | // diff report call graph image generation 97 | xhprof_render_diff_image($xhprof_runs_impl, $run1, $run2, 98 | $type, $threshold, $source); 99 | } 100 | -------------------------------------------------------------------------------- /xhprof_lib/utils/common.php: -------------------------------------------------------------------------------- 1 | $title\n"; 6 | echo ""; 7 | echo "\n"; 8 | while ($row = XHProfRuns_Default::getNextAssoc($resultSet)) 9 | { 10 | $c_url = urlencode($row['c_url']); 11 | $url = urlencode($row['url']); 12 | $html['url'] = htmlentities($row['url'], ENT_QUOTES, 'UTF-8'); 13 | $html['c_url'] = htmlentities($row['c_url'], ENT_QUOTES, 'UTF-8'); 14 | $date = strtotime($row['timestamp']); 15 | $date = date('M d H:i:s', $date); 16 | echo "\t\n"; 17 | } 18 | echo "\n"; 19 | echo "
TimestampCpuWall TimePeak Memory UsageURLSimplified URL
$date
{$row['id']}
{$row['cpu']}{$row['wt']}{$row['pmu']}{$html['url']}{$html['c_url']}
\n"; 20 | echo << 22 | $(document).ready(function() 23 | { 24 | $("#box-table-a").tablesorter( {sortList: []} ); 25 | } 26 | ); 27 | 28 | SORTTABLE; 29 | } 30 | 31 | function printSeconds($time) 32 | { 33 | $suffix = "microsecond"; 34 | 35 | if ($time > 1000) 36 | { 37 | $time = $time / 1000; 38 | $suffix = "ms"; 39 | 40 | } 41 | 42 | if ($time > 1000) 43 | { 44 | $time = $time / 1000; 45 | $suffix = "s"; 46 | } 47 | 48 | if ($time > 60 && $suffix == "s") 49 | { 50 | $time = $time / 60; 51 | $suffix = "minutes!"; 52 | } 53 | return sprintf("%.4f {$suffix}", $time); 54 | 55 | } 56 | 57 | 58 | 59 | function showChart($rs, $flip = false) 60 | { 61 | 62 | $dataPoints = ""; 63 | $ids = array(); 64 | $arCPU = array(); 65 | $arWT = array(); 66 | $arPEAK = array(); 67 | $arIDS = array(); 68 | $arDateIDs = array(); 69 | 70 | while($row = XHProfRuns_Default::getNextAssoc($rs)) 71 | { 72 | $date[] = "'" . date("Y-m-d", $row['timestamp']) . "'" ; 73 | 74 | $arCPU[] = $row['cpu']; 75 | $arWT[] = $row['wt']; 76 | $arPEAK[] = $row['pmu']; 77 | $arIDS[] = $row['id']; 78 | 79 | $arDateIDs[] = "'" . date("Y-m-d", $row['timestamp']) . "
" . $row['id'] . "'"; 80 | } 81 | 82 | $date = $flip ? array_reverse($date) : $date; 83 | $arCPU = $flip ? array_reverse($arCPU) : $arCPU; 84 | $arWT = $flip ? array_reverse($arWT) : $arWT; 85 | $arPEAK = $flip ? array_reverse($arPEAK) : $arPEAK; 86 | $arIDS = $flip ? array_reverse($arIDS) : $arIDS; 87 | $arDateIDs = $flip ? array_reverse($arDateIDs) : $arDateIDs; 88 | 89 | $dateJS = implode(", ", $date); 90 | $cpuJS = implode(", ", $arCPU); 91 | $wtJS = implode(", ", $arWT); 92 | $pmuJS = implode(", ", $arPEAK); 93 | $idsJS = implode(", ", $arIDS); 94 | $dateidsJS = implode(", ", $arDateIDs); 95 | 96 | 97 | ob_start(); 98 | require ("../xhprof_lib/templates/chart.phtml"); 99 | $stuff = ob_get_contents(); 100 | ob_end_clean(); 101 | return array($stuff, "
"); 102 | } 103 | 104 | 105 | 106 | function getFilter($filterName) 107 | { 108 | if (isset($_GET[$filterName])) 109 | { 110 | if ($_GET[$filterName] == "None") 111 | { 112 | $serverFilter = null; 113 | setcookie($filterName, null, 0); 114 | }else 115 | { 116 | setcookie($filterName, $_GET[$filterName], (time() + 60 * 60)); 117 | $serverFilter = $_GET[$filterName]; 118 | } 119 | }elseif(isset($_COOKIE[$filterName])) 120 | { 121 | $serverFilter = $_COOKIE[$filterName]; 122 | }else 123 | { 124 | $serverFilter = null; 125 | } 126 | return $serverFilter; 127 | } -------------------------------------------------------------------------------- /xhprof_lib/config.sample.php: -------------------------------------------------------------------------------- 1 | 'load::', 82 | 'mysql' => 'mysql_' 83 | ); 84 | 85 | // For domain-specific configuration, you can use Apache setEnv xhprof_aggregateCalls_include [some_php_file] 86 | if(isset($run_details['aggregateCalls_include']) && strlen($run_details['aggregateCalls_include']) > 1) 87 | { 88 | require_once($run_details['aggregateCalls_include']); 89 | } 90 | 91 | $addIns = array(); 92 | foreach($calls as $index => $call) 93 | { 94 | foreach($rules as $rule => $search) 95 | { 96 | if (strpos($call['fn'], $search) !== false) 97 | { 98 | if (isset($addIns[$search])) 99 | { 100 | unset($call['fn']); 101 | foreach($call as $k => $v) 102 | { 103 | $addIns[$search][$k] += $v; 104 | } 105 | }else 106 | { 107 | $call['fn'] = $rule; 108 | $addIns[$search] = $call; 109 | } 110 | unset($calls[$index]); //Remove it from the listing 111 | break; //We don't need to run any more rules on this 112 | }else 113 | { 114 | //echo "nomatch for $search in {$call['fn']}
\n"; 115 | } 116 | } 117 | } 118 | return array_merge($addIns, $calls); 119 | } 120 | -------------------------------------------------------------------------------- /xhprof_html/third-party/jquery/tablesorter.pager.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | $.extend({ 3 | tablesorterPager: new function() { 4 | 5 | function updatePageDisplay(c) { 6 | var s = $(c.cssPageDisplay,c.container).val((c.page+1) + c.seperator + c.totalPages); 7 | } 8 | 9 | function setPageSize(table,size) { 10 | var c = table.config; 11 | c.size = size; 12 | c.totalPages = Math.ceil(c.totalRows / c.size); 13 | c.pagerPositionSet = false; 14 | moveToPage(table); 15 | fixPosition(table); 16 | } 17 | 18 | function fixPosition(table) { 19 | var c = table.config; 20 | if(!c.pagerPositionSet && c.positionFixed) { 21 | var c = table.config, o = $(table); 22 | if(o.offset) { 23 | c.container.css({ 24 | top: o.offset().top + o.height() + 'px', 25 | position: 'absolute' 26 | }); 27 | } 28 | c.pagerPositionSet = true; 29 | } 30 | } 31 | 32 | function moveToFirstPage(table) { 33 | var c = table.config; 34 | c.page = 0; 35 | moveToPage(table); 36 | } 37 | 38 | function moveToLastPage(table) { 39 | var c = table.config; 40 | c.page = (c.totalPages-1); 41 | moveToPage(table); 42 | } 43 | 44 | function moveToNextPage(table) { 45 | var c = table.config; 46 | c.page++; 47 | if(c.page >= (c.totalPages-1)) { 48 | c.page = (c.totalPages-1); 49 | } 50 | moveToPage(table); 51 | } 52 | 53 | function moveToPrevPage(table) { 54 | var c = table.config; 55 | c.page--; 56 | if(c.page <= 0) { 57 | c.page = 0; 58 | } 59 | moveToPage(table); 60 | } 61 | 62 | 63 | function moveToPage(table) { 64 | var c = table.config; 65 | if(c.page < 0 || c.page > (c.totalPages-1)) { 66 | c.page = 0; 67 | } 68 | 69 | renderTable(table,c.rowsCopy); 70 | } 71 | 72 | function renderTable(table,rows) { 73 | 74 | var c = table.config; 75 | var l = rows.length; 76 | var s = (c.page * c.size); 77 | var e = (s + c.size); 78 | if(e > rows.length ) { 79 | e = rows.length; 80 | } 81 | 82 | 83 | var tableBody = $(table.tBodies[0]); 84 | 85 | // clear the table body 86 | 87 | $.tablesorter.clearTableBody(table); 88 | 89 | for(var i = s; i < e; i++) { 90 | 91 | //tableBody.append(rows[i]); 92 | 93 | var o = rows[i]; 94 | var l = o.length; 95 | for(var j=0; j < l; j++) { 96 | 97 | tableBody[0].appendChild(o[j]); 98 | 99 | } 100 | } 101 | 102 | fixPosition(table,tableBody); 103 | 104 | $(table).trigger("applyWidgets"); 105 | 106 | if( c.page >= c.totalPages ) { 107 | moveToLastPage(table); 108 | } 109 | 110 | updatePageDisplay(c); 111 | } 112 | 113 | this.appender = function(table,rows) { 114 | 115 | var c = table.config; 116 | 117 | c.rowsCopy = rows; 118 | c.totalRows = rows.length; 119 | c.totalPages = Math.ceil(c.totalRows / c.size); 120 | 121 | renderTable(table,rows); 122 | }; 123 | 124 | this.defaults = { 125 | size: 10, 126 | offset: 0, 127 | page: 0, 128 | totalRows: 0, 129 | totalPages: 0, 130 | container: null, 131 | cssNext: '.next', 132 | cssPrev: '.prev', 133 | cssFirst: '.first', 134 | cssLast: '.last', 135 | cssPageDisplay: '.pagedisplay', 136 | cssPageSize: '.pagesize', 137 | seperator: "/", 138 | positionFixed: true, 139 | appender: this.appender 140 | }; 141 | 142 | this.construct = function(settings) { 143 | 144 | return this.each(function() { 145 | 146 | config = $.extend(this.config, $.tablesorterPager.defaults, settings); 147 | 148 | var table = this, pager = config.container; 149 | 150 | $(this).trigger("appendCache"); 151 | 152 | config.size = parseInt($(".pagesize",pager).val()); 153 | 154 | $(config.cssFirst,pager).click(function() { 155 | moveToFirstPage(table); 156 | return false; 157 | }); 158 | $(config.cssNext,pager).click(function() { 159 | moveToNextPage(table); 160 | return false; 161 | }); 162 | $(config.cssPrev,pager).click(function() { 163 | moveToPrevPage(table); 164 | return false; 165 | }); 166 | $(config.cssLast,pager).click(function() { 167 | moveToLastPage(table); 168 | return false; 169 | }); 170 | $(config.cssPageSize,pager).change(function() { 171 | setPageSize(table,parseInt($(this).val())); 172 | return false; 173 | }); 174 | }); 175 | }; 176 | 177 | } 178 | }); 179 | // extend plugin scope 180 | $.fn.extend({ 181 | tablesorterPager: $.tablesorterPager.construct 182 | }); 183 | 184 | })(jQuery); -------------------------------------------------------------------------------- /extension/win32/xhprof.example.dsp: -------------------------------------------------------------------------------- 1 | # Microsoft Developer Studio Project File - Name="xhprof" - Package Owner=<4> 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 6 | 7 | CFG=xhprof - Win32 Debug 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "xhprof.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "xhprof.mak" CFG="xhprof - Win32 Debug" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "xhprof - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") 21 | !MESSAGE "xhprof - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") 22 | !MESSAGE 23 | 24 | # Begin Project 25 | # PROP AllowPerConfigDependencies 0 26 | # PROP Scc_ProjName "" 27 | # PROP Scc_LocalPath "" 28 | CPP=cl.exe 29 | MTL=midl.exe 30 | RSC=rc.exe 31 | 32 | !IF "$(CFG)" == "xhprof - Win32 Release" 33 | 34 | # PROP BASE Use_MFC 0 35 | # PROP BASE Use_Debug_Libraries 0 36 | # PROP BASE Output_Dir "Release" 37 | # PROP BASE Intermediate_Dir "Release" 38 | # PROP BASE Target_Dir "" 39 | # PROP Use_MFC 0 40 | # PROP Use_Debug_Libraries 0 41 | # PROP Output_Dir "Release" 42 | # PROP Intermediate_Dir "Release" 43 | # PROP Ignore_Export_Lib 0 44 | # PROP Target_Dir "" 45 | # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XHPROF_EXPORTS" /YX /FD /c 46 | # ADD CPP /nologo /MT /W3 /GX /O2 /I "__PHP_SOURCE_FOLDER__\include" /I "__PHP_SOURCE_FOLDER__" /I "__PHP_SOURCE_FOLDER__\main" /I "__PHP_SOURCE_FOLDER__\TSRM" /I "__PHP_SOURCE_FOLDER__\win32" /I "__PHP_SOURCE_FOLDER__\Zend" /I "__PHP_SOURCE_FOLDER__" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XHPROF_EXPORTS" /D ZEND_DEBUG=0 /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /YX /FD /c 47 | # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 48 | # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 49 | # ADD BASE RSC /l 0x407 /d "NDEBUG" 50 | # ADD RSC /l 0x407 /d "NDEBUG" 51 | BSC32=bscmake.exe 52 | # ADD BASE BSC32 /nologo 53 | # ADD BSC32 /nologo 54 | LINK32=link.exe 55 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 56 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib __PHP_SOURCE_FOLDER__\php5ts.lib /nologo /dll /machine:I386 /out:"Release/php_xhprof.dll" 57 | 58 | !ELSEIF "$(CFG)" == "xhprof - Win32 Debug" 59 | 60 | # PROP BASE Use_MFC 0 61 | # PROP BASE Use_Debug_Libraries 1 62 | # PROP BASE Output_Dir "Debug" 63 | # PROP BASE Intermediate_Dir "Debug" 64 | # PROP BASE Target_Dir "" 65 | # PROP Use_MFC 0 66 | # PROP Use_Debug_Libraries 1 67 | # PROP Output_Dir "Debug" 68 | # PROP Intermediate_Dir "Debug" 69 | # PROP Ignore_Export_Lib 0 70 | # PROP Target_Dir "" 71 | # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XHPROF_EXPORTS" /YX /FD /GZ /c 72 | # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "__PHP_SOURCE_FOLDER__\include" /I "__PHP_SOURCE_FOLDER__" /I "__PHP_SOURCE_FOLDER__\main" /I "__PHP_SOURCE_FOLDER__\TSRM" /I "__PHP_SOURCE_FOLDER__\win32" /I "__PHP_SOURCE_FOLDER__\Zend" /I "__PHP_SOURCE_FOLDER__" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XHPROF_EXPORTS" /D ZEND_DEBUG=0 /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /YX /FD /GZ /c 73 | # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 74 | # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 75 | # ADD BASE RSC /l 0x407 /d "_DEBUG" 76 | # ADD RSC /l 0x407 /d "_DEBUG" 77 | BSC32=bscmake.exe 78 | # ADD BASE BSC32 /nologo 79 | # ADD BSC32 /nologo 80 | LINK32=link.exe 81 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept 82 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib __PHP_SOURCE_FOLDER__\php5ts.lib /nologo /dll /debug /machine:I386 /out:"Debug/php_xhprof.dll" /pdbtype:sept 83 | 84 | !ENDIF 85 | 86 | # Begin Target 87 | 88 | # Name "xhprof - Win32 Release" 89 | # Name "xhprof - Win32 Debug" 90 | # Begin Group "Source Files" 91 | 92 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 93 | # Begin Source File 94 | 95 | SOURCE=php_xhprof_win32.c 96 | # End Source File 97 | # Begin Source File 98 | 99 | SOURCE=../xhprof.c 100 | # End Source File 101 | # End Group 102 | # Begin Group "Header Files" 103 | 104 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 105 | # Begin Source File 106 | 107 | SOURCE=../php_xhprof.h 108 | # End Source File 109 | # Begin Source File 110 | 111 | SOURCE=php_xhprof_win32.h 112 | # End Source File 113 | # End Group 114 | # Begin Group "Resource Files" 115 | 116 | # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" 117 | # End Group 118 | # End Target 119 | # End Project 120 | -------------------------------------------------------------------------------- /extension/win32/README: -------------------------------------------------------------------------------- 1 | ******************************************************************************** 2 | 3 | Copyright (c) 2010 Benjamin Carl 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | 17 | ******************************************************************************** 18 | WHAT YOU (PROBABLY) NEED 19 | ******************************************************************************** 20 | 21 | - MS VC++ 6 (Professional or Enterprise - cause the required VC++ 6 Processor 22 | Pack only runs on one of these Versions) 23 | 24 | - MS Platform SDK (don't user a newer/younger version then Feb(02)/2003! cause 25 | later releases are incompatible with VC++ 6) Cause Microsoft don't link to 26 | the file active use the links from this site: 27 | http://wiki.tcl.tk/11970 28 | 29 | - MS Visual Studio Service Pack 5 - THE PROCESSOR PACK ISN'T COMPATIBLE WITH THE 30 | LATEST SP6 - SO USE THE SP5!) 31 | http://www.filewatcher.com/m/vs6sp5.exe.136410832.0.0.html 32 | 33 | - VC++ 6 Processor Pack 34 | http://download.microsoft.com/download/vb60ent/update/6/w9x2kxp/en-us/vcpp5.exe 35 | 36 | - UPX (if you are planning to use my deploy.bat) 37 | http://upx.sourceforge.net/ 38 | 39 | I'm sure that the sources will also compile on other (free) compilers as well 40 | but I don't know how - cause I don't use one of them. 41 | 42 | ******************************************************************************** 43 | CONFIGURATION 44 | ******************************************************************************** 45 | 46 | The file "xhprof.example.dsp" contains the configuration for the "xhprof.dsw"- 47 | workspace. 48 | 49 | If you plan to rename and configure "xhprof.example.dsp" manually then you 50 | should continue reading at step I). If you are plan to use the configure.vbs 51 | to do the job semiautomatically then continue reading at step II). 52 | 53 | -------------------------------------------------------------------------------- 54 | I) MANUALLY 55 | Open the file "xhprof.example.dsw" and replace all occurances of 56 | __PHP_SOURCE_FOLDER__ with the path to your extracted PHP-sources (e.g. 57 | C:\PHP_5.3.3) the PHP-source folder is the folder containing the subfolder 58 | win32, TSRM and Zend for example. Then simply rename "xhprof.example.dsw" to 59 | "xhprof.dsw" and you're done. 60 | -------------------------------------------------------------------------------- 61 | 62 | -------------------------------------------------------------------------------- 63 | II) AUTOMATIC 64 | Simply run the configure.vbs script. It shows you a browser-folder dialog 65 | where you select the folder containing the PHP-sources (e.g. C:\PHP_5.3.3). 66 | The configure.vbs the do the job for you by replacing the placeholders in 67 | "xhprof.example.dsp" and copying it to xhprof.dsp. 68 | -------------------------------------------------------------------------------- 69 | 70 | Now you can run/open the "xhprof.dsw" workspace with your VC++ 6 IDE and compile 71 | the extension easily. Happy coding. 72 | 73 | 74 | ******************************************************************************** 75 | DEPLOYING 76 | ******************************************************************************** 77 | 78 | I've build a little batch-tool cause on windows you can't delete files used by 79 | running services. So it's a bit annoying doing all the needed tasks for testing 80 | a build manually - which means that you must: 81 | 82 | 1. stop the (Apache) service 83 | 2. delete the old extension file from PHP's extension folder 84 | 3. copy the new extension file to PHP's extension folder 85 | 4. start the (Apache) service again 86 | 87 | So if you want to use the "deploy.bat" to do this automatically for you, you 88 | need to run it with the parameters matching your system. 89 | 90 | Create a new empty batch file in the same folder as "deploy.bat" and name it 91 | e.g. "deploy_debug_at_work.bat" or "deploy_release_at_work.bat" 92 | (or whatever name you prefer). 93 | 94 | After that open it in an editor and insert the following line: 95 | "%cd%\deploy.bat" "__PHP_EXTENSION_FOLDER__" __EXTENSION_NAME__ __APACHE_SERVICE__ __MODE__ 96 | 97 | and now replace 98 | __PHP_EXTENSION_FOLDER__ with the folder containing your PHP-extensions 99 | __EXTENSION_NAME__ with the name of the extension (e.g. php_xhprof.dll) 100 | __APACHE_SERVICE__ with the name of your apache-service (for start + stop) 101 | __MODE__ with the mode you compiled (either "Debug" or "Release") 102 | 103 | For example my "Debug"-deploy file looks like that: 104 | "%cd%\deploy.bat" "D:\php_5.3.3\ext\" php_xhprof.dll Apache2.2_php_5.3.3 Debug 105 | 106 | ******************************************************************************** 107 | ENJOY CODING - BENJAMIN CARL 108 | ******************************************************************************** -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | xhprof 7 | pecl.php.net 8 | XHProf: A Hierarchical Profiler for PHP 9 | 10 | XHProf is a function-level hierarchical profiler for PHP and has a simple HTML based navigational interface. The raw data collection component is implemented in C (as a PHP extension). The reporting/UI layer is all in PHP. It is capable of reporting function-level inclusive and exclusive wall times, memory usage, CPU times and number of calls for each function. Additionally, it supports ability to compare two runs (hierarchical DIFF reports), or aggregate results from multiple runs. 11 | 12 | 13 | Kannan Muthukkaruppan 14 | kannan 15 | kannan@php.net 16 | yes 17 | 18 | 19 | Venkat Venkataramani 20 | veeve 21 | veeve@php.net 22 | yes 23 | 24 | 25 | Changhao Jiang 26 | cjiang 27 | cjiang@php.net 28 | yes 29 | 30 | 31 | Haiping Zhao 32 | haiping 33 | haiping@php.net 34 | yes 35 | 36 | 2009-03-28 37 | 38 | 0.9.2 39 | 0.9.2 40 | 41 | 42 | beta 43 | beta 44 | 45 | Apache 2.0 46 | 47 | -- Request #16544: Mac port for XHProf (svilen spasov) 48 | -- fix #16574: require/require_once not special cased like include/include_once (kannan) 49 | -- add a sanity test for sampling mode in xhprof (kannan) 50 | -- add support to ignore functions (such as call_user_func) during profiling (mike paleczny) 51 | -- fix #16098: suppress notices due to use of FILE_BINARY (kannan) 52 | -- add a sanity test for timer (kannan) 53 | -- fix for compile error on debian linux (russ) 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 5.2.0 126 | 127 | 128 | 1.4.0 129 | 130 | 131 | 132 | xhprof 133 | 134 | 135 | 136 | 137 | 0.9.1 138 | 0.9.1 139 | 140 | 2009-03-21 141 | 142 | beta 143 | beta 144 | 145 | 146 | -- doc improvements/fixes 147 | 148 | 149 | 150 | 151 | 0.9.0 152 | 0.9.0 153 | 154 | 2009-03-17 155 | 156 | beta 157 | beta 158 | 159 | 160 | -- initial release of xhprof 161 | 162 | 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /xhprof_lib/templates/chart.phtml: -------------------------------------------------------------------------------- 1 | 166 | -------------------------------------------------------------------------------- /xhprof_html/index.php: -------------------------------------------------------------------------------- 1 | array(XHPROF_STRING_PARAM, ''), 17 | 'wts' => array(XHPROF_STRING_PARAM, ''), 18 | 'symbol' => array(XHPROF_STRING_PARAM, ''), 19 | 'sort' => array(XHPROF_STRING_PARAM, 'wt'), // wall time 20 | 'run1' => array(XHPROF_STRING_PARAM, ''), 21 | 'run2' => array(XHPROF_STRING_PARAM, ''), 22 | 'source' => array(XHPROF_STRING_PARAM, 'xhprof'), 23 | 'all' => array(XHPROF_UINT_PARAM, 0), 24 | ); 25 | 26 | // pull values of these params, and create named globals for each param 27 | xhprof_param_init($params); 28 | 29 | /* reset params to be a array of variable names to values 30 | by the end of this page, param should only contain values that need 31 | to be preserved for the next page. unset all unwanted keys in $params. 32 | */ 33 | foreach ($params as $k => $v) { 34 | $params[$k] = $$k; 35 | 36 | // unset key from params that are using default values. So URLs aren't 37 | // ridiculously long. 38 | if ($params[$k] == $v[1]) { 39 | unset($params[$k]); 40 | } 41 | } 42 | 43 | 44 | $vbar = ' class="vbar"'; 45 | $vwbar = ' class="vwbar"'; 46 | $vwlbar = ' class="vwlbar"'; 47 | $vbbar = ' class="vbbar"'; 48 | $vrbar = ' class="vrbar"'; 49 | $vgbar = ' class="vgbar"'; 50 | 51 | $xhprof_runs_impl = new XHProfRuns_Default(); 52 | 53 | $domainFilter = getFilter('domain_filter'); 54 | $serverFilter = getFilter('server_filter'); 55 | 56 | $domainsRS = $xhprof_runs_impl->getDistinct(array('column' => 'server name')); 57 | $domainFilterOptions = array("None"); 58 | while ($row = XHProfRuns_Default::getNextAssoc($domainsRS)) 59 | { 60 | $domainFilterOptions[] = $row['server name']; 61 | } 62 | 63 | $serverRS = $xhprof_runs_impl->getDistinct(array('column' => 'server_id')); 64 | $serverFilterOptions = array("None"); 65 | while ($row = XHProfRuns_Default::getNextAssoc($serverRS)) 66 | { 67 | $serverFilterOptions[] = $row['server_id']; 68 | } 69 | 70 | $criteria = array(); 71 | if (!is_null($domainFilter)) 72 | { 73 | $criteria['server name'] = $domainFilter; 74 | } 75 | if (!is_null($serverFilter)) 76 | { 77 | $criteria['server_id'] = $serverFilter; 78 | } 79 | $_xh_header = ""; 80 | if(isset($_GET['run1']) || isset($_GET['run'])) 81 | { 82 | include ("../xhprof_lib/templates/header.phtml"); 83 | displayXHProfReport($xhprof_runs_impl, $params, $source, $run, $wts, 84 | $symbol, $sort, $run1, $run2); 85 | }elseif (isset($_GET['geturl'])) 86 | { 87 | $last = (isset($_GET['last'])) ? $_GET['last'] : 100; 88 | $last = (int) $last; 89 | $criteria['url'] = $_GET['geturl']; 90 | $criteria['limit'] = $last; 91 | $criteria['order by'] = 'timestamp'; 92 | $rs = $xhprof_runs_impl->getUrlStats($criteria); 93 | list($header, $body) = showChart($rs, true); 94 | $_xh_header .= $header; 95 | 96 | include ("../xhprof_lib/templates/header.phtml"); 97 | $rs = $xhprof_runs_impl->getRuns($criteria); 98 | include ("../xhprof_lib/templates/emptyBody.phtml"); 99 | 100 | $url = htmlentities($_GET['geturl'], ENT_QUOTES, "UTF-8"); 101 | displayRuns($rs, "Runs with URL: $url"); 102 | }elseif (isset($_GET['getcurl'])) 103 | { 104 | $last = (isset($_GET['last'])) ? $_GET['last'] : 100; 105 | $last = (int) $last; 106 | $criteria['c_url'] = $_GET['getcurl']; 107 | $criteria['limit'] = $last; 108 | $criteria['order by'] = 'timestamp'; 109 | 110 | $rs = $xhprof_runs_impl->getUrlStats($criteria); 111 | list($header, $body) = showChart($rs, true); 112 | $_xh_header .= $header; 113 | include ("../xhprof_lib/templates/header.phtml"); 114 | 115 | $url = htmlentities($_GET['getcurl'], ENT_QUOTES, "UTF-8"); 116 | $rs = $xhprof_runs_impl->getRuns($criteria); 117 | include("../xhprof_lib/templates/emptyBody.phtml"); 118 | displayRuns($rs, "Runs with Simplified URL: $url"); 119 | }elseif (isset($_GET['getruns'])) 120 | { 121 | include ("../xhprof_lib/templates/header.phtml"); 122 | $days = (int) $_GET['days']; 123 | 124 | switch ($_GET['getruns']) 125 | { 126 | case "cpu": 127 | $load = "cpu"; 128 | break; 129 | case "wt": 130 | $load = "wt"; 131 | break; 132 | case "pmu": 133 | $load = "pmu"; 134 | break; 135 | } 136 | 137 | $criteria['order by'] = $load; 138 | $criteria['limit'] = "500"; 139 | $criteria['where'] = "DATE_SUB(CURDATE(), INTERVAL $days DAY) <= `timestamp`"; 140 | $rs = $xhprof_runs_impl->getRuns($criteria); 141 | displayRuns($rs, "Worst runs by $load"); 142 | }elseif(isset($_GET['hit'])) 143 | { 144 | include ("../xhprof_lib/templates/header.phtml"); 145 | $last = (isset($_GET['hit'])) ? $_GET['hit'] : 25; 146 | $last = (int) $last; 147 | $days = (isset($_GET['days'])) ? $_GET['days'] : 1; 148 | $days = (int) $days; 149 | if (isset($_GET['type']) && ($_GET['type'] === 'url' OR $_GET['type'] = 'curl')) 150 | { 151 | $type = $_GET['type']; 152 | }else 153 | { 154 | $type = 'url'; 155 | } 156 | 157 | $criteria['limit'] = $last; 158 | $criteria['days'] = $days; 159 | $criteria['type'] = $type; 160 | $resultSet = $xhprof_runs_impl->getHardHit($criteria); 161 | 162 | echo "
Hardest Hit
\n"; 163 | echo ""; 164 | echo "\n"; 165 | while ($row = XHProfRuns_Default::getNextAssoc($resultSet)) 166 | { 167 | $url = urlencode($row['url']); 168 | $html['url'] = htmlentities($row['url'], ENT_QUOTES, 'UTF-8'); 169 | echo "\t\n"; 170 | } 171 | echo "\n"; 172 | echo "
URLHitsTotal Wall TimeAvg Wall Time
{$html['url']}{$row['count']}" . number_format($row['total_wall']) . " ms" . number_format($row['avg_wall']) . " ms
\n"; 173 | echo << 175 | $(document).ready(function() { 176 | $.tablesorter.addParser({ 177 | id: 'pretty', 178 | is: function(s) { 179 | return false; 180 | }, 181 | format: function(s) { 182 | s = s.replace(/ ms/g,""); 183 | return s.replace(/,/g,""); 184 | }, 185 | // set type, either numeric or text 186 | type: 'numeric' 187 | }); 188 | $(function() { 189 | $("table").tablesorter({ 190 | headers: { 191 | 2: { 192 | sorter:'pretty' 193 | }, 194 | 3: { 195 | sorter:'pretty' 196 | } 197 | } 198 | }); 199 | }); 200 | }); 201 | 202 | CODESE; 203 | }else 204 | { 205 | include ("../xhprof_lib/templates/header.phtml"); 206 | $last = (isset($_GET['last'])) ? $_GET['last'] : 25; 207 | $last = (int) $last; 208 | $criteria['order by'] = "timestamp"; 209 | $criteria['limit'] = $last; 210 | $rs = $xhprof_runs_impl->getRuns($criteria); 211 | displayRuns($rs, "Last $last Runs"); 212 | } 213 | 214 | include ("../xhprof_lib/templates/footer.phtml"); 215 | -------------------------------------------------------------------------------- /xhprof_lib/templates/single_run_header_block.phtml: -------------------------------------------------------------------------------- 1 | ", " ", stat_description($metric)); 7 | $arrayOfTotal[$i]["value"] = number_format($totals[$metric]) . " ". $possible_metrics[$metric][1]; 8 | $arrayOfTotal[$i]["metric"] = $possible_metrics[$metric][1]; 9 | $i++; 10 | } 11 | if ($display_calls) { 12 | $format_total= number_format($totals['ct']); 13 | } 14 | 15 | //TODO This is lame 16 | global $comparative; 17 | ?> 18 |
19 |
20 |

RunID: run_details['id']; ?> against run_details['server name'];?>run_details['url'], ENT_QUOTES, 'UTF-8'); ?>

21 | View Callgraph 22 |
23 |
24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 |
StatExact URLSimilar URLs
Count
Min Wall Time
Max Wall Time
Avg Wall Time
95% Wall Time
 
Min CPU Ticks
Max CPU Ticks
Avg CPU Ticks
95% CPU Ticks
 
Min Peak Memory Usage
Max Peak Memory Usage
Avg Peak Memory Usage
95% Peak Memory Usage
 
Number of Function Calls: 
Perform Delta:
55 |
56 |
57 |
58 | 59 |
60 |
61 | 62 | 63 | 64 | 65 | 66 | run_details['cookie']); 68 | // echo '
'.print_r($cookieArr, true).'
'; 69 | foreach($cookieArr as $key=>$value){ 70 | if (is_array($value)) 71 | { 72 | $value = implode(", ", $value); 73 | } 74 | echo "\n"; 75 | echo "\t\n"; 76 | echo "\n"; 77 | } 78 | if(count($cookieArr) == 0) 79 | { 80 | echo ""; 81 | } 82 | ?> 83 | 84 |
CookieResults
" . $key . "" . chunk_split($value) . "
  
85 |
86 |
87 | 88 | 89 | 90 | 91 | 92 | run_details['get']); 94 | // echo '
'.print_r($getArr, true).'
'; 95 | foreach($getArr as $key=>$value) 96 | { 97 | if (is_array($value)) 98 | { 99 | $value = implode(", ", $value); 100 | } 101 | echo ""; 102 | echo ""; 103 | echo ""; 104 | } 105 | if(count($getArr) == 0) 106 | { 107 | echo ""; 108 | } 109 | ?> 110 | 111 |
GetResults
" . $key . "" . $value . "
  
112 |
113 |
114 | 115 | 116 | 117 | 118 | 119 | run_details['post']); 121 | // echo '
'.print_r($postArr, true).'
'; 122 | foreach($postArr as $key=>$value){ 123 | if (is_array($value)) 124 | { 125 | $value = implode(", ", $value); 126 | } 127 | echo ""; 128 | echo ""; 129 | echo ""; 130 | } 131 | if(count($postArr) == 0) 132 | { 133 | echo ""; 134 | } 135 | ?> 136 | 137 |
PostResults
" . $key . "" . $value . "
  
138 |
139 |
140 |
141 |
142 |
143 | 144 | -------------------------------------------------------------------------------- /xhprof_html/css/xhprof.css: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2009 Facebook 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | td.sorted { 17 | color:#0000FF; 18 | } 19 | td.vbar, th.vbar { 20 | text-align: right; 21 | border-left: 22 | solid 1px #bdc7d8; 23 | } 24 | td.vbbar, th.vbar { 25 | text-align: right; 26 | border-left: 27 | solid 1px #bdc7d8; 28 | color:blue; 29 | } 30 | /* diff reports: display regressions in red */ 31 | td.vrbar { 32 | text-align: right; 33 | border-left:solid 1px #bdc7d8; 34 | color:red; 35 | } 36 | /* diff reports: display improvements in green */ 37 | td.vgbar { 38 | text-align: right; 39 | border-left: solid 1px #bdc7d8; 40 | color:green; 41 | } 42 | td.vwbar, th.vwbar { 43 | text-align: left; 44 | border-left: solid 1px white; 45 | /* background-color:#b9c9fe; */ 46 | } 47 | td.vwlbar, th.vwlbar { 48 | text-align: left; 49 | border-left: solid 1px white; 50 | } 51 | p.blue { 52 | color:blue 53 | } 54 | .bubble { 55 | background-color:#C3D9FF 56 | } 57 | ul.xhprof_actions { 58 | float: right; 59 | padding-left: 16px; 60 | list-style-image: none; 61 | list-style-type: none; 62 | margin:10px 10px 10px 3em; 63 | position:relative; 64 | } 65 | ul.xhprof_actions li { 66 | border-bottom:1px solid #D8DFEA; 67 | } 68 | ul.xhprof_actions li a:hover { 69 | background:#3B5998 none repeat scroll 0 0; 70 | color:#FFFFFF; 71 | } 72 | /* Styling for New Pages */ 73 | 74 | .dash-header {width:100%;height:100px;background:#e8edff;border: 2px solid #b9c9fe;margin-right:auto;margin-left:auto;} 75 | .search {width:auto;float:right;height:25px;margin-top:10px;margin-right:25px;font-family:"Lucida Grande", Sans-Serif;font-size:13px;} 76 | .link-options {width:auto;float:right;clear:right;height:auto;font-family:"Lucida Grande", Sans-Serif;font-size:13px;margin-right:20px;position:relative;top:45px;} 77 | .link-options a { margin: 0 0.2em; } 78 | h1.xh-title {width:225px;font-family:"Lucida Grande", Sans-Serif;font-size:30px;font-weight:bold;color:#333333;margin-left:20px;} 79 | .form-button {border:1px solid #999999;cursor:pointer;background-color:#b9c9fe;-webkit-border-radius: 4px;-moz-border-radius: 4px;} 80 | .form-button:hover {border:1px solid #999999;cursor:pointer;background-color:#e8edff;-webkit-border-radius: 4px;-moz-border-radius: 4px;} 81 | .runTitle {font-family:"Lucida Grande", Sans-Serif;font-size:18px;margin-left:auto;margin-right:auto;color:#333333;text-align:center;margin-top:25px;border: 2px solid #b9c9fe;padding:4px;} 82 | #box-table-a {width:100%;font-family: Monospace,"Courier New";font-size:12px;margin:20px auto 45px auto;text-align: left;border-collapse:collapse;} 83 | #box-table-a th {font-size:13px;font-weight:normal;padding: 8px 8px 8px 20px;background-color:#b9c9fe;border-top:4px solid #aabcfe;border-bottom: 1px solid #ffffff;color: #333333;} 84 | #box-table-a td {padding:8px;background:#e8edff;border-bottom:1px solid #ffffff;color:#333333;border-top: 1px solid transparent;} 85 | #box-table-a tr:hover td {background:#d0dafd;color:#339;} 86 | #box-table-a, .link-options a:link {color:#0066ff;} 87 | #box-table-a, .link-options a:hover {color:#0066ff;} 88 | #box-table-a, .link-options a:visited {color:#cc0066;} 89 | 90 | #view-center-tables {width:100%;min-height:575px;background-color:#ffffff;border: 1px solid #b9c9fe;margin-right:auto;margin-left:auto;-webkit-border-radius:4px;-moz-border-radius:4px;position:relative;top:30px;} 91 | #view-diff-tables {width:100%;min-height:500px;background-color:#ffffff;border: 1px solid #b9c9fe;margin-right:auto;margin-left:auto;-webkit-border-radius:4px;-moz-border-radius:4px;position:relative;top:30px;} 92 | #run-id-wrapper {width:100%;margin-right:auto;margin-left:auto;height:auto;} 93 | .runid {font-family:Monospace,"Courier New";} 94 | h2.run-details {margin-left:20px;margin-right:20px;font-family:Monospace,"Courier New";font-size:1.125em;color:#333333;} 95 | h2.diff-details {font-family:Monospace,"Courier New";font-size:1.125em;color:#333333;margin:15px 0 0 15px;} 96 | /*#invert-wrapper{width: 100%;height: auto;} */ 97 | #invert-image{float:left;width:auto;height:80px;} 98 | #link-id{float:left;width:auto;height:80px;margin:0px;padding:0px;} 99 | #diff-graph{width:100%;padding-bottom:10px;float:left; height:auto;padding-top:10px;} 100 | #clear{clear: left;width: 100%;} 101 | a.callgraph:link {margin-left:20px;font-family: "Lucida Grande", Sans-Serif;font-size:1.064em;color:#0066ff;} 102 | a.callgraph:hover {margin-left:20px;font-family: "Lucida Grande", Sans-Serif;font-size:1.064em;color:#0066ff;} 103 | a.callgraph:visited {margin-left:20px;font-family: "Lucida Grande", Sans-Serif;font-size:1.064em;color:#0066ff;} 104 | 105 | #left-col{width:51%;float:left; margin-left:1%; margin-top:15px;} 106 | #right-col{width:45%;float:left;margin-left:2%;margin-top:15px;} 107 | 108 | #box-table-b {width: 100%;font-family:Monospace,"Courier New";font-size:12px;text-align: left;border-collapse: collapse;float:left;} 109 | #box-table-b th {font-size:13px;font-weight:normal;padding: 4px 4px 4px 4px;background-color: #b9c9fe;border-top:4px solid #aabcfe;border-bottom: 1px solid #ffffff;color: #333333;} 110 | #box-table-b td {padding:4px;background:#e8edff;border-bottom: 1px solid #ffffff;color:#333333;border-top: 1px solid transparent;} 111 | #box-table-b tr:hover td {background:#d0dafd;color:#339;} 112 | #box-table-b .link-options a:link {color:#0066ff;} 113 | #box-table-b .link-options a:hover {color:#0066ff;} 114 | #box-table-b .link-options a:visited {color:#cc0066;} 115 | 116 | .box-fix {width: 100%;overflow:auto;} 117 | .box-fix-cr {width:100%;overflow:auto;margin:20px 0 0 0;clear:right;} 118 | .box-tables {width: 100%;font-family: Monospace,"Courier New";font-size:12px;border-collapse:collapse;text-align:left;} 119 | .box-tables th {font-size:13px;font-weight:normal;padding: 4px 4px 4px 4px;background-color:#b9c9fe;border-top: 4px solid #aabcfe;border-bottom: 1px solid #ffffff;color:#333333;} 120 | .box-tables td {padding:4px;background:#e8edff;border-bottom:1px solid #ffffff;color:#333333;border-top:1px solid transparent;} 121 | .box-tables tr:hover td {background: #d0dafd;color:#339;} 122 | .box-tables .link-options a:link {color:#0066ff;} 123 | .box-tables .link-options a:hover {color:#0066ff;} 124 | .box-tables .link-options a:visited {color:#cc0066;} 125 | 126 | .colone {width:30%;height:auto;float:left;margin-left:1%;} 127 | .coltwo {width:36%;height:auto;float:left;margin-left:1%;} 128 | .colthree {width:30%;height:auto;float:left;margin-left:1%;} 129 | 130 | .overall{font-family: "Lucida Grande", Sans-Serif;font-size:1.188em;color:#333333;} 131 | a.invert:link {font-family:"Lucida Grande", Sans-serif;font-size:0.875em;color:#0066ff;} 132 | a.invert:hover {font-family:"Lucida Grande", Sans-serif;font-size:0.875em;color:#0066ff;} 133 | a.invert:visited {font-family:"Lucida Grande", Sans-serif;font-size:0.875em;color:#0066ff;} 134 | 135 | #diff-summary {width:100%;height:auto;float:left;overflow:auto;} 136 | .diff-box {font-family:Monospace,"Courier New";font-size:12px;border-collapse:collapse;text-align:left;} 137 | .diff-box th {font-size:13px;font-weight:normal;padding: 4px 4px 4px 4px;background-color:#aabcfe;border-top: 4px solid #aacdfe;border-bottom: 1px solid #ffffff;color:#333333;} 138 | .diff-box td {padding:3px;background:#e8edff;border-bottom:1px solid #ffffff;color:#333333;border-top:1px solid transparent;} 139 | .diff-box tr:hover td {background: #d0dafd;color:#339;} 140 | .diff-box .link-options a:link {color:#0066ff;} 141 | .diff-box .link-options a:hover {color:#0066ff;} 142 | .diff-box .link-options a:visited {color:#cc0066;} 143 | 144 | .box-fix-small {width:100%;height:120px;overflow:auto;float:left;margin:0;} 145 | .box-fix-small-cl {width:100%; height:120px;overflow:auto;float:left; margin-top:20px;clear:left;} 146 | .box-tables-small {font-family:Monospace,"Courier New";font-size:12px;border-collapse:collapse;text-align:left;width: 100%;} 147 | .box-tables-small th {font-size:13px;font-weight:normal;padding: 4px 4px 4px 4px;background-color:#b9c9fe;border-top: 4px solid #aabcfe;border-bottom: 1px solid #ffffff;color:#333333;} 148 | .box-tables-small td {padding:4px;background:#e8edff;border-bottom:1px solid #ffffff;color:#333333;border-top:1px solid transparent;} 149 | .box-tables-small tr:hover td {background: #d0dafd;color:#339;} 150 | .box-tables-small .link-options a:link {color:#0066ff;} 151 | .box-tables-small .link-options a:hover {color:#0066ff;} 152 | .box-tables-small .link-options a:visited {color:#cc0066;} 153 | .different {font-family:Monospace,"Courier New";font-size:12px;font-weight:bold;} 154 | img{border: none;} 155 | :focus{outline:none;} -------------------------------------------------------------------------------- /xhprof_html/third-party/jquery/jquery.tooltip.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Tooltip plugin 1.3 3 | * 4 | * http://bassistance.de/jquery-plugins/jquery-plugin-tooltip/ 5 | * http://docs.jquery.com/Plugins/Tooltip 6 | * 7 | * Copyright (c) 2006 - 2008 Jörn Zaefferer 8 | * 9 | * $Id: jquery.tooltip.js,v 1.1.1.1 2009/03/17 18:35:18 kannan Exp $ 10 | * 11 | * Dual licensed under the MIT and GPL licenses: 12 | * http://www.opensource.org/licenses/mit-license.php 13 | * http://www.gnu.org/licenses/gpl.html 14 | */ 15 | 16 | ;(function($) { 17 | 18 | // the tooltip element 19 | var helper = {}, 20 | // the current tooltipped element 21 | current, 22 | // the title of the current element, used for restoring 23 | title, 24 | // timeout id for delayed tooltips 25 | tID, 26 | // IE 5.5 or 6 27 | IE = $.browser.msie && /MSIE\s(5\.5|6\.)/.test(navigator.userAgent), 28 | // flag for mouse tracking 29 | track = false; 30 | 31 | $.tooltip = { 32 | blocked: false, 33 | defaults: { 34 | delay: 200, 35 | fade: false, 36 | showURL: true, 37 | extraClass: "", 38 | top: 15, 39 | left: 15, 40 | id: "tooltip" 41 | }, 42 | block: function() { 43 | $.tooltip.blocked = !$.tooltip.blocked; 44 | } 45 | }; 46 | 47 | $.fn.extend({ 48 | tooltip: function(settings) { 49 | settings = $.extend({}, $.tooltip.defaults, settings); 50 | createHelper(settings); 51 | return this.each(function() { 52 | $.data(this, "tooltip", settings); 53 | this.tOpacity = helper.parent.css("opacity"); 54 | // copy tooltip into its own expando and remove the title 55 | this.tooltipText = this.title; 56 | $(this).removeAttr("title"); 57 | // also remove alt attribute to prevent default tooltip in IE 58 | this.alt = ""; 59 | }) 60 | .mouseover(save) 61 | .mouseout(hide) 62 | .click(hide); 63 | }, 64 | fixPNG: IE ? function() { 65 | return this.each(function () { 66 | var image = $(this).css('backgroundImage'); 67 | if (image.match(/^url\(["']?(.*\.png)["']?\)$/i)) { 68 | image = RegExp.$1; 69 | $(this).css({ 70 | 'backgroundImage': 'none', 71 | 'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')" 72 | }).each(function () { 73 | var position = $(this).css('position'); 74 | if (position != 'absolute' && position != 'relative') 75 | $(this).css('position', 'relative'); 76 | }); 77 | } 78 | }); 79 | } : function() { return this; }, 80 | unfixPNG: IE ? function() { 81 | return this.each(function () { 82 | $(this).css({'filter': '', backgroundImage: ''}); 83 | }); 84 | } : function() { return this; }, 85 | hideWhenEmpty: function() { 86 | return this.each(function() { 87 | $(this)[ $(this).html() ? "show" : "hide" ](); 88 | }); 89 | }, 90 | url: function() { 91 | return this.attr('href') || this.attr('src'); 92 | } 93 | }); 94 | 95 | function createHelper(settings) { 96 | // there can be only one tooltip helper 97 | if( helper.parent ) 98 | return; 99 | // create the helper, h3 for title, div for url 100 | helper.parent = $('

') 101 | // add to document 102 | .appendTo(document.body) 103 | // hide it at first 104 | .hide(); 105 | 106 | // apply bgiframe if available 107 | if ( $.fn.bgiframe ) 108 | helper.parent.bgiframe(); 109 | 110 | // save references to title and url elements 111 | helper.title = $('h3', helper.parent); 112 | helper.body = $('div.body', helper.parent); 113 | helper.url = $('div.url', helper.parent); 114 | } 115 | 116 | function settings(element) { 117 | return $.data(element, "tooltip"); 118 | } 119 | 120 | // main event handler to start showing tooltips 121 | function handle(event) { 122 | // show helper, either with timeout or on instant 123 | if( settings(this).delay ) 124 | tID = setTimeout(show, settings(this).delay); 125 | else 126 | show(); 127 | 128 | // if selected, update the helper position when the mouse moves 129 | track = !!settings(this).track; 130 | $(document.body).bind('mousemove', update); 131 | 132 | // update at least once 133 | update(event); 134 | } 135 | 136 | // save elements title before the tooltip is displayed 137 | function save() { 138 | // if this is the current source, or it has no title (occurs with click event), stop 139 | if ( $.tooltip.blocked || this == current || (!this.tooltipText && !settings(this).bodyHandler) ) 140 | return; 141 | 142 | // save current 143 | current = this; 144 | title = this.tooltipText; 145 | 146 | if ( settings(this).bodyHandler ) { 147 | helper.title.hide(); 148 | var bodyContent = settings(this).bodyHandler.call(this); 149 | if (bodyContent.nodeType || bodyContent.jquery) { 150 | helper.body.empty().append(bodyContent) 151 | } else { 152 | helper.body.html( bodyContent ); 153 | } 154 | helper.body.show(); 155 | } else if ( settings(this).showBody ) { 156 | var parts = title.split(settings(this).showBody); 157 | helper.title.html(parts.shift()).show(); 158 | helper.body.empty(); 159 | for(var i = 0, part; (part = parts[i]); i++) { 160 | if(i > 0) 161 | helper.body.append("
"); 162 | helper.body.append(part); 163 | } 164 | helper.body.hideWhenEmpty(); 165 | } else { 166 | helper.title.html(title).show(); 167 | helper.body.hide(); 168 | } 169 | 170 | // if element has href or src, add and show it, otherwise hide it 171 | if( settings(this).showURL && $(this).url() ) 172 | helper.url.html( $(this).url().replace('http://', '') ).show(); 173 | else 174 | helper.url.hide(); 175 | 176 | // add an optional class for this tip 177 | helper.parent.addClass(settings(this).extraClass); 178 | 179 | // fix PNG background for IE 180 | if (settings(this).fixPNG ) 181 | helper.parent.fixPNG(); 182 | 183 | handle.apply(this, arguments); 184 | } 185 | 186 | // delete timeout and show helper 187 | function show() { 188 | tID = null; 189 | if ((!IE || !$.fn.bgiframe) && settings(current).fade) { 190 | if (helper.parent.is(":animated")) 191 | helper.parent.stop().show().fadeTo(settings(current).fade, current.tOpacity); 192 | else 193 | helper.parent.is(':visible') ? helper.parent.fadeTo(settings(current).fade, current.tOpacity) : helper.parent.fadeIn(settings(current).fade); 194 | } else { 195 | helper.parent.show(); 196 | } 197 | update(); 198 | } 199 | 200 | /** 201 | * callback for mousemove 202 | * updates the helper position 203 | * removes itself when no current element 204 | */ 205 | function update(event) { 206 | if($.tooltip.blocked) 207 | return; 208 | 209 | if (event && event.target.tagName == "OPTION") { 210 | return; 211 | } 212 | 213 | // stop updating when tracking is disabled and the tooltip is visible 214 | if ( !track && helper.parent.is(":visible")) { 215 | $(document.body).unbind('mousemove', update) 216 | } 217 | 218 | // if no current element is available, remove this listener 219 | if( current == null ) { 220 | $(document.body).unbind('mousemove', update); 221 | return; 222 | } 223 | 224 | // remove position helper classes 225 | helper.parent.removeClass("viewport-right").removeClass("viewport-bottom"); 226 | 227 | var left = helper.parent[0].offsetLeft; 228 | var top = helper.parent[0].offsetTop; 229 | if (event) { 230 | // position the helper 15 pixel to bottom right, starting from mouse position 231 | left = event.pageX + settings(current).left; 232 | top = event.pageY + settings(current).top; 233 | var right='auto'; 234 | if (settings(current).positionLeft) { 235 | right = $(window).width() - left; 236 | left = 'auto'; 237 | } 238 | helper.parent.css({ 239 | left: left, 240 | right: right, 241 | top: top 242 | }); 243 | } 244 | 245 | var v = viewport(), 246 | h = helper.parent[0]; 247 | // check horizontal position 248 | if (v.x + v.cx < h.offsetLeft + h.offsetWidth) { 249 | left -= h.offsetWidth + 20 + settings(current).left; 250 | helper.parent.css({left: left + 'px'}).addClass("viewport-right"); 251 | } 252 | // check vertical position 253 | if (v.y + v.cy < h.offsetTop + h.offsetHeight) { 254 | top -= h.offsetHeight + 20 + settings(current).top; 255 | helper.parent.css({top: top + 'px'}).addClass("viewport-bottom"); 256 | } 257 | } 258 | 259 | function viewport() { 260 | return { 261 | x: $(window).scrollLeft(), 262 | y: $(window).scrollTop(), 263 | cx: $(window).width(), 264 | cy: $(window).height() 265 | }; 266 | } 267 | 268 | // hide helper and restore added classes and the title 269 | function hide(event) { 270 | if($.tooltip.blocked) 271 | return; 272 | // clear timeout if possible 273 | if(tID) 274 | clearTimeout(tID); 275 | // no more current element 276 | current = null; 277 | 278 | var tsettings = settings(this); 279 | function complete() { 280 | helper.parent.removeClass( tsettings.extraClass ).hide().css("opacity", ""); 281 | } 282 | if ((!IE || !$.fn.bgiframe) && tsettings.fade) { 283 | if (helper.parent.is(':animated')) 284 | helper.parent.stop().fadeTo(tsettings.fade, 0, complete); 285 | else 286 | helper.parent.stop().fadeOut(tsettings.fade, complete); 287 | } else 288 | complete(); 289 | 290 | if( settings(this).fixPNG ) 291 | helper.parent.unfixPNG(); 292 | } 293 | 294 | })(jQuery); 295 | -------------------------------------------------------------------------------- /xhprof_lib/templates/diff_run_header_block.phtml: -------------------------------------------------------------------------------- 1 | '); 11 | print("
"); 12 | print("
"); 13 | print("\"Invert"); 14 | print("
"); 15 | print(""); 19 | print("
"); 20 | 21 | print("
"); 22 | print("View Callgraph"); 23 | print("
"); 24 | 25 | print("
"); 26 | 27 | print('
'); 28 | // cookie diff data from array position 0 29 | $cookieArr0 = unserialize($xhprof_runs_impl->run_details[0]['cookie']); 30 | $cookieArr1 = unserialize($xhprof_runs_impl->run_details[1]['cookie']); 31 | $getArr0 = unserialize($xhprof_runs_impl->run_details[0]['get']); 32 | $getArr1 = unserialize($xhprof_runs_impl->run_details[1]['get']); 33 | $postArr0 = unserialize($xhprof_runs_impl->run_details[0]['post']); 34 | $postArr1 = unserialize($xhprof_runs_impl->run_details[1]['post']); 35 | 36 | 37 | print ('
'); 38 | print ''; 39 | print ""; 40 | print ""; 41 | print ""; 42 | print ""; 43 | 44 | foreach($cookieArr0 as $key=>$value){ 45 | echo ""; 46 | 47 | if(isset($cookieArr1[$key]) && $cookieArr0[$key] == $cookieArr1[$key]){ 48 | $class ="normal"; 49 | }else{ 50 | $class ="different"; 51 | } 52 | echo ""; 53 | echo ""; 54 | } 55 | print ""; 56 | print "
Run One ID:\n$run1Cookie Results
" . $key . "" . chunk_split($value) . "
"; 57 | print "
"; 58 | 59 | // get diff data from array position 0 60 | 61 | // $getArr0 = unserialize($xhprof_runs_impl->run_details[0]['get']); 62 | print '
'; 63 | print ''; 64 | print ""; 65 | print ""; 66 | print ""; 67 | print ""; 68 | 69 | foreach($getArr0 as $key=>$value){ 70 | echo ""; 71 | 72 | if(isset($getArr1[$key]) && ($getArr0[$key] == $getArr1[$key])){ 73 | $class ="normal"; 74 | }else{ 75 | $class ="different"; 76 | } 77 | if (is_array($value)) 78 | { 79 | $value = implode(", ", $value); 80 | } 81 | echo ""; 82 | echo ""; 83 | } 84 | print ""; 85 | print "
Run:$run1Get Results
" . $key . "" . chunk_split($value) . "
"; 86 | print "
"; 87 | 88 | // post diff data from array position 0 89 | // $postArr0 = unserialize($xhprof_runs_impl->run_details[0]['post']); 90 | print '
'; 91 | print ''; 92 | print ""; 93 | print ""; 94 | print ""; 95 | print ""; 96 | 97 | foreach($postArr0 as $key=>$value){ 98 | echo ""; 99 | if(isset($postArr1[$key]) && $postArr0[$key] == $postArr1[$key]){ 100 | $class ="normal"; 101 | }else{ 102 | $class ="different"; 103 | } 104 | echo ""; 105 | echo ""; 106 | } 107 | print ""; 108 | print "
Run:$run1Post Results
" . $key . "" . chunk_split($value) . "
"; 109 | print "
"; 110 | 111 | print('
'); 112 | 113 | print('
'); 114 | print('
'); 115 | print(''); 116 | print(""); 117 | print(''); 118 | print(""); 119 | print(""); 120 | print(""); 121 | print(""); 122 | print(""); 123 | print(''); 124 | print(""); 125 | print ""; 126 | if ($display_calls) { 127 | print(''); 128 | print(""); 129 | print_td_num($totals_1["ct"], $format_cbk["ct"]); 130 | print_td_num($totals_2["ct"], $format_cbk["ct"]); 131 | print_td_num($totals_2["ct"] - $totals_1["ct"], $format_cbk["ct"], true); 132 | print_td_pct($totals_2["ct"] - $totals_1["ct"], $totals_1["ct"], true); 133 | print(''); 134 | } 135 | 136 | foreach ($metrics as $metric) { 137 | $m = $metric; 138 | print(''); 139 | print(""); 140 | print_td_num($totals_1[$m], $format_cbk[$m]); 141 | print_td_num($totals_2[$m], $format_cbk[$m]); 142 | print_td_num($totals_2[$m] - $totals_1[$m], $format_cbk[$m], true); 143 | print_td_pct($totals_2[$m] - $totals_1[$m], $totals_1[$m], true); 144 | print(''); 145 | } 146 | print ""; 147 | print('
Run One ID: " . xhprof_render_link("$run1", $href1) . "Run Two ID: " . xhprof_render_link("$run2", $href2) . "DiffDiff%
Number of Function Calls
" . str_replace("
", " ", $descriptions[$m]) . "
'); 148 | print('
'); 149 | 150 | 151 | print('
'); 152 | 153 | 154 | print('
'); 155 | print '
'; 156 | print ''; 157 | print ""; 158 | print ""; 159 | print ""; 160 | print ""; 161 | // cookie diff data from array position 1 162 | //$cookieArr1 = unserialize($xhprof_runs_impl->run_details[1]['cookie']); 163 | 164 | foreach($cookieArr1 as $key=>$value){ 165 | echo ""; 166 | 167 | if(isset($cookieArr0[$key]) && ($cookieArr1[$key] == $cookieArr0[$key])){ 168 | $class ="normal"; 169 | }else{ 170 | $class ="different"; 171 | } 172 | echo ""; 173 | echo ""; 174 | } 175 | print ""; 176 | print "
Run Two ID:\n$run2Cookie Results
" . $key . "" . chunk_split($value) . "
"; 177 | print "
"; 178 | 179 | 180 | print '
'; 181 | print ''; 182 | print ""; 183 | print ""; 184 | print ""; 185 | print ""; 186 | // get diff data from array position 1 187 | // $getArr1 = unserialize($xhprof_runs_impl->run_details[1]['get']); 188 | 189 | foreach($getArr1 as $key=>$value){ 190 | echo ""; 191 | 192 | if(isset($getArr0[$key]) && ($getArr1[$key] == $getArr0[$key])){ 193 | $class ="normal"; 194 | }else{ 195 | $class ="different"; 196 | } 197 | if(is_array($value)) 198 | { 199 | $value = implode(", ", $value); 200 | } 201 | echo ""; 202 | echo ""; 203 | } 204 | print ""; 205 | print "
Run:$run2Get Results
" . $key . "" . chunk_split($value) . "
"; 206 | print "
"; 207 | 208 | 209 | print '
'; 210 | print ''; 211 | print ""; 212 | print ""; 213 | print ""; 214 | print ""; 215 | // post diff data from array position 1 216 | // $postArr1 = unserialize($xhprof_runs_impl->run_details[1]['post']); 217 | 218 | foreach($postArr1 as $key=>$value){ 219 | echo ""; 220 | 221 | if($postArr1[$key] == $postArr0[$key]){ 222 | $class ="normal"; 223 | }else{ 224 | $class ="different"; 225 | } 226 | echo ""; 227 | echo ""; 228 | } 229 | ?> 230 | 231 |
Run:$run2Post Results
" . $key . "" . chunk_split($value) . "
232 |
233 |
234 | -------------------------------------------------------------------------------- /extension/tests/xhprof_007.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | XHPRrof: Test excluding call_user_func and similar functions 3 | Author: mpal 4 | --FILE-- 5 | 10 | array('call_user_func', 11 | 'call_user_func_array', 12 | 'my_call_user_func_safe', 13 | 'my_call_user_func_array_safe')); 14 | function bar() { 15 | return 1; 16 | } 17 | 18 | function foo($x) { 19 | $sum = 0; 20 | for ($idx = 0; $idx < 2; $idx++) { 21 | $sum += bar(); 22 | } 23 | echo "hello: {$x}\n" ; 24 | return strlen("hello: {$x}"); 25 | } 26 | 27 | function foo_array($x1, $x2 = 'test') { 28 | $sum = 0; 29 | $x = array($x1, $x2); 30 | foreach ($x as $idx) { 31 | $sum += bar(); 32 | } 33 | echo "hello: " . $x[0] . $x[1] . "\n"; 34 | return strlen("hello: {$x[0]} {$x[1]}"); 35 | } 36 | 37 | function my_call_user_func_safe($function, $args = 'my_safe') { 38 | if (!is_callable($function, true)) { 39 | throw new Exception('my_call_user_func_safe() invoked without ' . 40 | 'a valid callable.'); 41 | } 42 | 43 | call_user_func($function, array($args)); 44 | } 45 | 46 | function my_call_user_func_array_safe($function, $args = array()) { 47 | if (!is_callable($function, true)) { 48 | throw new Exception('my_call_user_func_array_safe() invoked without ' . 49 | 'a valid callable.'); 50 | } 51 | 52 | call_user_func_array($function, $args); 53 | } 54 | 55 | 56 | class test_call_user_func { 57 | function test_call_user_func($test_func = 'foo', 58 | $arg1 = 'user_func test') { 59 | call_user_func($test_func, $arg1); 60 | } 61 | } 62 | 63 | function test_call_user_func_array($test_func = 'foo_array', 64 | $arg1 = array(0 => 'user_func_array', 65 | 'test')) { 66 | call_user_func_array($test_func, $arg1); 67 | } 68 | 69 | function test_my_call_user_func_safe($test_func = 'foo', 70 | $arg1 = 'my_user_func_safe test') { 71 | my_call_user_func_safe($test_func, $arg1); 72 | } 73 | 74 | function test_my_call_user_func_array_safe( 75 | $test_func = 'foo_array', 76 | $arg1 = array('my_user_func_array_safe', 77 | 'test')) { 78 | my_call_user_func_array_safe($test_func, $arg1); 79 | } 80 | 81 | 82 | // 1: Sanity test a simple profile run 83 | echo "Part 1: Default Flags\n"; 84 | xhprof_enable(0, $xhprof_ignored_functions); 85 | foo("this is a test"); 86 | $array_arg = array(); 87 | $array_arg[] = 'calling '; 88 | $array_arg[] = 'foo_array'; 89 | foo_array($array_arg); 90 | 91 | $output = xhprof_disable(); 92 | echo "Part 1 output:\n"; 93 | print_canonical($output); 94 | echo "\n"; 95 | 96 | // 2a: Sanity test ignoring call_user_func 97 | echo "Part 2a: Ignore call_user_func\n"; 98 | xhprof_enable(0, $xhprof_ignored_functions); 99 | $indirect_foo = new test_call_user_func('foo'); 100 | $output = xhprof_disable(); 101 | echo "Part 2a output:\n"; 102 | print_canonical($output); 103 | echo "\n"; 104 | 105 | // 2b: Confirm that profiling without parameters still works 106 | echo "Part 2b: Standard profile without parameters\n"; 107 | xhprof_enable(); 108 | $indirect_foo = new test_call_user_func('foo'); 109 | $output = xhprof_disable(); 110 | echo "Part 2b output:\n"; 111 | print_canonical($output); 112 | echo "\n"; 113 | 114 | // 2c: Confirm that empty array of ignored functions works 115 | echo "Part 2c: Standard profile with empty array of ignored functions\n"; 116 | xhprof_enable(0, array()); 117 | $indirect_foo = new test_call_user_func('foo'); 118 | $output = xhprof_disable(); 119 | echo "Part 2c output:\n"; 120 | print_canonical($output); 121 | echo "\n"; 122 | 123 | // 3: Sanity test ignoring call_user_func_array 124 | echo "Part 3: Ignore call_user_func_array\n"; 125 | xhprof_enable(XHPROF_FLAGS_CPU, $xhprof_ignored_functions); 126 | test_call_user_func_array('foo_array', $array_arg); 127 | $output = xhprof_disable(); 128 | echo "Part 3 output:\n"; 129 | print_canonical($output); 130 | echo "\n"; 131 | 132 | // 4: Sanity test ignoring my_call_user_func_safe 133 | echo "Part 4: Ignore my_call_user_func_safe\n"; 134 | xhprof_enable(0, $xhprof_ignored_functions); 135 | test_my_call_user_func_safe('foo'); 136 | $output = xhprof_disable(); 137 | echo "Part 4 output:\n"; 138 | print_canonical($output); 139 | echo "\n"; 140 | 141 | // 5a: Sanity test ignoring my_call_user_func_array_safe and strlen 142 | echo "Part 5a: Ignore my_call_user_func_array_safe and strlen\n"; 143 | $tmp1 = $xhprof_ignored_functions['ignored_functions']; 144 | $tmp1[] = 'strlen'; 145 | $ignore_strlen_also = array('ignored_functions' => $tmp1); 146 | xhprof_enable(XHPROF_FLAGS_MEMORY, $ignore_strlen_also); 147 | test_my_call_user_func_array_safe('foo_array'); 148 | $output = xhprof_disable(); 149 | echo "Part 5a output:\n"; 150 | print_canonical($output); 151 | echo "\n"; 152 | 153 | // 5b: Sanity test to not ignore call_user_func variants 154 | echo "Part 5b: Profile call_user_func_array and my_call_user_func_array_safe\n"; 155 | xhprof_enable(XHPROF_FLAGS_MEMORY, array()); 156 | test_my_call_user_func_array_safe('foo_array'); 157 | $output = xhprof_disable(); 158 | echo "Part 5b output:\n"; 159 | print_canonical($output); 160 | echo "\n"; 161 | 162 | // 5c: Sanity test to only ignore my_call_user_func_array_safe 163 | echo "Part 5c: Only ignore call_user_func_array\n"; 164 | $xhprof_ignored_functions = array('ignored_functions' => 165 | 'my_call_user_func_array_safe'); 166 | xhprof_enable(XHPROF_FLAGS_MEMORY, $xhprof_ignored_functions); 167 | test_my_call_user_func_array_safe('foo_array'); 168 | $output = xhprof_disable(); 169 | echo "Part 5c output:\n"; 170 | print_canonical($output); 171 | echo "\n"; 172 | 173 | ?> 174 | --EXPECT-- 175 | Part 1: Default Flags 176 | hello: this is a test 177 | hello: Arraytest 178 | Part 1 output: 179 | foo==>bar : ct= 2; wt=*; 180 | foo==>strlen : ct= 1; wt=*; 181 | foo_array==>bar : ct= 2; wt=*; 182 | foo_array==>strlen : ct= 1; wt=*; 183 | main() : ct= 1; wt=*; 184 | main()==>foo : ct= 1; wt=*; 185 | main()==>foo_array : ct= 1; wt=*; 186 | main()==>xhprof_disable : ct= 1; wt=*; 187 | 188 | Part 2a: Ignore call_user_func 189 | hello: user_func test 190 | Part 2a output: 191 | foo==>bar : ct= 2; wt=*; 192 | foo==>strlen : ct= 1; wt=*; 193 | main() : ct= 1; wt=*; 194 | main()==>test_call_user_func::test_call_user_func: ct= 1; wt=*; 195 | main()==>xhprof_disable : ct= 1; wt=*; 196 | test_call_user_func::test_call_user_func==>foo: ct= 1; wt=*; 197 | 198 | Part 2b: Standard profile without parameters 199 | hello: user_func test 200 | Part 2b output: 201 | call_user_func==>foo : ct= 1; wt=*; 202 | foo==>bar : ct= 2; wt=*; 203 | foo==>strlen : ct= 1; wt=*; 204 | main() : ct= 1; wt=*; 205 | main()==>test_call_user_func::test_call_user_func: ct= 1; wt=*; 206 | main()==>xhprof_disable : ct= 1; wt=*; 207 | test_call_user_func::test_call_user_func==>call_user_func: ct= 1; wt=*; 208 | 209 | Part 2c: Standard profile with empty array of ignored functions 210 | hello: user_func test 211 | Part 2c output: 212 | call_user_func==>foo : ct= 1; wt=*; 213 | foo==>bar : ct= 2; wt=*; 214 | foo==>strlen : ct= 1; wt=*; 215 | main() : ct= 1; wt=*; 216 | main()==>test_call_user_func::test_call_user_func: ct= 1; wt=*; 217 | main()==>xhprof_disable : ct= 1; wt=*; 218 | test_call_user_func::test_call_user_func==>call_user_func: ct= 1; wt=*; 219 | 220 | Part 3: Ignore call_user_func_array 221 | hello: calling foo_array 222 | Part 3 output: 223 | foo_array==>bar : cpu=*; ct= 2; wt=*; 224 | foo_array==>strlen : cpu=*; ct= 1; wt=*; 225 | main() : cpu=*; ct= 1; wt=*; 226 | main()==>test_call_user_func_array : cpu=*; ct= 1; wt=*; 227 | main()==>xhprof_disable : cpu=*; ct= 1; wt=*; 228 | test_call_user_func_array==>foo_array : cpu=*; ct= 1; wt=*; 229 | 230 | Part 4: Ignore my_call_user_func_safe 231 | hello: Array 232 | Part 4 output: 233 | foo==>bar : ct= 2; wt=*; 234 | foo==>strlen : ct= 1; wt=*; 235 | main() : ct= 1; wt=*; 236 | main()==>test_my_call_user_func_safe : ct= 1; wt=*; 237 | main()==>xhprof_disable : ct= 1; wt=*; 238 | test_my_call_user_func_safe==>foo : ct= 1; wt=*; 239 | test_my_call_user_func_safe==>is_callable: ct= 1; wt=*; 240 | 241 | Part 5a: Ignore my_call_user_func_array_safe and strlen 242 | hello: my_user_func_array_safetest 243 | Part 5a output: 244 | foo_array==>bar : ct= 2; mu=*; pmu=*; wt=*; 245 | main() : ct= 1; mu=*; pmu=*; wt=*; 246 | main()==>test_my_call_user_func_array_safe: ct= 1; mu=*; pmu=*; wt=*; 247 | main()==>xhprof_disable : ct= 1; mu=*; pmu=*; wt=*; 248 | test_my_call_user_func_array_safe==>foo_array: ct= 1; mu=*; pmu=*; wt=*; 249 | test_my_call_user_func_array_safe==>is_callable: ct= 1; mu=*; pmu=*; wt=*; 250 | 251 | Part 5b: Profile call_user_func_array and my_call_user_func_array_safe 252 | hello: my_user_func_array_safetest 253 | Part 5b output: 254 | call_user_func_array==>foo_array : ct= 1; mu=*; pmu=*; wt=*; 255 | foo_array==>bar : ct= 2; mu=*; pmu=*; wt=*; 256 | foo_array==>strlen : ct= 1; mu=*; pmu=*; wt=*; 257 | main() : ct= 1; mu=*; pmu=*; wt=*; 258 | main()==>test_my_call_user_func_array_safe: ct= 1; mu=*; pmu=*; wt=*; 259 | main()==>xhprof_disable : ct= 1; mu=*; pmu=*; wt=*; 260 | my_call_user_func_array_safe==>call_user_func_array: ct= 1; mu=*; pmu=*; wt=*; 261 | my_call_user_func_array_safe==>is_callable: ct= 1; mu=*; pmu=*; wt=*; 262 | test_my_call_user_func_array_safe==>my_call_user_func_array_safe: ct= 1; mu=*; pmu=*; wt=*; 263 | 264 | Part 5c: Only ignore call_user_func_array 265 | hello: my_user_func_array_safetest 266 | Part 5c output: 267 | call_user_func_array==>foo_array : ct= 1; mu=*; pmu=*; wt=*; 268 | foo_array==>bar : ct= 2; mu=*; pmu=*; wt=*; 269 | foo_array==>strlen : ct= 1; mu=*; pmu=*; wt=*; 270 | main() : ct= 1; mu=*; pmu=*; wt=*; 271 | main()==>test_my_call_user_func_array_safe: ct= 1; mu=*; pmu=*; wt=*; 272 | main()==>xhprof_disable : ct= 1; mu=*; pmu=*; wt=*; 273 | test_my_call_user_func_array_safe==>call_user_func_array: ct= 1; mu=*; pmu=*; wt=*; 274 | test_my_call_user_func_array_safe==>is_callable: ct= 1; mu=*; pmu=*; wt=*; 275 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The bulk of this work is provided under, and subject to the Apache license, included 2 | below. 3 | 4 | 5 | This software uses the JQuery javascript library, which is provided under the 6 | MIT or GPL licenses. You may obtain the terms of these licenses from 7 | MIT: http://www.opensource.org/licenses/mit-license.php 8 | GPL: http://www.opensource.org/licenses/gpl-license.php 9 | 10 | You may obtain JQuery directly: http://jquery.com/ 11 | 12 | 13 | This software uses the JQuery Table Sorter, which is provided under the MIT or GPL 14 | licenses, you may obtain the terms of these licenses from: 15 | MIT: http://www.opensource.org/licenses/mit-license.php 16 | GPL: http://www.opensource.org/licenses/gpl-license.php 17 | 18 | You may obtain Table Sorter directly: http://tablesorter.com/docs/ 19 | 20 | 21 | This software uses the HighCharts graphing library which is provided under 22 | a commercial license. A license has been purchased for use within the GUI portion 23 | of XHProf. 24 | 25 | You may verify this license here: http://www.highslide.com/legal/note/xhprof.htm 26 | You may obtain Highcharts directly: http://highcharts.com/ 27 | 28 | 29 | 30 | Apache License 31 | Version 2.0, January 2004 32 | http://www.apache.org/licenses/ 33 | 34 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 35 | 36 | 1. Definitions. 37 | 38 | "License" shall mean the terms and conditions for use, reproduction, 39 | and distribution as defined by Sections 1 through 9 of this document. 40 | 41 | "Licensor" shall mean the copyright owner or entity authorized by 42 | the copyright owner that is granting the License. 43 | 44 | "Legal Entity" shall mean the union of the acting entity and all 45 | other entities that control, are controlled by, or are under common 46 | control with that entity. For the purposes of this definition, 47 | "control" means (i) the power, direct or indirect, to cause the 48 | direction or management of such entity, whether by contract or 49 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 50 | outstanding shares, or (iii) beneficial ownership of such entity. 51 | 52 | "You" (or "Your") shall mean an individual or Legal Entity 53 | exercising permissions granted by this License. 54 | 55 | "Source" form shall mean the preferred form for making modifications, 56 | including but not limited to software source code, documentation 57 | source, and configuration files. 58 | 59 | "Object" form shall mean any form resulting from mechanical 60 | transformation or translation of a Source form, including but 61 | not limited to compiled object code, generated documentation, 62 | and conversions to other media types. 63 | 64 | "Work" shall mean the work of authorship, whether in Source or 65 | Object form, made available under the License, as indicated by a 66 | copyright notice that is included in or attached to the work 67 | (an example is provided in the Appendix below). 68 | 69 | "Derivative Works" shall mean any work, whether in Source or Object 70 | form, that is based on (or derived from) the Work and for which the 71 | editorial revisions, annotations, elaborations, or other modifications 72 | represent, as a whole, an original work of authorship. For the purposes 73 | of this License, Derivative Works shall not include works that remain 74 | separable from, or merely link (or bind by name) to the interfaces of, 75 | the Work and Derivative Works thereof. 76 | 77 | "Contribution" shall mean any work of authorship, including 78 | the original version of the Work and any modifications or additions 79 | to that Work or Derivative Works thereof, that is intentionally 80 | submitted to Licensor for inclusion in the Work by the copyright owner 81 | or by an individual or Legal Entity authorized to submit on behalf of 82 | the copyright owner. For the purposes of this definition, "submitted" 83 | means any form of electronic, verbal, or written communication sent 84 | to the Licensor or its representatives, including but not limited to 85 | communication on electronic mailing lists, source code control systems, 86 | and issue tracking systems that are managed by, or on behalf of, the 87 | Licensor for the purpose of discussing and improving the Work, but 88 | excluding communication that is conspicuously marked or otherwise 89 | designated in writing by the copyright owner as "Not a Contribution." 90 | 91 | "Contributor" shall mean Licensor and any individual or Legal Entity 92 | on behalf of whom a Contribution has been received by Licensor and 93 | subsequently incorporated within the Work. 94 | 95 | 2. Grant of Copyright License. Subject to the terms and conditions of 96 | this License, each Contributor hereby grants to You a perpetual, 97 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 98 | copyright license to reproduce, prepare Derivative Works of, 99 | publicly display, publicly perform, sublicense, and distribute the 100 | Work and such Derivative Works in Source or Object form. 101 | 102 | 3. Grant of Patent License. Subject to the terms and conditions of 103 | this License, each Contributor hereby grants to You a perpetual, 104 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 105 | (except as stated in this section) patent license to make, have made, 106 | use, offer to sell, sell, import, and otherwise transfer the Work, 107 | where such license applies only to those patent claims licensable 108 | by such Contributor that are necessarily infringed by their 109 | Contribution(s) alone or by combination of their Contribution(s) 110 | with the Work to which such Contribution(s) was submitted. If You 111 | institute patent litigation against any entity (including a 112 | cross-claim or counterclaim in a lawsuit) alleging that the Work 113 | or a Contribution incorporated within the Work constitutes direct 114 | or contributory patent infringement, then any patent licenses 115 | granted to You under this License for that Work shall terminate 116 | as of the date such litigation is filed. 117 | 118 | 4. Redistribution. You may reproduce and distribute copies of the 119 | Work or Derivative Works thereof in any medium, with or without 120 | modifications, and in Source or Object form, provided that You 121 | meet the following conditions: 122 | 123 | (a) You must give any other recipients of the Work or 124 | Derivative Works a copy of this License; and 125 | 126 | (b) You must cause any modified files to carry prominent notices 127 | stating that You changed the files; and 128 | 129 | (c) You must retain, in the Source form of any Derivative Works 130 | that You distribute, all copyright, patent, trademark, and 131 | attribution notices from the Source form of the Work, 132 | excluding those notices that do not pertain to any part of 133 | the Derivative Works; and 134 | 135 | (d) If the Work includes a "NOTICE" text file as part of its 136 | distribution, then any Derivative Works that You distribute must 137 | include a readable copy of the attribution notices contained 138 | within such NOTICE file, excluding those notices that do not 139 | pertain to any part of the Derivative Works, in at least one 140 | of the following places: within a NOTICE text file distributed 141 | as part of the Derivative Works; within the Source form or 142 | documentation, if provided along with the Derivative Works; or, 143 | within a display generated by the Derivative Works, if and 144 | wherever such third-party notices normally appear. The contents 145 | of the NOTICE file are for informational purposes only and 146 | do not modify the License. You may add Your own attribution 147 | notices within Derivative Works that You distribute, alongside 148 | or as an addendum to the NOTICE text from the Work, provided 149 | that such additional attribution notices cannot be construed 150 | as modifying the License. 151 | 152 | You may add Your own copyright statement to Your modifications and 153 | may provide additional or different license terms and conditions 154 | for use, reproduction, or distribution of Your modifications, or 155 | for any such Derivative Works as a whole, provided Your use, 156 | reproduction, and distribution of the Work otherwise complies with 157 | the conditions stated in this License. 158 | 159 | 5. Submission of Contributions. Unless You explicitly state otherwise, 160 | any Contribution intentionally submitted for inclusion in the Work 161 | by You to the Licensor shall be under the terms and conditions of 162 | this License, without any additional terms or conditions. 163 | Notwithstanding the above, nothing herein shall supersede or modify 164 | the terms of any separate license agreement you may have executed 165 | with Licensor regarding such Contributions. 166 | 167 | 6. Trademarks. This License does not grant permission to use the trade 168 | names, trademarks, service marks, or product names of the Licensor, 169 | except as required for reasonable and customary use in describing the 170 | origin of the Work and reproducing the content of the NOTICE file. 171 | 172 | 7. Disclaimer of Warranty. Unless required by applicable law or 173 | agreed to in writing, Licensor provides the Work (and each 174 | Contributor provides its Contributions) on an "AS IS" BASIS, 175 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 176 | implied, including, without limitation, any warranties or conditions 177 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 178 | PARTICULAR PURPOSE. You are solely responsible for determining the 179 | appropriateness of using or redistributing the Work and assume any 180 | risks associated with Your exercise of permissions under this License. 181 | 182 | 8. Limitation of Liability. In no event and under no legal theory, 183 | whether in tort (including negligence), contract, or otherwise, 184 | unless required by applicable law (such as deliberate and grossly 185 | negligent acts) or agreed to in writing, shall any Contributor be 186 | liable to You for damages, including any direct, indirect, special, 187 | incidental, or consequential damages of any character arising as a 188 | result of this License or out of the use or inability to use the 189 | Work (including but not limited to damages for loss of goodwill, 190 | work stoppage, computer failure or malfunction, or any and all 191 | other commercial damages or losses), even if such Contributor 192 | has been advised of the possibility of such damages. 193 | 194 | 9. Accepting Warranty or Additional Liability. While redistributing 195 | the Work or Derivative Works thereof, You may choose to offer, 196 | and charge a fee for, acceptance of support, warranty, indemnity, 197 | or other liability obligations and/or rights consistent with this 198 | License. However, in accepting such obligations, You may act only 199 | on Your own behalf and on Your sole responsibility, not on behalf 200 | of any other Contributor, and only if You agree to indemnify, 201 | defend, and hold each Contributor harmless for any liability 202 | incurred by, or claims asserted against, such Contributor by reason 203 | of your accepting any such warranty or additional liability. 204 | 205 | END OF TERMS AND CONDITIONS 206 | -------------------------------------------------------------------------------- /xhprof_html/third-party/jquery/tablesorter.min.js: -------------------------------------------------------------------------------- 1 | 2 | (function($){$.extend({tablesorter:new 3 | function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",cssChildRow:"expand-child",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,sortLocaleCompare:true,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'/\.|\,/g',onRenderHeader:null,selectorHeaders:'thead th',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}if(table.tBodies.length==0)return;var rows=table.tBodies[0].rows;if(rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function checkHeaderOptionsSortingLocked(table,i){if((table.config.headers[i])&&(table.config.headers[i].lockedOrder))return table.config.headers[i].lockedOrder;return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;i b["+i+"]) ? 1 : 0));";};function makeSortTextDesc(i){return"((b["+i+"] < a["+i+"]) ? -1 : ((b["+i+"] > a["+i+"]) ? 1 : 0));";};function makeSortNumeric(i){return"a["+i+"]-b["+i+"];";};function makeSortNumericDesc(i){return"b["+i+"]-a["+i+"];";};function sortText(a,b){if(table.config.sortLocaleCompare)return a.localeCompare(b);return((ab)?1:0));};function sortTextDesc(a,b){if(table.config.sortLocaleCompare)return b.localeCompare(a);return((ba)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$.data(this,"tablesorter",config);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){$this.trigger("sortStart");var $cell=$(this);var i=this.column;this.order=this.count++%2;if(this.lockedOrder)this.order=this.lockedOrder;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;idb(); 81 | } 82 | 83 | protected function db() 84 | { 85 | global $_xhprof; 86 | $connectionString = $_xhprof['dbtype'] . ':host=' . $_xhprof['dbhost'] . ';dbname=' . $_xhprof['dbname']; 87 | $db = new PDO($connectionString, $_xhprof['dbuser'], $_xhprof['dbpass']); 88 | if ($db === FALSE) 89 | { 90 | xhprof_error("Could not connect to db"); 91 | $run_desc = "could not connect to db"; 92 | throw new Exception("Unable to connect to database"); 93 | return false; 94 | } 95 | $this->db = $db; 96 | $this->db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); 97 | } 98 | /** 99 | * When setting the `id` column, consider the length of the prefix you're specifying in $this->prefix 100 | * 101 | * 102 | CREATE TABLE `details` ( 103 | `id` char(17) NOT NULL, 104 | `url` varchar(255) default NULL, 105 | `c_url` varchar(255) default NULL, 106 | `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, 107 | `server name` varchar(64) default NULL, 108 | `perfdata` MEDIUMBLOB, 109 | `type` tinyint(4) default NULL, 110 | `cookie` BLOB, 111 | `post` BLOB, 112 | `get` BLOB, 113 | `pmu` int(11) default NULL, 114 | `wt` int(11) default NULL, 115 | `cpu` int(11) default NULL, 116 | `server_id` char(3) NOT NULL default 't11', 117 | `aggregateCalls_include` varchar(255) DEFAULT NULL, 118 | PRIMARY KEY (`id`), 119 | KEY `url` (`url`), 120 | KEY `c_url` (`c_url`), 121 | KEY `cpu` (`cpu`), 122 | KEY `wt` (`wt`), 123 | KEY `pmu` (`pmu`), 124 | KEY `timestamp` (`timestamp`) 125 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 126 | 127 | */ 128 | 129 | 130 | private function gen_run_id($type) 131 | { 132 | return uniqid(); 133 | } 134 | 135 | /** 136 | * This function gets runs based on passed parameters, column data as key, value as the value. Values 137 | * are escaped automatically. You may also pass limit, order by, group by, or "where" to add those values, 138 | * all of which are used as is, no escaping. 139 | * 140 | * @param array $stats Criteria by which to select columns 141 | * @return resource 142 | */ 143 | public function getRuns($stats) 144 | { 145 | if (isset($stats['select'])) 146 | { 147 | $query = "SELECT {$stats['select']} FROM `details` "; 148 | }else 149 | { 150 | $query = "SELECT * FROM `details` "; 151 | } 152 | 153 | $skippers = array("limit", "order by", "group by", "where", "select"); 154 | $hasWhere = false; 155 | $sqlParams = array(); 156 | 157 | foreach($stats AS $column => $value) 158 | { 159 | 160 | if (in_array($column, $skippers)) 161 | { 162 | continue; 163 | } 164 | if ($hasWhere === false) 165 | { 166 | $query .= " WHERE "; 167 | $hasWhere = true; 168 | }elseif($hasWhere === true) 169 | { 170 | $query .= "AND "; 171 | } 172 | if (strlen($value) == 0) 173 | { 174 | $query .= $column; 175 | } 176 | $sqlParams[] = $value; 177 | $query .= " `$column` = ? "; 178 | } 179 | 180 | if (isset($stats['where'])) 181 | { 182 | if ($hasWhere === false) 183 | { 184 | $query .= " WHERE "; 185 | $hasWhere = true; 186 | }else 187 | { 188 | $query .= " AND "; 189 | } 190 | $query .= $stats['where']; 191 | } 192 | 193 | if (isset($stats['group by'])) 194 | { 195 | $query .= " GROUP BY `{$stats['group by']}` "; 196 | } 197 | 198 | if (isset($stats['order by'])) 199 | { 200 | $query .= " ORDER BY `{$stats['order by']}` DESC"; 201 | } 202 | 203 | if (isset($stats['limit'])) 204 | { 205 | $query .= " LIMIT {$stats['limit']} "; 206 | } 207 | 208 | $stmt = $this->db->prepare($query); 209 | $rs = $stmt->execute($sqlParams); 210 | return $stmt; 211 | } 212 | 213 | /** 214 | * Obtains the pages that have been the hardest hit over the past N days, utalizing the getRuns() method. 215 | * 216 | * @param array $criteria An associative array containing, at minimum, type, days, and limit 217 | * @return resource The result set reprsenting the results of the query 218 | */ 219 | public function getHardHit($criteria) 220 | { 221 | //call thing to get runs 222 | $criteria['select'] = "distinct(`{$criteria['type']}`), count(`{$criteria['type']}`) AS `count` , sum(`wt`) as total_wall, avg(`wt`) as avg_wall"; 223 | unset($criteria['type']); 224 | $criteria['where'] = "DATE_SUB(CURDATE(), INTERVAL {$criteria['days']} DAY) <= `timestamp`"; 225 | unset($criteria['days']); 226 | $criteria['group by'] = "url"; 227 | $criteria['order by'] = "count"; 228 | $resultSet = $this->getRuns($criteria); 229 | 230 | return $resultSet; 231 | } 232 | 233 | public function getDistinct($data) 234 | { 235 | $column = preg_replace('/[^a-zA-Z0-9-_]/', '', $data['column']); 236 | $query = $this->db->prepare("SELECT DISTINCT({$column}) FROM `details`"); 237 | $rs = $query->execute(array($data['column'])); 238 | return $query; 239 | } 240 | 241 | public static function getNextAssoc($resultSet) 242 | { 243 | return $resultSet->fetch(); 244 | } 245 | 246 | /** 247 | * Retreives a run from the database, 248 | * 249 | * @param string $run_id unique identifier for the run being requested 250 | * @param mixed $type 251 | * @param mixed $run_desc 252 | * @return mixed 253 | */ 254 | public function get_run($run_id, $type, &$run_desc) 255 | { 256 | $run_id = $this->db->quote($run_id); 257 | $query = "SELECT * FROM `details` WHERE `id` = $run_id"; 258 | $resultSet = $this->db->query($query); 259 | $data = $resultSet->fetch(); 260 | 261 | //The Performance data is compressed lightly to avoid max row length 262 | $contents = unserialize(gzuncompress($data['perfdata'])); 263 | 264 | //This data isnt' needed for display purposes, there's no point in keeping it in this array 265 | unset($data['perfdata']); 266 | 267 | 268 | // The same function is called twice when diff'ing runs. In this case we'll populate the global scope with an array 269 | if (is_null($this->run_details)) 270 | { 271 | $this->run_details = $data; 272 | }else 273 | { 274 | $this->run_details[0] = $this->run_details; 275 | $this->run_details[1] = $data; 276 | } 277 | 278 | $run_desc = "XHProf Run (Namespace=$type)"; 279 | $this->getRunComparativeData($data['url'], $data['c_url']); 280 | 281 | return array($contents, $data); 282 | } 283 | 284 | /** 285 | * Get stats (pmu, ct, wt) on a url or c_url 286 | * 287 | * @param array $data An associative array containing the limit you'd like to set for the queyr, as well as either c_url or url for the desired element. 288 | * @return resource result set from the database query 289 | */ 290 | public function getUrlStats($data) 291 | { 292 | $data['select'] = '`id`, UNIX_TIMESTAMP(`timestamp`) as `timestamp`, `pmu`, `wt`, `cpu`'; 293 | $rs = $this->getRuns($data); 294 | return $rs; 295 | } 296 | 297 | /** 298 | * Get comparative information for a given URL and c_url, this information will be used to display stats like how many calls a URL has, 299 | * average, min, max execution time, etc. This information is pushed into the global namespace, which is horribly hacky. 300 | * 301 | * @param string $url 302 | * @param string $c_url 303 | * @return array 304 | */ 305 | public function getRunComparativeData($url, $c_url) 306 | { 307 | //Runs same URL 308 | // count, avg/min/max for wt, cpu, pmu 309 | $query = "SELECT count(`id`), avg(`wt`), min(`wt`), max(`wt`), avg(`cpu`), min(`cpu`), max(`cpu`), avg(`pmu`), min(`pmu`), max(`pmu`) FROM `details` WHERE `url` = ?"; 310 | $stmt = $this->db->prepare($query); 311 | $rs = $stmt->execute(array($url)); 312 | $row = $stmt->fetch(); 313 | $row['url'] = $url; 314 | 315 | $row['95(`wt`)'] = $this->calculatePercentile(array('count' => $row['count(`id`)'], 'column' => 'wt', 'type' => 'url', 'url' => $url)); 316 | $row['95(`cpu`)'] = $this->calculatePercentile(array('count' => $row['count(`id`)'], 'column' => 'cpu', 'type' => 'url', 'url' => $url)); 317 | $row['95(`pmu`)'] = $this->calculatePercentile(array('count' => $row['count(`id`)'], 'column' => 'pmu', 'type' => 'url', 'url' => $url)); 318 | 319 | global $comparative; 320 | $comparative['url'] = $row; 321 | unset($row); 322 | 323 | //Runs same c_url 324 | // count, avg/min/max for wt, cpu, pmu 325 | $query = "SELECT count(`id`), avg(`wt`), min(`wt`), max(`wt`), avg(`cpu`), min(`cpu`), max(`cpu`), avg(`pmu`), min(`pmu`), max(`pmu`) FROM `details` WHERE `c_url` = ?"; 326 | $stmt = $this->db->prepare($query); 327 | $rs = $stmt->execute(array($c_url)); 328 | $row = $stmt->fetch(); 329 | $row['url'] = $c_url; 330 | $row['95(`wt`)'] = $this->calculatePercentile(array('count' => $row['count(`id`)'], 'column' => 'wt', 'type' => 'c_url', 'url' => $c_url)); 331 | $row['95(`cpu`)'] = $this->calculatePercentile(array('count' => $row['count(`id`)'], 'column' => 'cpu', 'type' => 'c_url', 'url' => $c_url)); 332 | $row['95(`pmu`)'] = $this->calculatePercentile(array('count' => $row['count(`id`)'], 'column' => 'pmu', 'type' => 'c_url', 'url' => $c_url)); 333 | 334 | $comparative['c_url'] = $row; 335 | unset($row); 336 | return $comparative; 337 | } 338 | 339 | protected function calculatePercentile($details) 340 | { 341 | $limit = (int) ($details['count'] / 20); 342 | $query = "SELECT ? as `value` FROM `details` WHERE ? = ? ORDER BY ? DESC LIMIT $limit, 1"; 343 | $stmt = $this->db->prepare($query); 344 | $rs = $stmt->execute(array($details['column'], $details['type'], $details['url'], $details['column'])); 345 | $row = $stmt->fetch(); 346 | return $row['value']; 347 | } 348 | 349 | /** 350 | * Save the run in the database. 351 | * 352 | * @param string $xhprof_data 353 | * @param mixed $type 354 | * @param string $run_id 355 | * @param mixed $xhprof_details 356 | * @return string 357 | */ 358 | public function save_run($xhprof_data, $type, $run_id = null, $xhprof_details = null) 359 | { 360 | $sql = array(); 361 | if ($run_id === null) { 362 | $run_id = $this->gen_run_id($type); 363 | } 364 | 365 | /* 366 | Session data is ommitted purposefully, mostly because it's not likely that the data 367 | that resides in $_SESSION at this point is the same as the data that the application 368 | started off with (for most apps, it's likely that session data is manipulated on most 369 | pageloads). 370 | 371 | The goal of storing get, post and cookie is to help explain why an application chose 372 | a particular code execution path, pehaps it was a poorly filled out form, or a cookie that 373 | overwrote some default parameters. So having them helps. Most applications don't push data 374 | back into those super globals, so we're safe(ish) storing them now. 375 | 376 | We can't just clone the session data in header.php to be sneaky either, starting the session 377 | is an application decision, and we don't want to go starting sessions where none are needed 378 | (not good performance wise). We could be extra sneaky and do something like: 379 | if(isset($_COOKIE['phpsessid'])) 380 | { 381 | session_start(); 382 | $_xhprof['session_data'] = $_SESSION; 383 | } 384 | but starting session support really feels like an application level decision, not one that 385 | a supposedly unobtrusive profiler makes for you. 386 | 387 | */ 388 | 389 | $sql['get'] = $this->db->quote(serialize($_GET)); 390 | $sql['cookie'] = $this->db->quote(serialize($_COOKIE)); 391 | 392 | global $_xhprof; 393 | //This code has not been tested 394 | if (isset($_xhprof['savepost']) && $_xhprof['savepost']) 395 | { 396 | $sql['post'] = $this->db->quote(serialize($_POST)); 397 | }else 398 | { 399 | $sql['post'] = $this->db->quote(serialize(array("Skipped" => "Post data omitted by rule"))); 400 | } 401 | 402 | 403 | $sql['pmu'] = isset($xhprof_data['main()']['pmu']) ? $xhprof_data['main()']['pmu'] : ''; 404 | $sql['wt'] = isset($xhprof_data['main()']['wt']) ? $xhprof_data['main()']['wt'] : ''; 405 | $sql['cpu'] = isset($xhprof_data['main()']['cpu']) ? $xhprof_data['main()']['cpu'] : ''; 406 | 407 | 408 | // The value of 2 seems to be light enugh that we're not killing the server, but still gives us lots of breathing room on 409 | // full production code. 410 | $sql['data'] = $this->db->quote(gzcompress(serialize($xhprof_data), 2)); 411 | 412 | $url = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $_SERVER['PHP_SELF']; 413 | $sname = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : ''; 414 | 415 | $sql['url'] = $this->db->quote($url); 416 | $sql['c_url'] = $this->db->quote(_urlSimilartor($_SERVER['REQUEST_URI'])); 417 | $sql['servername'] = $this->db->quote($sname); 418 | $sql['type'] = (int) (isset($xhprof_details['type']) ? $xhprof_details['type'] : 0); 419 | $sql['timestamp'] = $this->db->quote($_SERVER['REQUEST_TIME']); 420 | $sql['server_id'] = $this->db->quote($_xhprof['servername']); 421 | $sql['aggregateCalls_include'] = getenv('xhprof_aggregateCalls_include') ? $this->db-quote(getenv('xhprof_aggregateCalls_include')) : 'NULL'; 422 | 423 | $query = "INSERT INTO `details` (`id`, `url`, `c_url`, `timestamp`, `server name`, `perfdata`, `type`, `cookie`, `post`, `get`, `pmu`, `wt`, `cpu`, `server_id`, `aggregateCalls_include`) VALUES('$run_id', {$sql['url']}, {$sql['c_url']}, FROM_UNIXTIME({$sql['timestamp']}), {$sql['servername']}, {$sql['data']}, {$sql['type']}, {$sql['cookie']}, {$sql['post']}, {$sql['get']}, {$sql['pmu']}, {$sql['wt']}, {$sql['cpu']}, {$sql['server_id']}, {$sql['aggregateCalls_include']})"; 424 | 425 | $rs = $this->db->query($query); 426 | if ($rs && $rs->rowCount() == 1) 427 | { 428 | return $run_id; 429 | }else 430 | { 431 | if ($_xhprof['display'] === true) 432 | { 433 | echo "Failed to insert: $query
\n"; 434 | var_dump($rs->errorInfo()); 435 | var_dump($rs->errorCode()); 436 | } 437 | return -1; 438 | } 439 | } 440 | 441 | 442 | 443 | } 444 | -------------------------------------------------------------------------------- /xhprof_lib/utils/xhprof_runs_mysql.php: -------------------------------------------------------------------------------- 1 | db(); 81 | } 82 | 83 | protected function db() 84 | { 85 | global $_xhprof; 86 | 87 | 88 | $linkid = mysql_connect($_xhprof['dbhost'], $_xhprof['dbuser'], $_xhprof['dbpass']); 89 | if ($linkid === FALSE) 90 | { 91 | xhprof_error("Could not connect to db"); 92 | $run_desc = "could not connect to db"; 93 | throw new Exception("Unable to connect to database"); 94 | return false; 95 | } 96 | mysql_select_db($_xhprof['dbname'], $linkid); 97 | $this->linkID = $linkid; 98 | } 99 | /** 100 | * When setting the `id` column, consider the length of the prefix you're specifying in $this->prefix 101 | * 102 | * 103 | CREATE TABLE `details` ( 104 | `id` char(17) NOT NULL, 105 | `url` varchar(255) default NULL, 106 | `c_url` varchar(255) default NULL, 107 | `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, 108 | `server name` varchar(64) default NULL, 109 | `perfdata` MEDIUMBLOB, 110 | `type` tinyint(4) default NULL, 111 | `cookie` BLOB, 112 | `post` BLOB, 113 | `get` BLOB, 114 | `pmu` int(11) default NULL, 115 | `wt` int(11) default NULL, 116 | `cpu` int(11) default NULL, 117 | `server_id` char(3) NOT NULL default 't11', 118 | `aggregateCalls_include` varchar(255) DEFAULT NULL, 119 | PRIMARY KEY (`id`), 120 | KEY `url` (`url`), 121 | KEY `c_url` (`c_url`), 122 | KEY `cpu` (`cpu`), 123 | KEY `wt` (`wt`), 124 | KEY `pmu` (`pmu`), 125 | KEY `timestamp` (`timestamp`) 126 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 127 | 128 | */ 129 | 130 | 131 | private function gen_run_id($type) 132 | { 133 | return uniqid(); 134 | } 135 | 136 | /** 137 | * This function gets runs based on passed parameters, column data as key, value as the value. Values 138 | * are escaped automatically. You may also pass limit, order by, group by, or "where" to add those values, 139 | * all of which are used as is, no escaping. 140 | * 141 | * @param array $stats Criteria by which to select columns 142 | * @return resource 143 | */ 144 | public function getRuns($stats) 145 | { 146 | if (isset($stats['select'])) 147 | { 148 | $query = "SELECT {$stats['select']} FROM `details` "; 149 | }else 150 | { 151 | $query = "SELECT * FROM `details` "; 152 | } 153 | 154 | $skippers = array("limit", "order by", "group by", "where", "select"); 155 | $hasWhere = false; 156 | 157 | foreach($stats AS $column => $value) 158 | { 159 | 160 | if (in_array($column, $skippers)) 161 | { 162 | continue; 163 | } 164 | if ($hasWhere === false) 165 | { 166 | $query .= " WHERE "; 167 | $hasWhere = true; 168 | }elseif($hasWhere === true) 169 | { 170 | $query .= "AND "; 171 | } 172 | if (strlen($value) == 0) 173 | { 174 | $query .= $column; 175 | } 176 | $value = mysql_real_escape_string($value); 177 | $query .= " `$column` = '$value' "; 178 | } 179 | 180 | if (isset($stats['where'])) 181 | { 182 | if ($hasWhere === false) 183 | { 184 | $query .= " WHERE "; 185 | $hasWhere = true; 186 | }else 187 | { 188 | $query .= " AND "; 189 | } 190 | $query .= $stats['where']; 191 | } 192 | 193 | if (isset($stats['group by'])) 194 | { 195 | $query .= " GROUP BY `{$stats['group by']}` "; 196 | } 197 | 198 | if (isset($stats['order by'])) 199 | { 200 | $query .= " ORDER BY `{$stats['order by']}` DESC"; 201 | } 202 | 203 | if (isset($stats['limit'])) 204 | { 205 | $query .= " LIMIT {$stats['limit']} "; 206 | } 207 | 208 | $resultSet = mysql_query($query); 209 | return $resultSet; 210 | } 211 | 212 | /** 213 | * Obtains the pages that have been the hardest hit over the past N days, utalizing the getRuns() method. 214 | * 215 | * @param array $criteria An associative array containing, at minimum, type, days, and limit 216 | * @return resource The result set reprsenting the results of the query 217 | */ 218 | public function getHardHit($criteria) 219 | { 220 | //call thing to get runs 221 | $criteria['select'] = "distinct(`{$criteria['type']}`), count(`{$criteria['type']}`) AS `count` , sum(`wt`) as total_wall, avg(`wt`) as avg_wall"; 222 | unset($criteria['type']); 223 | $criteria['where'] = "DATE_SUB(CURDATE(), INTERVAL {$criteria['days']} DAY) <= `timestamp`"; 224 | unset($criteria['days']); 225 | $criteria['group by'] = "url"; 226 | $criteria['order by'] = "count"; 227 | $resultSet = $this->getRuns($criteria); 228 | 229 | return $resultSet; 230 | } 231 | 232 | public function getDistinct($data) 233 | { 234 | $sql['column'] = mysql_real_escape_string($data['column']); 235 | $query = "SELECT DISTINCT(`{$sql['column']}`) FROM `details`"; 236 | $rs = mysql_query($query); 237 | return $rs; 238 | } 239 | 240 | public static function getNextAssoc($resultSet) 241 | { 242 | return mysql_fetch_assoc($resultSet); 243 | } 244 | 245 | /** 246 | * Retreives a run from the database, 247 | * 248 | * @param string $run_id unique identifier for the run being requested 249 | * @param mixed $type 250 | * @param mixed $run_desc 251 | * @return mixed 252 | */ 253 | public function get_run($run_id, $type, &$run_desc) 254 | { 255 | $run_id = mysql_real_escape_string($run_id); 256 | $query = "SELECT * FROM `details` WHERE `id` = '$run_id'"; 257 | $resultSet = mysql_query($query, $this->linkID); 258 | $data = mysql_fetch_assoc($resultSet); 259 | 260 | //The Performance data is compressed lightly to avoid max row length 261 | $contents = unserialize(gzuncompress($data['perfdata'])); 262 | 263 | //This data isnt' needed for display purposes, there's no point in keeping it in this array 264 | unset($data['perfdata']); 265 | 266 | 267 | // The same function is called twice when diff'ing runs. In this case we'll populate the global scope with an array 268 | if (is_null($this->run_details)) 269 | { 270 | $this->run_details = $data; 271 | }else 272 | { 273 | $this->run_details[0] = $this->run_details; 274 | $this->run_details[1] = $data; 275 | } 276 | 277 | $run_desc = "XHProf Run (Namespace=$type)"; 278 | $this->getRunComparativeData($data['url'], $data['c_url']); 279 | 280 | return array($contents, $data); 281 | } 282 | 283 | /** 284 | * Get stats (pmu, ct, wt) on a url or c_url 285 | * 286 | * @param array $data An associative array containing the limit you'd like to set for the queyr, as well as either c_url or url for the desired element. 287 | * @return resource result set from the database query 288 | */ 289 | public function getUrlStats($data) 290 | { 291 | $data['select'] = '`id`, UNIX_TIMESTAMP(`timestamp`) as `timestamp`, `pmu`, `wt`, `cpu`'; 292 | $rs = $this->getRuns($data); 293 | return $rs; 294 | } 295 | 296 | /** 297 | * Get comparative information for a given URL and c_url, this information will be used to display stats like how many calls a URL has, 298 | * average, min, max execution time, etc. This information is pushed into the global namespace, which is horribly hacky. 299 | * 300 | * @param string $url 301 | * @param string $c_url 302 | * @return array 303 | */ 304 | public function getRunComparativeData($url, $c_url) 305 | { 306 | $url = mysql_real_escape_string($url); 307 | $c_url = mysql_real_escape_string($c_url); 308 | //Runs same URL 309 | // count, avg/min/max for wt, cpu, pmu 310 | $query = "SELECT count(`id`), avg(`wt`), min(`wt`), max(`wt`), avg(`cpu`), min(`cpu`), max(`cpu`), avg(`pmu`), min(`pmu`), max(`pmu`) FROM `details` WHERE `url` = '$url'"; 311 | $rs = mysql_query($query, $this->linkID); 312 | $row = mysql_fetch_assoc($rs); 313 | $row['url'] = $url; 314 | 315 | $row['95(`wt`)'] = $this->calculatePercentile(array('count' => $row['count(`id`)'], 'column' => 'wt', 'type' => 'url', 'url' => $url)); 316 | $row['95(`cpu`)'] = $this->calculatePercentile(array('count' => $row['count(`id`)'], 'column' => 'cpu', 'type' => 'url', 'url' => $url)); 317 | $row['95(`pmu`)'] = $this->calculatePercentile(array('count' => $row['count(`id`)'], 'column' => 'pmu', 'type' => 'url', 'url' => $url)); 318 | 319 | global $comparative; 320 | $comparative['url'] = $row; 321 | unset($row); 322 | 323 | //Runs same c_url 324 | // count, avg/min/max for wt, cpu, pmu 325 | $query = "SELECT count(`id`), avg(`wt`), min(`wt`), max(`wt`), avg(`cpu`), min(`cpu`), max(`cpu`), avg(`pmu`), min(`pmu`), max(`pmu`) FROM `details` WHERE `c_url` = '$c_url'"; 326 | $rs = mysql_query($query, $this->linkID); 327 | $row = mysql_fetch_assoc($rs); 328 | $row['url'] = $c_url; 329 | $row['95(`wt`)'] = $this->calculatePercentile(array('count' => $row['count(`id`)'], 'column' => 'wt', 'type' => 'c_url', 'url' => $c_url)); 330 | $row['95(`cpu`)'] = $this->calculatePercentile(array('count' => $row['count(`id`)'], 'column' => 'cpu', 'type' => 'c_url', 'url' => $c_url)); 331 | $row['95(`pmu`)'] = $this->calculatePercentile(array('count' => $row['count(`id`)'], 'column' => 'pmu', 'type' => 'c_url', 'url' => $c_url)); 332 | 333 | $comparative['c_url'] = $row; 334 | unset($row); 335 | return $comparative; 336 | } 337 | 338 | protected function calculatePercentile($details) 339 | { 340 | $limit = (int) ($details['count'] / 20); 341 | $query = "SELECT `{$details['column']}` as `value` FROM `details` WHERE `{$details['type']}` = '{$details['url']}' ORDER BY `{$details['column']}` DESC LIMIT $limit, 1"; 342 | $rs = mysql_query($query, $this->linkID); 343 | $row = mysql_fetch_assoc($rs); 344 | return $row['value']; 345 | } 346 | 347 | /** 348 | * Save the run in the database. 349 | * 350 | * @param string $xhprof_data 351 | * @param mixed $type 352 | * @param string $run_id 353 | * @param mixed $xhprof_details 354 | * @return string 355 | */ 356 | public function save_run($xhprof_data, $type, $run_id = null, $xhprof_details = null) 357 | { 358 | global $_xhprof; 359 | 360 | $sql = array(); 361 | if ($run_id === null) { 362 | $run_id = $this->gen_run_id($type); 363 | } 364 | 365 | /* 366 | Session data is ommitted purposefully, mostly because it's not likely that the data 367 | that resides in $_SESSION at this point is the same as the data that the application 368 | started off with (for most apps, it's likely that session data is manipulated on most 369 | pageloads). 370 | 371 | The goal of storing get, post and cookie is to help explain why an application chose 372 | a particular code execution path, pehaps it was a poorly filled out form, or a cookie that 373 | overwrote some default parameters. So having them helps. Most applications don't push data 374 | back into those super globals, so we're safe(ish) storing them now. 375 | 376 | We can't just clone the session data in header.php to be sneaky either, starting the session 377 | is an application decision, and we don't want to go starting sessions where none are needed 378 | (not good performance wise). We could be extra sneaky and do something like: 379 | if(isset($_COOKIE['phpsessid'])) 380 | { 381 | session_start(); 382 | $_xhprof['session_data'] = $_SESSION; 383 | } 384 | but starting session support really feels like an application level decision, not one that 385 | a supposedly unobtrusive profiler makes for you. 386 | 387 | */ 388 | 389 | $sql['get'] = mysql_real_escape_string(serialize($_GET), $this->linkID); 390 | $sql['cookie'] = mysql_real_escape_string(serialize($_COOKIE), $this->linkID); 391 | 392 | //This code has not been tested 393 | if ($_xhprof['savepost']) 394 | { 395 | $sql['post'] = mysql_real_escape_string(serialize($_POST), $this->linkID); 396 | }else 397 | { 398 | $sql['post'] = mysql_real_escape_string(serialize(array("Skipped" => "Post data omitted by rule")), $this->linkID); 399 | } 400 | 401 | 402 | $sql['pmu'] = isset($xhprof_data['main()']['pmu']) ? $xhprof_data['main()']['pmu'] : ''; 403 | $sql['wt'] = isset($xhprof_data['main()']['wt']) ? $xhprof_data['main()']['wt'] : ''; 404 | $sql['cpu'] = isset($xhprof_data['main()']['cpu']) ? $xhprof_data['main()']['cpu'] : ''; 405 | 406 | 407 | // The value of 2 seems to be light enugh that we're not killing the server, but still gives us lots of breathing room on 408 | // full production code. 409 | $sql['data'] = mysql_real_escape_string(gzcompress(serialize($xhprof_data), 2)); 410 | 411 | $url = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $_SERVER['PHP_SELF']; 412 | $sname = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : ''; 413 | 414 | $sql['url'] = mysql_real_escape_string($url); 415 | $sql['c_url'] = mysql_real_escape_string(_urlSimilartor($_SERVER['REQUEST_URI'])); 416 | $sql['servername'] = mysql_real_escape_string($sname); 417 | $sql['type'] = (int) (isset($xhprof_details['type']) ? $xhprof_details['type'] : 0); 418 | $sql['timestamp'] = mysql_real_escape_string($_SERVER['REQUEST_TIME']); 419 | $sql['server_id'] = mysql_real_escape_string($_xhprof['servername']); 420 | $sql['aggregateCalls_include'] = getenv('xhprof_aggregateCalls_include') ? getenv('xhprof_aggregateCalls_include') : ''; 421 | 422 | $query = "INSERT INTO `details` (`id`, `url`, `c_url`, `timestamp`, `server name`, `perfdata`, `type`, `cookie`, `post`, `get`, `pmu`, `wt`, `cpu`, `server_id`, `aggregateCalls_include`) VALUES('$run_id', '{$sql['url']}', '{$sql['c_url']}', FROM_UNIXTIME('{$sql['timestamp']}'), '{$sql['servername']}', '{$sql['data']}', '{$sql['type']}', '{$sql['cookie']}', '{$sql['post']}', '{$sql['get']}', '{$sql['pmu']}', '{$sql['wt']}', '{$sql['cpu']}', '{$sql['server_id']}', '{$sql['aggregateCalls_include']}')"; 423 | 424 | mysql_query($query, $this->linkID); 425 | if (mysql_affected_rows($this->linkID) == 1) 426 | { 427 | return $run_id; 428 | }else 429 | { 430 | global $_xhprof; 431 | if ($_xhprof['display'] === true) 432 | { 433 | echo "Failed to insert: $query
\n"; 434 | var_dump(mysql_error($this->linkID)); 435 | var_dump(mysql_errno($this->linkID)); 436 | } 437 | return -1; 438 | } 439 | } 440 | 441 | 442 | 443 | } 444 | --------------------------------------------------------------------------------