pax_global_header00006660000000000000000000000064135632716650014530gustar00rootroot0000000000000052 comment=97c780dc2cc905fded6d99bbe22eaf2c400a1aa0 php-xhprof-extension-5.0.2/000077500000000000000000000000001356327166500156415ustar00rootroot00000000000000php-xhprof-extension-5.0.2/.appveyor.yml000066400000000000000000000042671356327166500203200ustar00rootroot00000000000000image: Visual Studio 2015 version: '{branch}.{build}' cache: - c:\build-cache -> .appveyor.yml, .appveyor/*.cmd environment: PHP_BUILD_CACHE_BASE_DIR: c:\build-cache PHP_BUILD_OBJ_DIR: c:\obj PHP_BUILD_CACHE_SDK_DIR: c:\build-cache\sdk PHP_BUILD_SDK_BRANCH: php-sdk-2.1.1 SDK_REMOTE: https://github.com/OSTC/php-sdk-binary-tools.git SDK_BRANCH: php-sdk-2.1.1 matrix: - PHP_REL: 7.3 ARCHITECTURE: x64 ZTS_STATE: enable APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 PHP_BUILD_CRT: vc15 - PHP_REL: 7.2 ARCHITECTURE: x64 ZTS_STATE: enable APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 PHP_BUILD_CRT: vc15 - PHP_REL: 7.1 ARCHITECTURE: x64 ZTS_STATE: enable APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 PHP_BUILD_CRT: vc14 - PHP_REL: 7.3 ARCHITECTURE: x64 ZTS_STATE: disable APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 PHP_BUILD_CRT: vc15 - PHP_REL: 7.2 ARCHITECTURE: x64 ZTS_STATE: disable APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 PHP_BUILD_CRT: vc15 - PHP_REL: 7.1 ARCHITECTURE: x64 ZTS_STATE: disable APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 PHP_BUILD_CRT: vc14 - PHP_REL: 7.3 ARCHITECTURE: x86 ZTS_STATE: enable APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 PHP_BUILD_CRT: vc15 - PHP_REL: 7.2 ARCHITECTURE: x86 ZTS_STATE: enable APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 PHP_BUILD_CRT: vc15 - PHP_REL: 7.1 ARCHITECTURE: x86 ZTS_STATE: enable APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 PHP_BUILD_CRT: vc14 - PHP_REL: 7.3 ARCHITECTURE: x86 ZTS_STATE: disable APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 PHP_BUILD_CRT: vc15 - PHP_REL: 7.2 ARCHITECTURE: x86 ZTS_STATE: disable APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 PHP_BUILD_CRT: vc15 - PHP_REL: 7.1 ARCHITECTURE: x86 ZTS_STATE: disable APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 PHP_BUILD_CRT: vc14 install: - .appveyor\install.cmd build_script: - .appveyor\build.cmd php-xhprof-extension-5.0.2/.appveyor/000077500000000000000000000000001356327166500175645ustar00rootroot00000000000000php-xhprof-extension-5.0.2/.appveyor/build.cmd000066400000000000000000000005421356327166500213510ustar00rootroot00000000000000@echo off setlocal enableextensions enabledelayedexpansion set SDK_RUNNER=%PHP_BUILD_CACHE_SDK_DIR%\phpsdk-%PHP_BUILD_CRT%-%ARCHITECTURE%.bat if not exist "!SDK_RUNNER!" ( echo "!SDK_RUNNER!" doesn't exist exit /b 3 ) cmd /c !SDK_RUNNER! -t %APPVEYOR_BUILD_FOLDER%\.appveyor\build_task.cmd if %errorlevel% neq 0 exit /b 3 endlocal exit /b 0 php-xhprof-extension-5.0.2/.appveyor/build_task.cmd000066400000000000000000000076531356327166500224050ustar00rootroot00000000000000@echo off setlocal enableextensions enabledelayedexpansion cd /D %APPVEYOR_BUILD_FOLDER% if %errorlevel% neq 0 exit /b 3 set STABILITY=staging set DEPS_DIR=%PHP_BUILD_CACHE_BASE_DIR%\deps-%PHP_REL%-%PHP_SDK_VC%-%PHP_SDK_ARCH% rem SDK is cached, deps info is cached as well echo Updating dependencies in %DEPS_DIR% cmd /c phpsdk_deps --update --no-backup --branch %PHP_REL% --stability %STABILITY% --deps %DEPS_DIR% if %errorlevel% neq 0 exit /b 3 rem Something went wrong, most likely when concurrent builds were to fetch deps rem updates. It might be, that some locking mechanism is needed. if not exist "%DEPS_DIR%" ( cmd /c phpsdk_deps --update --force --no-backup --branch %PHP_REL% --stability %STABILITY% --deps %DEPS_DIR% ) if %errorlevel% neq 0 exit /b 3 if "%ZTS_STATE%"=="enable" set ZTS_SHORT=ts if "%ZTS_STATE%"=="disable" set ZTS_SHORT=nts if "%ZTS_STATE%"=="enable" set ZTS_IN_FILENAME= if "%ZTS_STATE%"=="disable" set ZTS_IN_FILENAME=-nts if "%PHP_SDK_ARCH%"=="x86" set ARCH_IN_FILENAME= if "%PHP_SDK_ARCH%"=="x64" set ARCH_IN_FILENAME=-x86_64 cd /d C:\projects\php-src cmd /c buildconf.bat --force if %errorlevel% neq 0 exit /b 3 cmd /c configure.bat --disable-all --with-mp=auto --enable-cli --%ZTS_STATE%-zts --with-tideways_xhprof=shared --enable-object-out-dir=%PHP_BUILD_OBJ_DIR% --with-config-file-scan-dir=%APPVEYOR_BUILD_FOLDER%\build\modules.d --with-prefix=%APPVEYOR_BUILD_FOLDER%\build --with-php-build=%DEPS_DIR% if %errorlevel% neq 0 exit /b 3 nmake /NOLOGO if %errorlevel% neq 0 exit /b 3 nmake install if %errorlevel% neq 0 exit /b 3 mkdir c:\tests_tmp set TEST_PHP_EXECUTABLE=%APPVEYOR_BUILD_FOLDER%\build\php.exe set TEST_PHP_JUNIT=c:\tests_tmp\tests-junit.xml if "%OPCACHE%" equ "1" set TEST_PHP_ARGS=!TEST_PHP_ARGS! -d extension=%APPVEYOR_BUILD_FOLDER%\build\ext\php_opcache.so -d opcache.enable=1 -d opcache.enable_cli=1 set TEST_PHP_ARGS=-n -d -foo=1 -d extension=%APPVEYOR_BUILD_FOLDER%\build\ext\php_tideways_xhprof.dll set SKIP_DBGP_TESTS=1 set SKIP_IPV6_TESTS=1 set REPORT_EXIT_STATUS=1 echo !TEST_PHP_EXECUTABLE! !TEST_PHP_ARGS! -v echo !TEST_PHP_EXECUTABLE! -n run-tests.php -q -x --show-diff --show-slow 1000 --set-timeout 120 -g FAIL,XFAIL,BORK,WARN,LEAK,SKIP --temp-source c:\tests_tmp --temp-target c:\tests_tmp %APPVEYOR_BUILD_FOLDER%\tests !TEST_PHP_EXECUTABLE! !TEST_PHP_ARGS! -v !TEST_PHP_EXECUTABLE! -n run-tests.php -q -x --show-diff %APPVEYOR_BUILD_FOLDER%\tests set EXIT_CODE=%errorlevel% powershell -Command "$wc = New-Object 'System.Net.WebClient'; $wc.UploadFile('https://ci.appveyor.com/api/testresults/junit/%APPVEYOR_JOB_ID%', 'c:\tests_tmp\tests-junit.xml')" if %EXIT_CODE% neq 0 exit /b 3 cd /d %APPVEYOR_BUILD_FOLDER% if not exist "%APPVEYOR_BUILD_FOLDER%\build\ext\php_tideways_xhprof.dll" exit /b 3 xcopy %APPVEYOR_BUILD_FOLDER%\LICENSE %APPVEYOR_BUILD_FOLDER%\php_tideways_xhprof-%PHP_REL%-!ZTS_SHORT!-%PHP_BUILD_CRT%-%PHP_SDK_ARCH%\ /y /f xcopy %APPVEYOR_BUILD_FOLDER%\NOTICE %APPVEYOR_BUILD_FOLDER%\php_tideways_xhprof-%PHP_REL%-!ZTS_SHORT!-%PHP_BUILD_CRT%-%PHP_SDK_ARCH%\ /y /f echo F|xcopy %APPVEYOR_BUILD_FOLDER%\build\ext\php_tideways_xhprof.dll %APPVEYOR_BUILD_FOLDER%\php_tideways_xhprof-%PHP_REL%-!ZTS_SHORT!-%PHP_BUILD_CRT%-%PHP_SDK_ARCH%\php_tideways_xhprof-%APPVEYOR_REPO_TAG_NAME%-%PHP_REL%-%PHP_BUILD_CRT%!ZTS_IN_FILENAME!!ARCH_IN_FILENAME!.dll /y /f 7z a php_tideways_xhprof-%APPVEYOR_REPO_TAG_NAME%-%PHP_REL%-%PHP_BUILD_CRT%!ZTS_IN_FILENAME!!ARCH_IN_FILENAME!.zip %APPVEYOR_BUILD_FOLDER%\php_tideways_xhprof-%PHP_REL%-!ZTS_SHORT!-%PHP_BUILD_CRT%-%PHP_SDK_ARCH%\* appveyor PushArtifact php_tideways_xhprof-%APPVEYOR_REPO_TAG_NAME%-%PHP_REL%-%PHP_BUILD_CRT%!ZTS_IN_FILENAME!!ARCH_IN_FILENAME!.zip -FileName php_tideways_xhprof-%APPVEYOR_REPO_TAG_NAME%-%PHP_REL%-%PHP_BUILD_CRT%!ZTS_IN_FILENAME!!ARCH_IN_FILENAME!.zip rem move build\ext\php_tideways_xhprof.dll artifacts\php_tideways_xhprof-%PHP_REL%-!ZTS_SHORT!-%PHP_BUILD_CRT%-%PHP_SDK_ARCH%.dll endlocal php-xhprof-extension-5.0.2/.appveyor/install.cmd000066400000000000000000000046701356327166500217260ustar00rootroot00000000000000@echo off setlocal enableextensions enabledelayedexpansion cinst wget if not exist "%PHP_BUILD_CACHE_BASE_DIR%" ( echo Creating %PHP_BUILD_CACHE_BASE_DIR% mkdir "%PHP_BUILD_CACHE_BASE_DIR%" ) if not exist "%PHP_BUILD_OBJ_DIR%" ( echo Creating %PHP_BUILD_OBJ_DIR% mkdir "%PHP_BUILD_OBJ_DIR%" ) if not exist "%PHP_BUILD_CACHE_SDK_DIR%" ( echo Cloning remote SDK repository rem git clone -q --depth=1 --branch %SDK_BRANCH% %SDK_REMOTE% "%PHP_BUILD_CACHE_SDK_DIR%" 2>&1 git clone --branch %SDK_BRANCH% %SDK_REMOTE% "%PHP_BUILD_CACHE_SDK_DIR%" 2>&1 ) else ( echo Fetching remote SDK repository git --git-dir="%PHP_BUILD_CACHE_SDK_DIR%\.git" --work-tree="%PHP_BUILD_CACHE_SDK_DIR%" fetch --prune origin 2>&1 echo Checkout SDK repository branch git --git-dir="%PHP_BUILD_CACHE_SDK_DIR%\.git" --work-tree="%PHP_BUILD_CACHE_SDK_DIR%" checkout --force %SDK_BRANCH% ) if "%PHP_REL%"=="master" ( echo git clone -q --depth=1 --branch=%PHP_REL% https://github.com/php/php-src C:\projects\php-src git clone -q --depth=1 --branch=%PHP_REL% https://github.com/php/php-src C:\projects\php-src ) else ( echo git clone -q --depth=1 --branch=PHP-%PHP_REL% https://github.com/php/php-src C:\projects\php-src git clone -q --depth=1 --branch=PHP-%PHP_REL% https://github.com/php/php-src C:\projects\php-src ) xcopy %APPVEYOR_BUILD_FOLDER% C:\projects\php-src\ext\tideways_xhprof\ /s /e /y /q xcopy %APPVEYOR_BUILD_FOLDER%\LICENSE %APPVEYOR_BUILD_FOLDER%\artifacts\ /y /q xcopy %APPVEYOR_BUILD_FOLDER%\NOTICE %APPVEYOR_BUILD_FOLDER%\artifacts\ /y /q if "%APPVEYOR%" equ "True" rmdir /s /q C:\cygwin >NUL 2>NUL if %errorlevel% neq 0 exit /b 3 if "%APPVEYOR%" equ "True" rmdir /s /q C:\cygwin64 >NUL 2>NUL if %errorlevel% neq 0 exit /b 3 if "%APPVEYOR%" equ "True" rmdir /s /q C:\mingw >NUL 2>NUL if %errorlevel% neq 0 exit /b 3 if "%APPVEYOR%" equ "True" rmdir /s /q C:\mingw-w64 >NUL 2>NUL if %errorlevel% neq 0 exit /b 3 if "%APPVEYOR_REPO_TAG_NAME%"=="" ( set APPVEYOR_REPO_TAG_NAME=%APPVEYOR_REPO_BRANCH%-%APPVEYOR_REPO_COMMIT:~0,8% for /f "delims=" %%l in (php_tideways_xhprof.h) do ( if not "%%l"=="" ( set line=%%l if "!line:~8,27!"=="PHP_TIDEWAYS_XHPROF_VERSION" ( set APPVEYOR_REPO_TAG_NAME=!line:~37,-1!-%APPVEYOR_REPO_BRANCH%-%APPVEYOR_REPO_COMMIT:~0,8% ) ) ) echo Final repo tag name: !APPVEYOR_REPO_TAG_NAME! appveyor SetVariable -Name APPVEYOR_REPO_TAG_NAME -Value !APPVEYOR_REPO_TAG_NAME! ) endlocal php-xhprof-extension-5.0.2/.appveyor/test.cmd000066400000000000000000000005411356327166500212300ustar00rootroot00000000000000@echo off setlocal enableextensions enabledelayedexpansion set SDK_RUNNER=%PHP_BUILD_CACHE_SDK_DIR%\phpsdk-%PHP_BUILD_CRT%-%ARCHITECTURE%.bat if not exist "!SDK_RUNNER!" ( echo "!SDK_RUNNER!" doesn't exist exit /b 3 ) cmd /c !SDK_RUNNER! -t %APPVEYOR_BUILD_FOLDER%\.appveyor\test_task.cmd if %errorlevel% neq 0 exit /b 3 endlocal exit /b 0 php-xhprof-extension-5.0.2/.appveyor/test_task.cmd000066400000000000000000000014571356327166500222610ustar00rootroot00000000000000@echo off set NO_INTERACTION=1 set REPORT_EXIT_STATUS=1 set SKIP_IO_CAPTURE_TESTS=1 if /i "%APPVEYOR_REPO_BRANCH:~0,7%" equ "XDEBUG_" ( set BRANCH=%APPVEYOR_REPO_BRANCH:~7,3% set STABILITY=stable ) else ( set BRANCH=master set STABILITY=staging ) set BRANCH=%PHP_REL% set DEPS_DIR=%PHP_BUILD_CACHE_BASE_DIR%\deps-%BRANCH%-%PHP_SDK_VC%-%PHP_SDK_ARCH% if not exist "%DEPS_DIR%" ( echo "%DEPS_DIR%" doesn't exist exit /b 3 ) rem prepare for Opcache if "%OPCACHE%" equ "1" set OPCACHE_OPTS=-d opcache.enabled=1 -d opcache.enable_cli=1 mkdir c:\tests_tmp cd "%APPVEYOR_BUILD_FOLDER%" nmake test TESTS="%OPCACHE_OPTS% -q --offline --show-diff --show-slow 1000 --set-timeout 120 -g FAIL,XFAIL,BORK,WARN,LEAK,SKIP --temp-source c:\tests_tmp --temp-target c:\tests_tmp" exit /b %errorlevel% php-xhprof-extension-5.0.2/.buildkite/000077500000000000000000000000001356327166500176735ustar00rootroot00000000000000php-xhprof-extension-5.0.2/.buildkite/build_extension.sh000077500000000000000000000010171356327166500234240ustar00rootroot00000000000000#!/bin/bash set -e PHP_VERSION=$1 EXTENSION="tideways_xhprof" make distclean || true /opt/php/php-${PHP_VERSION}/bin/phpize CFLAGS="-O2" ./configure --with-php-config=/opt/php/php-${PHP_VERSION}/bin/php-config make -j2 cp modules/${EXTENSION}.so modules/${EXTENSION}-${PHP_VERSION}.so buildkite-agent artifact upload modules/${EXTENSION}-${PHP_VERSION}.so REPORT_EXIT_STATUS=1 /opt/php/php-${PHP_VERSION}/bin/php run-tests.php -p /opt/php/php-${PHP_VERSION}/bin/php --show-diff -d extension=`pwd`/.libs/${EXTENSION}.so -q php-xhprof-extension-5.0.2/.buildkite/package_extension.sh000066400000000000000000000036261356327166500237250ustar00rootroot00000000000000#!/bin/bash set -e BASEDIR=`dirname $0` BASEDIR=`dirname $BASEDIR` PACKAGENAME="tideways-xhprof" DESCRIPTION="tideways-xhprof is a modern XHProf fork built for PHP 7." EXTENSION="tideways_xhprof" VERSIONS=( "7.0" "7.1" "7.2" "7.3" "7.4" "7.1-zts" "7.2-zts" "7.3-zts" "7.4-zts" ) PACKAGES=( "deb" "rpm" ) ARCHITECTURE=`uname -m` ARCHITECTURE=${ARCHITECTURE/686/386} buildkite-agent artifact download "modules/*.so" . mkdir packaging/dist -p mkdir packaging/root/usr/lib/${EXTENSION} -p mkdir packaging/root/usr/share/doc/${PACKAGENAME} -p for VERSION in "${VERSIONS[@]}" do if [ -f "/opt/php/php-${VERSION}/bin/php" ]; then EXTVERSION=`/opt/php/php-${VERSION}/bin/php -dextension=modules/${EXTENSION}-${VERSION}.so -r "echo phpversion(\"${EXTENSION}\");"` fi done mkdir packaging/tarball/${EXTENSION}-${EXTVERSION} -p cp modules/*.so packaging/tarball/${EXTENSION}-${EXTVERSION}/ cp modules/*.so packaging/root/usr/lib/${EXTENSION}/ cp ${BASEDIR}/LICENSE packaging/tarball/${EXTENSION}-${EXTVERSION}/LICENSE || true cp ${BASEDIR}/NOTICE packaging/tarball/${EXTENSION}-${EXTVERSION}/NOTICE || true cp ${BASEDIR}/LICENSE packaging/root/usr/share/doc/${PACKAGENAME}/LICENSE || true cp ${BASEDIR}/NOTICE packaging/root/usr/share/doc/${PACKAGENAME}/NOTICE || true pushd . cd packaging/tarball tar czvf ../dist/${PACKAGENAME}-${EXTVERSION}-${ARCHITECTURE}.tar.gz . popd buildkite-agent artifact upload packaging/dist/${PACKAGENAME}-${EXTVERSION}-${ARCHITECTURE}.tar.gz for PKG in "${PACKAGES[@]}" do fpm --maintainer "support@tideways.com" \ --url "https://tideways.com" \ --description "${DESCRIPTION}" \ --vendor "Tideways GmbH" \ -f \ -s dir \ -t ${PKG} \ -C "${BASEDIR}/packaging/root" \ -n "${PACKAGENAME}" \ -a "${ARCHITECTURE}" \ -v "${EXTVERSION}" \ . buildkite-agent artifact upload "${PACKAGENAME}*.${PKG}" done php-xhprof-extension-5.0.2/.buildkite/pipeline.yml000066400000000000000000000035101356327166500222220ustar00rootroot00000000000000env: NO_INTERACTION: 1 steps: - label: ":php: 7.4 amd64" command: ./.buildkite/build_extension.sh 7.4 agents: phpbuild: "no-debug" queue: "build" arch: "x86_64" - label: ":php: 7.3 amd64" command: ./.buildkite/build_extension.sh 7.3 agents: phpbuild: "no-debug" queue: "build" arch: "x86_64" - label: ":php: 7.2 amd64" command: ./.buildkite/build_extension.sh 7.2 agents: phpbuild: "no-debug" queue: "build" arch: "x86_64" - label: ":php: 7.1 amd64" command: ./.buildkite/build_extension.sh 7.1 agents: phpbuild: "no-debug" queue: "build" arch: "x86_64" - label: ":php: 7.0 amd64" command: ./.buildkite/build_extension.sh 7.0 agents: phpbuild: "no-debug" queue: "build" arch: "x86_64" - label: ":php: 7.4-zts amd64" command: ./.buildkite/build_extension.sh 7.4-zts agents: phpbuild: "no-debug" queue: "build" arch: "x86_64" - label: ":php: 7.3-zts amd64" command: ./.buildkite/build_extension.sh 7.3-zts agents: phpbuild: "no-debug" queue: "build" arch: "x86_64" - label: ":php: 7.2-zts amd64" command: ./.buildkite/build_extension.sh 7.2-zts agents: phpbuild: "no-debug" queue: "build" arch: "x86_64" - label: ":php: 7.1-zts amd64" command: ./.buildkite/build_extension.sh 7.1-zts agents: phpbuild: "no-debug" queue: "build" arch: "x86_64" - wait - label: ":package::debian: amd64" command: ./.buildkite/package_extension.sh agents: queue: "build" phpbuild: "no-debug" arch: "x86_64" php-xhprof-extension-5.0.2/.gitignore000066400000000000000000000013301356327166500176260ustar00rootroot00000000000000/.deps /Makefile /*.lo /*.loT /*.slo /*.mk /*.la /.libs /libs.mk /ac*.m4 /build /config.h /config.h.in /config.nice /config.sub /configure /configure.in /configure.ac /config.status /config.cache /conftest /conftest.c /core /dynlib.m4 /install-sh /ltmain.sh /include /Makefile.fragments /Makefile.global /Makefile.objects /missing /memory: /mkinstalldirs /modules /scan_makefile_in.awk /config.guess /*swo /*swp /*swn tags /tmp-php.ini /config.log /libtool /*.plg /*.patch /*.tgz /*.ncb /*.opt /*.dsw /autom4te.cache .svn /*~ tests/*.diff tests/*.out tests/*.php tests/*.sh tests/*.log tests/*.exp run-tests.php vendor/ *.phar php5/*.lo php7/*.lo php5/.libs php7/.libs /.gdb_history src/Tideways/*.lo src/Tideways/.libs .vscode php-xhprof-extension-5.0.2/.travis.yml000066400000000000000000000004231356327166500177510ustar00rootroot00000000000000language: php dist: precise notifications: email: false sudo: false php: - 7.0 - 7.1 - 7.2 env: global: - NO_INTERACTION=1 - REPORT_EXIT_STATUS=1 before_script: - phpize - ./configure - make script: make test after_failure: "cat tests/*.diff" php-xhprof-extension-5.0.2/CHANGELOG.md000066400000000000000000000004131356327166500174500ustar00rootroot00000000000000# 5.0.2 - [#90](https://github.com/tideways/php-xhprof-extension/issues/90): Add packaging for PHP 7.4 # 5.0.1 - [#86](https://github.com/tideways/php-xhprof-extension/pull/86): Fix bug in Apple/MacOS timer code that prevented wall time measurements from working. php-xhprof-extension-5.0.2/LICENSE000066400000000000000000000236761356327166500166640ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS php-xhprof-extension-5.0.2/NOTICE000066400000000000000000000015361356327166500165520ustar00rootroot00000000000000Tideways PHP XHProf Profiler Copyright (c) 2014 - 2019 Tideways GmbH This product includes work from the following third-party libraries: - xhprof (https://github.com/phacility/xhprof) Copyright (c) 2009 Facebook Creators: Changhao Jiang Kannan Muthukkaruppan Venkat Venkataramani Haiping Zhao Additional Contributors: George Cabrera - UI enhancements Paul Saab - FreeBSD port Syseleven - Function Arguments - The PHP Group (https://github.com/php/php-src, http://php.net) Copyright (c) 1997-2017 The PHP Group - Xdebug (https://github.com/xdebug/xdebug) Copyright (c) 2003-2018 Derick Rethans. Appveyor Windows Testsuite Configuration - Benjamin Carl (c) 2010-2012 Windows Support for XHProf php-xhprof-extension-5.0.2/README.md000066400000000000000000000142211356327166500171200ustar00rootroot00000000000000# Tideways XHProf Extension Home of the `tideways_xhprof` extension - a hierarchical Profiler for PHP. **This extensions is not compatible with our Tideways service. Are you looking for `tideways` Extension to use with tideways.com?** [Download here](https://tideways.io/profiler/downloads). This PHP extension is a complete, modernized open-source rewrite of the original XHProf extension, with a new core datastructure and specifically optimized for PHP 7. The result is an XHProf data-format compatible extension with a much reduced overhead in the critical path that you are profiling. We are committed to provide support for this extension and port it to as many platforms as possible. **Note:** The public API is not compatible to previous xhprof extensions and forks, but function names are different. Only the data format is compatible. ## About tideways and tideways_xhprof Extensions This repository now contains an extension by the name of `tideways_xhprof`, which only contains the XHProf related (Callgraph) Profiler functionality. Previously the `tideways` extension contained this functionality together with other functionality used in our Software as a Service. If you want to use the SaaS, the current approach is to fetch the code using precompiled binaries and packages from our [Downloads page](https://tideways.io/profiler/downloads). ## Requirements - PHP >= 7.0 - OS: Linux, MacOS, Windows ([Download DLLs](https://ci.appveyor.com/project/tideways/php-profiler-extension)) - Architectures: x64/amd64, x86, ARM, PowerPC - Non-Threaded (NTS) or Threaded (ZTS) support ## Installation You can install the extension from source: phpize ./configure make sudo make install Configure the extension to load with this PHP INI directive: extension=tideways_xhprof.so Restart Apache or PHP-FPM. ### Download Pre-Compiled Binaries We pre-compile binaries for Linux AMD64 and for Windows. See the [releases page for the downloads](https://github.com/tideways/php-xhprof-extension/releases) for each tagged version. The Debian and RPM packages install the PHP extension to `/usr/lib/tideways_xhprof` and doesn't automatically put it into your PHP installation extension directory. You should link the package by full path for a simple installation: extension=/usr/lib/tideways_xhprof/tideways_xhprof-7.3.so ## Usage The API is not compatible to previous xhprof extensions and forks, only the data format is compatible: ```php child function call that was made between the calls to `tideways_xhprof_enable` and `tideways_xhprof_disable`. It is formatted as an array with the parent and child function names as a key concatenated with ==> and an array value with 2 to 5 entries: - `wt` The summary wall time of all calls of this parent ==> child function pair. - `ct` The number of calls between this parent ==> child function pair. - `cpu` The cpu cycle time of all calls of thi sparent ==> child function pair. - `mu` The sum of increase in `memory_get_usage` for this parent ==> child function pair. - `pmu` The sum of increase in `memory_get_peak_usage` for this parent ==> child function pair. When `TIDEWAYS_XHPROF_FLAGS_MEMORY_ALLOC` flag is set, the following additional values are set: - `mem.na` The sum of the number of all allocations in this function. - `mem.nf` The sum of the number of all frees in this function. - `mem.aa` The amount of allocated memory. If `TIDEWAYS_XHPROF_FLAGS_MEMORY_ALLOC_AS_MU` is set, `TIDEWAYS_XHPROF_FLAGS_MEMORY_ALLOC` is activated and, if `TIDEWAYS_XHPROF_FLAGS_MEMORY_MU` is not set, `mem.aa` is additionally returned in `mu`. There is a "magic" function call called "main()" that represents the entry into the profiling. The wall time on this performance data describes the full timeframe that the profiling ran. Example: ```php array( "wt" => 1000, "ct" => 1, "cpu" => 400, ), "main()==>foo" => array( "wt" => 500, "ct" => 2, "cpu" => 200, ), "foo==>bar" => array( "wt" => 200, "ct" => 10, "cpu" => 100, ), ) ``` ## Clock Sources Any Profiler needs timer functions to calculate the duration of a function call and the `tideways_xhprof` extension is no different. On Linux you can collect timing information through various means. The classic, most simple one is the function `gettimeofday`, which PHP uses when you call `microtime()`. This function is slower compared to other mechanisms that the kernel provides: - `clock_gettime(CLOCK_MONOTONIC)` returns a monotonically increasing number (not a timestamp) at very high precision and much faster than `gettimeofday()`. It is the preferred and recommended API to get high precision timestamps. On Xen based virtualizations (such as AWS) this call is much slower than on bare-metal or other virtualizations ([Blog post](https://blog.packagecloud.io/eng/2017/03/08/system-calls-are-much-slower-on-ec2/)) - TSC (Time Stamp Counter) API is accessible in C using inline assembler. It was the timing API that the original XHProf extension used and it is generally very fast, however depending on the make and generation of the CPU might not be synchronized between cores. On modern CPUs it is usually good to use without having to force the current process to a specific CPU. Tideways on Linux defaults to using `clock_gettime(CLOCK_MONOTONIC)`, but if you are running on Xen based virtualization, you could try to reduce the overhead by setting `tideways.clock_use_rdtsc=1" in your PHP.ini. php-xhprof-extension-5.0.2/config.m4000066400000000000000000000153061356327166500173550ustar00rootroot00000000000000PHP_ARG_ENABLE(tideways_xhprof, whether to enable tideways_xhprof support, [ --enable-tideways-xhprof Enable tideways-xhprof support]) AC_DEFUN([AC_TIDEWAYS_CLOCK], [ have_clock_gettime=no AC_MSG_CHECKING([for clock_gettime]) AC_TRY_LINK([ #include ], [struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);], [ have_clock_gettime=yes AC_MSG_RESULT([yes]) ], [ AC_MSG_RESULT([no]) ]) if test "$have_clock_gettime" = "no"; then AC_MSG_CHECKING([for clock_gettime in -lrt]) SAVED_LIBS="$LIBS" LIBS="$LIBS -lrt" AC_TRY_LINK([ #include ], [struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);], [ have_clock_gettime=yes TIDEWAYS_SHARED_LIBADD="$TIDEWAYS_SHARED_LIBADD -lrt" AC_MSG_RESULT([yes]) ], [ LIBS="$SAVED_LIBS" AC_MSG_RESULT([no]) ]) fi if test "$have_clock_gettime" = "no"; then AC_MSG_CHECKING([for clock_get_time]) AC_TRY_RUN([ #include #include #include int main() { kern_return_t ret; clock_serv_t aClock; mach_timespec_t aTime; ret = host_get_clock_service(mach_host_self(), REALTIME_CLOCK, &aClock); if (ret != KERN_SUCCESS) { return 1; } ret = clock_get_time(aClock, &aTime); if (ret != KERN_SUCCESS) { return 2; } return 0; } ], [ have_clock_gettime=yes AC_DEFINE([HAVE_CLOCK_GET_TIME], 1, [do we have clock_get_time?]) AC_MSG_RESULT([yes]) ], [ AC_MSG_RESULT([no]) ]) fi if test "$have_clock_gettime" = "yes"; then AC_DEFINE([HAVE_CLOCK_GETTIME], 1, [do we have clock_gettime?]) fi if test "$have_clock_gettime" = "no"; then AC_MSG_ERROR([clock_gettime is missing, but required]) fi ]) if test "$PHP_TIDEWAYS_XHPROF" != "no"; then PHP_ARG_ENABLE(developer-flags, whether to enable developer build flags, [ --enable-developer-flags Enable developer flags],, no) if test "$PHP_DEVELOPER_FLAGS" = "yes"; then dnl Warn about functions which might be candidates for format attributes PHP_CHECK_GCC_ARG(-Wmissing-format-attribute, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wmissing-format-attribute") dnl Avoid duplicating values for an enum PHP_CHECK_GCC_ARG(-Wduplicate-enum, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wduplicate-enum") dnl Warns on mismatches between #ifndef and #define header guards PHP_CHECK_GCC_ARG(-Wheader-guard, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wheader-guard") dnl logical not of a non-boolean expression PHP_CHECK_GCC_ARG(-Wlogical-not-parentheses, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wlogical-not-parentheses") dnl Warn about suspicious uses of logical operators in expressions PHP_CHECK_GCC_ARG(-Wlogical-op, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wlogical-op") dnl memory error detector. dnl FIXME: -fsanitize=address,undefined for clang. The PHP_CHECK_GCC_ARG macro isn't happy about that string :( PHP_CHECK_GCC_ARG(-fsanitize-address, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -fsanitize-address") dnl Enable frame debugging PHP_CHECK_GCC_ARG(-fno-omit-frame-pointer, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -fno-omit-frame-pointer") dnl Make sure we don't optimize calls PHP_CHECK_GCC_ARG(-fno-optimize-sibling-calls, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -fno-optimize-sibling-calls") PHP_CHECK_GCC_ARG(-Wlogical-op-parentheses, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wlogical-op-parentheses") PHP_CHECK_GCC_ARG(-Wbool-conversion, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wbool-conversion") PHP_CHECK_GCC_ARG(-Wloop-analysis, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wloop-analysis") PHP_CHECK_GCC_ARG(-Wsizeof-array-argument, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wsizeof-array-argument") PHP_CHECK_GCC_ARG(-Wstring-conversion, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wstring-conversion") PHP_CHECK_GCC_ARG(-Wno-variadic-macros, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wno-variadic-macros") PHP_CHECK_GCC_ARG(-Wno-sign-compare, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wno-sign-compare") PHP_CHECK_GCC_ARG(-fstack-protector, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -fstack-protector") PHP_CHECK_GCC_ARG(-fno-exceptions, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -fno-exceptions") PHP_CHECK_GCC_ARG(-Wformat-security, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wformat-security") PHP_CHECK_GCC_ARG(-Wformat-nonliteral, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wformat-nonliteral") PHP_CHECK_GCC_ARG(-Winit-self, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Winit-self") PHP_CHECK_GCC_ARG(-Wwrite-strings, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wwrite-strings") PHP_CHECK_GCC_ARG(-Wenum-compare, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wenum-compare") PHP_CHECK_GCC_ARG(-Wempty-body, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wempty-body") PHP_CHECK_GCC_ARG(-Wparentheses, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wparentheses") PHP_CHECK_GCC_ARG(-Wdeclaration-after-statement, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wdeclaration-after-statement") PHP_CHECK_GCC_ARG(-Wmaybe-uninitialized, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wmaybe-uninitialized") PHP_CHECK_GCC_ARG(-Werror, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Werror") PHP_CHECK_GCC_ARG(-Wextra, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wextra") PHP_CHECK_GCC_ARG(-Wno-unused-parameter, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wno-unused-parameter") PHP_CHECK_GCC_ARG(-Wno-unused-but-set-variable, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wno-unused-but-set-variable") PHP_CHECK_GCC_ARG(-Wno-missing-field-initializers, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wno-missing-field-initializers") MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS" STD_CFLAGS="-g -O0 -Wall" fi AC_CHECK_FUNCS(gettimeofday) AC_CHECK_FUNCS(clock_gettime) AC_TIDEWAYS_CLOCK PHP_TIDEWAYS_XHPROF_CFLAGS="-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 $MAINTAINER_CFLAGS $STD_CFLAGS" PHP_SUBST([LIBS]) PHP_NEW_EXTENSION(tideways_xhprof, tideways_xhprof.c tracing.c, $ext_shared,, $PHP_TIDEWAYS_XHPROF_CFLAGS ) fi php-xhprof-extension-5.0.2/config.w32000066400000000000000000000005561356327166500174510ustar00rootroot00000000000000ARG_WITH("tideways_xhprof", "Tideways XHProf support", "no"); if (PHP_TIDEWAYS_XHPROF != 'no') { EXTENSION("tideways_xhprof", "tideways_xhprof.c", PHP_TIDEWAYS_XHPROF_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); ADD_SOURCES(configure_module_dirname, "tracing.c", "tideways_xhprof"); AC_DEFINE('HAVE_TIDEWAYS_XHPROF', 1, 'Have tideways support'); } php-xhprof-extension-5.0.2/php_tideways_xhprof.h000066400000000000000000000130521356327166500221010ustar00rootroot00000000000000#ifndef PHP_TIDEWAYS_XHPROF_H #define PHP_TIDEWAYS_XHPROF_H extern zend_module_entry tideways_xhprof_module_entry; #define phpext_tideways_xhprof_ptr &tideways_xhprof_module_entry #define PHP_TIDEWAYS_XHPROF_VERSION "5.0.2" #define TIDEWAYS_XHPROF_CALLGRAPH_COUNTER_SIZE 1024 #define TIDEWAYS_XHPROF_CALLGRAPH_SLOTS 8192 #define TIDEWAYS_XHPROF_CLOCK_CGT 0 #define TIDEWAYS_XHPROF_CLOCK_GTOD 1 #define TIDEWAYS_XHPROF_CLOCK_TSC 2 #define TIDEWAYS_XHPROF_CLOCK_MACH 3 #define TIDEWAYS_XHPROF_CLOCK_QPC 4 #define TIDEWAYS_XHPROF_CLOCK_NONE 255 #ifdef ZTS #include "TSRM.h" #endif #if !defined(uint32) typedef unsigned int uint32; #endif #if !defined(uint64) typedef unsigned long long uint64; #endif typedef struct xhprof_frame_t xhprof_frame_t; typedef struct xhprof_callgraph_bucket_t { zend_ulong key; zend_string *parent_class; zend_string *parent_function; int parent_recurse_level; zend_string *child_class; zend_string *child_function; int child_recurse_level; struct xhprof_callgraph_bucket_t *next; zend_long count; zend_long wall_time; zend_long cpu_time; zend_long memory; zend_long memory_peak; long int num_alloc, num_free; long int amount_alloc; } xhprof_callgraph_bucket; /* Tracer maintains a stack of entries being profiled. * * This structure is a convenient place to track start time of a particular * profile operation, recursion depth, and the name of the function being * profiled. */ struct xhprof_frame_t { struct xhprof_frame_t *previous_frame; /* ptr to prev entry being profiled */ zend_string *function_name; zend_string *class_name; uint64 wt_start; /* start value for wall clock timer */ uint64 cpu_start; /* start value for CPU clock timer */ long int mu_start; /* memory usage */ long int pmu_start; /* peak memory usage */ long int num_alloc, num_free; long int amount_alloc; int recurse_level; zend_ulong hash_code; /* hash_code for the function name */ }; ZEND_BEGIN_MODULE_GLOBALS(tideways_xhprof) int enabled; uint64 start_timestamp; uint64 start_time; int clock_source; zend_bool clock_use_rdtsc; double timebase_factor; zend_string *root; xhprof_frame_t *callgraph_frames; xhprof_frame_t *frame_free_list; zend_ulong function_hash_counters[TIDEWAYS_XHPROF_CALLGRAPH_COUNTER_SIZE]; xhprof_callgraph_bucket* callgraph_buckets[TIDEWAYS_XHPROF_CALLGRAPH_SLOTS]; zend_long flags; long int num_alloc; long int num_free; long int amount_alloc; ZEND_END_MODULE_GLOBALS(tideways_xhprof) #if defined(__GNUC__) && __GNUC__ >= 4 # define PHP_TIDEWAYS_XHPROF_API __attribute__ ((visibility("default"))) #else # define PHP_TIDEWAYS_XHPROF_API #endif #define TIDEWAYS_LOGO_DATA_URI "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEYAAABGCAYAAABxLuKEAAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4AMFEx0atoCzjwAABvtJREFUeNrtnH1sleUVwH/ned771dtLDYitFFBCcQ63VTNkA4JDbdSNrXR/mG5LXBYz3f5YzEQWMpINcWZ/KM4sQzecMfhBFheJzNSIMGapVojIKG1lQJHaT1ra8lXae2/vfd9nf7QwVm3Je3u/eulJ3j9u0vPc8/7ec85zznnuW5iSKZmSJIhc/sEYg4hgjFFACLBy/P7jwAURsccFMwJHAx8CtwB5OQ4mDDQAdwIRETFjeYwC9gKLr7LI2Ski944XSgVABxCMHHsNztSDqKR9u5pVhnd2mSudprcaObatEVFy5T82BscxlG2qwD8t4Na8IhHpvvhhdA6xLoXPmXro2gGSrDRjcPJvANyBOX20l6Y3GhCtxgViD9l8ffVylqy7C2/In4iBc4ExwVzmS2oYiuikgRFxryWWoCyNaPmiJREtXFNyLRXbf0x+0bSJGOiM9pC0bYBibNdaXp93eLcctU/EwzGKFs/m7j9VcN3XZiXd2rRux2Li7vOS538ea2wH4xiKl8/jtkeWMf++m1Nma1rB2LEIHrcwfQqMwdgOc+4u4b6X7idwTeqriPR6jD3oWmf6/Bnc8dRKSsoXEiouSJut6a1s4wOuVYqXzaN42by0FzYqrR6TAJhMSVrB2JHerLnx9vMt7GquyiQYGb7EgoKbswLKey3v8kDVSo71HU5BjjHOyGVfuhzlQ/JvQIVKUAULkNACVKAQAkWowMyMAzkbOcPvatewr7MGr/ZhMAmA0X7wTEOUFyMaUdbwU1cWaD/GX4gKzoa8uajQjUhoPtpXkJX5YsiO8u6Jf/Dkh2sJePLwal/iu5KvdC2YNYgojCgEBUoBmoRq+wzJoe4DPFH7GH2RHvI8wYlv12IFxh7aTAL5pKeOlxv+THXbDoKe0OdaiuyqY1Iuhv7oedZV/4L63o9Rogl6QpOgwEuh1HXtZ0vjc9R178dgUBOcCkxqMAOxC/ynt4HNBzfS0HuQgJWHiLgOm5wBE44N8tyBp6hu28FA7AIAASu5jeWkAdMX7mFv+x7ea93Bvs4alCgslTrzJwWYSDzCg29XcG7oLILg1d7c6pUSFb/lp8A/PSm5I6fAAJTOXETciecumMNHT9Dc2uFab8msFcSdWNrsTHqOiUaHOHmql86uHto7u2nr7Ka98xQt7SdpaTtJdGiI+8vLWL/mZ67WXTrnWzjGyTyYWCxO3LaHD7GMwYwcZhljGIxE6OruobOrl9b2Llo7umhu7eDTz9qJxeIorVBKoZVCLuurPB4Ly9J8sK8uIWO/NP0rtPU3ZxbMxudfobr2AAjE4za2bROLx4nF4ti2M3zDAoIgAiKC1hqtx684RYS+M+foHxgkFHRXeywqWpI2MGPmmP7+QU6fPce58xcYGAwTiQ5h2w5KqUtP3tIaPeId4qLj1lpz7HiLa2NvK0rfkXpGdiWtFUeOf+Za76bpC8cdLuXEdl1/uMm1TmFwFjMDhWmBkzEwdY1HE9J74Jafp2XbzhiYk929tHV0udb79vzv49d5uQvG6/Gwdds7rvU82uLLM76au2AsS/OvDz7GcdwWbULZjStTHk4Z7ZXC4Qhdp/pc66266QdosXIXzFAsxsGGIwnpPlz6KMaY3AQjIry4dXtCuvfOryBgBXITDEDTiTaaTrS61psRuJbF1y9P2Sgi42CCeX5eeb0qId0NdzybsvFmxsGICPsPHU44XzxcujollXBWTPBO9Zxm9/sfJaRbufAnhDzTkg4nK8B4vR42PP1CYjcgihe/82bS58FZM/MdisX45559CekWBov40cKfErWjuQdGRNiSYBIGeOjWX7J01gpIUkhl1SlB45HjVO2sSVj/9ys2URQsTspsOKvA+H0+/vCXrUQiiYWEV/v426qdzM6fO+GqOOvOlQYGw7xRtXtCa2z57lvMCc2bkOdkHRgRYePzr9LSfjLhNTzay6vlVZSXVBKOD+YGmOGQ8rLh6c0TDofHvrGezfe8Tp4VzA0wAPWHj/PX196c8DqlRbfz94rdPHr7b7DEImpHJjcYy9Jsfnkbhz45NvF+zJtP+YJKdv2wjvVLn+HW6xZTFCzGp8d+4Wv0q38zgB5A1j25iV01+654gJaOsKre/gLJ/olkzIkhyOVN6CIROZD1HnNRBsNRKh/6dQIj0CskaOUZtzPPejBKCc2tnaz+7TPp/V4mgSgl1H50iF89/uwUmNGitWb3+/tZ+8QfsR1nCszo8cSevf/mwUceT32hOWpXKgA6gbyqnTUc/bQVpbLvB/O27VB8/UwqV92DUkl7toUicmosMAqoBb7J1SXVInLnxX/68blQEhEHuAvYeRVBqQG+d7FP+0KPGfEaERFjjClk+LV+J4ehtF0ePlPy/44wBWFKkiD/BYCRXpsmVUP/AAAAAElFTkSuQmCC" #if defined(ZTS) && defined(COMPILE_DL_TIDEWAYS_XHPROF) ZEND_TSRMLS_CACHE_EXTERN() #endif #endif /* PHP_TIDEWAYS_XHPROF_H */ php-xhprof-extension-5.0.2/tests/000077500000000000000000000000001356327166500170035ustar00rootroot00000000000000php-xhprof-extension-5.0.2/tests/common.php000066400000000000000000000030741356327166500210100ustar00rootroot00000000000000 $metrics) { foreach ($ignoreFunctions as $ignoreFunction) { if (strpos($func, "==>" . $ignoreFunction) !== false) { continue 2; } } echo str_pad($func, 40) . ":"; ksort($metrics); foreach ($metrics as $name => $value) { // Only call counts are stable. // Wild card everything else. We still print // the metric name to ensure it was collected. if (!in_array($name, array("ct"))) { $value = "*"; } else { $value = str_pad($value, 8, " ", STR_PAD_LEFT); } echo " {$name}={$value};"; } echo "\n"; } } php-xhprof-extension-5.0.2/tests/xhprof_001.phpt000066400000000000000000000100401356327166500215610ustar00rootroot00000000000000--TEST-- Tideways: Basic Profiling Test --FILE-- --EXPECT-- Part 1: Default Flags foo==>bar : ct= 2; wt=*; main() : ct= 1; wt=*; main()==>foo : ct= 1; wt=*; main()==>tideways_xhprof_disable : ct= 1; wt=*; Part 2: CPU foo==>bar : cpu=*; ct= 2; wt=*; main() : cpu=*; ct= 1; wt=*; main()==>foo : cpu=*; ct= 1; wt=*; main()==>tideways_xhprof_disable : cpu=*; ct= 1; wt=*; Part 3: No Builtins foo==>bar : ct= 2; wt=*; main() : ct= 1; wt=*; main()==>foo : ct= 1; wt=*; Part 4: Memory foo==>bar : ct= 2; mu=*; pmu=*; wt=*; main() : ct= 1; mu=*; pmu=*; wt=*; main()==>foo : ct= 1; mu=*; pmu=*; wt=*; main()==>tideways_xhprof_disable : ct= 1; mu=*; pmu=*; wt=*; Part 5: Memory & CPU foo==>bar : cpu=*; ct= 2; mu=*; pmu=*; wt=*; main() : cpu=*; ct= 1; mu=*; pmu=*; wt=*; main()==>foo : cpu=*; ct= 1; mu=*; pmu=*; wt=*; main()==>tideways_xhprof_disable : cpu=*; ct= 1; mu=*; pmu=*; wt=*; Part 6: Extended Memory Profiling foo==>bar : ct= 2; mem.aa=*; mem.na=*; mem.nf=*; wt=*; main() : ct= 1; mem.aa=*; mem.na=*; mem.nf=*; wt=*; main()==>foo : ct= 1; mem.aa=*; mem.na=*; mem.nf=*; wt=*; main()==>tideways_xhprof_disable : ct= 1; mem.aa=*; mem.na=*; mem.nf=*; wt=*; Part 7: Extended Memory Profiling as mu foo==>bar : ct= 2; mem.aa=*; mem.na=*; mem.nf=*; mu=*; wt=*; main() : ct= 1; mem.aa=*; mem.na=*; mem.nf=*; mu=*; wt=*; main()==>foo : ct= 1; mem.aa=*; mem.na=*; mem.nf=*; mu=*; wt=*; main()==>tideways_xhprof_disable : ct= 1; mem.aa=*; mem.na=*; mem.nf=*; mu=*; wt=*; php-xhprof-extension-5.0.2/tests/xhprof_002.phpt000066400000000000000000000035771356327166500216030ustar00rootroot00000000000000--TEST-- Tideways: Test (direct and indirect) recursive function calls. --FILE-- 0) { if ($use_direct_recursion) foo($depth - 1, $use_direct_recursion); else bar($depth - 1, $use_direct_recursion); } } tideways_xhprof_enable(); foo(4, true); $output = tideways_xhprof_disable(); echo "Direct Recursion\n"; print_canonical($output); echo "\n"; tideways_xhprof_enable(); foo(4, false); $output = tideways_xhprof_disable(); echo "Indirect Recursion\n"; print_canonical($output); echo "\n"; ?> --EXPECT-- Direct Recursion foo==>foo@1 : ct= 1; wt=*; foo@1==>foo@2 : ct= 1; wt=*; foo@2==>foo@3 : ct= 1; wt=*; foo@3==>foo@4 : ct= 1; wt=*; main() : ct= 1; wt=*; main()==>foo : ct= 1; wt=*; main()==>tideways_xhprof_disable : ct= 1; wt=*; Indirect Recursion bar==>foo@1 : ct= 1; wt=*; bar@1==>foo@2 : ct= 1; wt=*; bar@2==>foo@3 : ct= 1; wt=*; bar@3==>foo@4 : ct= 1; wt=*; foo==>bar : ct= 1; wt=*; foo@1==>bar@1 : ct= 1; wt=*; foo@2==>bar@2 : ct= 1; wt=*; foo@3==>bar@3 : ct= 1; wt=*; main() : ct= 1; wt=*; main()==>foo : ct= 1; wt=*; main()==>tideways_xhprof_disable : ct= 1; wt=*; php-xhprof-extension-5.0.2/tests/xhprof_003.phpt000066400000000000000000000026551356327166500216000ustar00rootroot00000000000000--TEST-- Tideways: Test Class Methods, Constructors, Destructors. --FILE-- _attr = $attr; } private static function inner_static() { return C::$_static_attr; } public static function outer_static() { return C::inner_static(); } public function get_attr() { return $this->_attr; } function __destruct() { echo "Destroying class {$this->_attr}\n"; } } tideways_xhprof_enable(); // static methods echo C::outer_static() . "\n"; // constructor $obj = new C("Hello World"); // instance methods $obj->get_attr(); // destructor $obj = null; $output = tideways_xhprof_disable(); echo "Profiler data for 'Class' tests:\n"; print_canonical($output); echo "\n"; ?> --EXPECT-- i am a class static In constructor... Destroying class Hello World Profiler data for 'Class' tests: C::outer_static==>C::inner_static : ct= 1; wt=*; main() : ct= 1; wt=*; main()==>C::__construct : ct= 1; wt=*; main()==>C::__destruct : ct= 1; wt=*; main()==>C::get_attr : ct= 1; wt=*; main()==>C::outer_static : ct= 1; wt=*; main()==>tideways_xhprof_disable : ct= 1; wt=*; php-xhprof-extension-5.0.2/tests/xhprof_004.phpt000066400000000000000000000010671356327166500215750ustar00rootroot00000000000000--TEST-- Tideways: Closure and Anonymous Classes --FILE-- baz(); $output = tideways_xhprof_disable(); print_canonical($output); ?> --EXPECTF-- main() : ct= 1; wt=*; main()==>class@anonymous::baz : ct= 1; wt=*; main()==>tideways_xhprof_disable : ct= 1; wt=*; main()==>{closure} : ct= 1; wt=*; php-xhprof-extension-5.0.2/tests/xhprof_005.phpt000066400000000000000000000003071356327166500215720ustar00rootroot00000000000000--TEST-- tideways: dont disable no memory leak --FILE-- ") !== false) { echo $line . PHP_EOL; } } function foo($x) { } // 1: Sanity test a simple profile run tideways_xhprof_enable(); foo("this is a test"); $output = tideways_xhprof_disable(); print_canonical($output); --EXPECTF-- string(1) "1" Clock Source => %s main() : ct= 1; wt=*; main()==>foo : ct= 1; wt=*; main()==>tideways_xhprof_disable : ct= 1; wt=*; php-xhprof-extension-5.0.2/tests/xhprof_007.phpt000066400000000000000000000017501356327166500215770ustar00rootroot00000000000000--TEST-- Tideways: call_user_func_array --FILE-- foo : ct= 1; wt=*; call_user_func_array==>class@anonymous::__invoke: ct= 1; wt=*; call_user_func_array==>foo : ct= 1; wt=*; call_user_func_array==>{closure} : ct= 1; wt=*; main() : ct= 1; wt=*; main()==>call_user_func : ct= 1; wt=*; main()==>call_user_func_array : ct= 3; wt=*; main()==>tideways_xhprof_disable : ct= 1; wt=*; php-xhprof-extension-5.0.2/tideways_xhprof.c000066400000000000000000000167251356327166500212370ustar00rootroot00000000000000#ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_ini.h" #include "SAPI.h" #include "ext/standard/info.h" #include "php_tideways_xhprof.h" ZEND_DECLARE_MODULE_GLOBALS(tideways_xhprof) #include "tracing.h" static void (*_zend_execute_ex) (zend_execute_data *execute_data); static void (*_zend_execute_internal) (zend_execute_data *execute_data, zval *return_value); ZEND_DLEXPORT void tideways_xhprof_execute_internal(zend_execute_data *execute_data, zval *return_value); ZEND_DLEXPORT void tideways_xhprof_execute_ex (zend_execute_data *execute_data); PHP_INI_BEGIN() STD_PHP_INI_ENTRY("tideways_xhprof.clock_use_rdtsc", "0", PHP_INI_SYSTEM, OnUpdateBool, clock_use_rdtsc, zend_tideways_xhprof_globals, tideways_xhprof_globals) PHP_INI_END() PHP_FUNCTION(tideways_xhprof_enable) { zend_long flags = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) == FAILURE) { return; } tracing_begin(flags TSRMLS_CC); tracing_enter_root_frame(TSRMLS_C); } PHP_FUNCTION(tideways_xhprof_disable) { tracing_end(TSRMLS_C); array_init(return_value); tracing_callgraph_append_to_array(return_value TSRMLS_CC); } PHP_GINIT_FUNCTION(tideways_xhprof) { #if defined(COMPILE_DL_TIDEWAYS_XHPROF) && defined(ZTS) ZEND_TSRMLS_CACHE_UPDATE(); #endif tideways_xhprof_globals->root = NULL; tideways_xhprof_globals->callgraph_frames = NULL; tideways_xhprof_globals->frame_free_list = NULL; } PHP_MINIT_FUNCTION(tideways_xhprof) { REGISTER_INI_ENTRIES(); REGISTER_LONG_CONSTANT("TIDEWAYS_XHPROF_FLAGS_MEMORY", TIDEWAYS_XHPROF_FLAGS_MEMORY, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("TIDEWAYS_XHPROF_FLAGS_MEMORY_MU", TIDEWAYS_XHPROF_FLAGS_MEMORY_MU, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("TIDEWAYS_XHPROF_FLAGS_MEMORY_PMU", TIDEWAYS_XHPROF_FLAGS_MEMORY_PMU, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("TIDEWAYS_XHPROF_FLAGS_CPU", TIDEWAYS_XHPROF_FLAGS_CPU, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("TIDEWAYS_XHPROF_FLAGS_NO_BUILTINS", TIDEWAYS_XHPROF_FLAGS_NO_BUILTINS, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("TIDEWAYS_XHPROF_FLAGS_MEMORY_ALLOC", TIDEWAYS_XHPROF_FLAGS_MEMORY_ALLOC, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("TIDEWAYS_XHPROF_FLAGS_MEMORY_ALLOC_AS_MU", TIDEWAYS_XHPROF_FLAGS_MEMORY_ALLOC_AS_MU, CONST_CS | CONST_PERSISTENT); _zend_execute_internal = zend_execute_internal; zend_execute_internal = tideways_xhprof_execute_internal; _zend_execute_ex = zend_execute_ex; zend_execute_ex = tideways_xhprof_execute_ex; return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(tideways_xhprof) { return SUCCESS; } PHP_RINIT_FUNCTION(tideways_xhprof) { tracing_request_init(TSRMLS_C); TXRG(clock_source) = determine_clock_source(TXRG(clock_use_rdtsc)); CG(compiler_options) = CG(compiler_options) | ZEND_COMPILE_NO_BUILTINS; return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(tideways_xhprof) { int i = 0; xhprof_callgraph_bucket *bucket; tracing_end(TSRMLS_C); for (i = 0; i < TIDEWAYS_XHPROF_CALLGRAPH_SLOTS; i++) { bucket = TXRG(callgraph_buckets)[i]; while (bucket) { TXRG(callgraph_buckets)[i] = bucket->next; tracing_callgraph_bucket_free(bucket); bucket = TXRG(callgraph_buckets)[i]; } } tracing_request_shutdown(); return SUCCESS; } static int tideways_xhprof_info_print(const char *str) /* {{{ */ { return php_output_write(str, strlen(str)); } PHP_MINFO_FUNCTION(tideways_xhprof) { php_info_print_table_start(); php_info_print_table_row(2, "Version", PHP_TIDEWAYS_XHPROF_VERSION); switch (TXRG(clock_source)) { case TIDEWAYS_XHPROF_CLOCK_TSC: php_info_print_table_row(2, "Clock Source", "tsc"); break; case TIDEWAYS_XHPROF_CLOCK_CGT: php_info_print_table_row(2, "Clock Source", "clock_gettime"); break; case TIDEWAYS_XHPROF_CLOCK_GTOD: php_info_print_table_row(2, "Clock Source", "gettimeofday"); break; case TIDEWAYS_XHPROF_CLOCK_MACH: php_info_print_table_row(2, "Clock Source", "mach"); break; case TIDEWAYS_XHPROF_CLOCK_QPC: php_info_print_table_row(2, "Clock Source", "Query Performance Counter"); break; case TIDEWAYS_XHPROF_CLOCK_NONE: php_info_print_table_row(2, "Clock Source", "none"); break; } php_info_print_table_end(); php_info_print_box_start(0); if (!sapi_module.phpinfo_as_text) { tideways_xhprof_info_print("\"Tideways\n"); } tideways_xhprof_info_print("Tideways is a PHP Profiler, Monitoring and Exception Tracking Software."); tideways_xhprof_info_print(!sapi_module.phpinfo_as_text?"

":"\n\n"); tideways_xhprof_info_print("The 'tideways_xhprof' extension provides a subset of the functionality of our commercial Tideways offering in a modern, optimized fork of the XHProf extension from Facebook as open-source. (c) Tideways GmbH 2014-2017, (c) Facebook 2009"); if (!sapi_module.phpinfo_as_text) { tideways_xhprof_info_print("

Register for a free trial on https://tideways.io"); } else { tideways_xhprof_info_print("\n\nRegister for a free trial on https://tideways.io\n\n"); } php_info_print_box_end(); } ZEND_DLEXPORT void tideways_xhprof_execute_internal(zend_execute_data *execute_data, zval *return_value) { int is_profiling = 1; if (!TXRG(enabled) || (TXRG(flags) & TIDEWAYS_XHPROF_FLAGS_NO_BUILTINS) > 0) { execute_internal(execute_data, return_value TSRMLS_CC); return; } is_profiling = tracing_enter_frame_callgraph(NULL, execute_data TSRMLS_CC); if (!_zend_execute_internal) { execute_internal(execute_data, return_value TSRMLS_CC); } else { _zend_execute_internal(execute_data, return_value TSRMLS_CC); } if (is_profiling == 1 && TXRG(callgraph_frames)) { tracing_exit_frame_callgraph(TSRMLS_C); } } ZEND_DLEXPORT void tideways_xhprof_execute_ex (zend_execute_data *execute_data) { zend_execute_data *real_execute_data = execute_data; int is_profiling = 0; if (!TXRG(enabled)) { _zend_execute_ex(execute_data TSRMLS_CC); return; } is_profiling = tracing_enter_frame_callgraph(NULL, real_execute_data TSRMLS_CC); _zend_execute_ex(execute_data TSRMLS_CC); if (is_profiling == 1 && TXRG(callgraph_frames)) { tracing_exit_frame_callgraph(TSRMLS_C); } } const zend_function_entry tideways_xhprof_functions[] = { PHP_FE(tideways_xhprof_enable, NULL) PHP_FE(tideways_xhprof_disable, NULL) PHP_FE_END }; zend_module_entry tideways_xhprof_module_entry = { STANDARD_MODULE_HEADER, "tideways_xhprof", tideways_xhprof_functions, PHP_MINIT(tideways_xhprof), PHP_MSHUTDOWN(tideways_xhprof), PHP_RINIT(tideways_xhprof), PHP_RSHUTDOWN(tideways_xhprof), PHP_MINFO(tideways_xhprof), PHP_TIDEWAYS_XHPROF_VERSION, PHP_MODULE_GLOBALS(tideways_xhprof), PHP_GINIT(tideways_xhprof), NULL, NULL, STANDARD_MODULE_PROPERTIES_EX }; #ifdef COMPILE_DL_TIDEWAYS_XHPROF #ifdef ZTS ZEND_TSRMLS_CACHE_DEFINE() #endif ZEND_GET_MODULE(tideways_xhprof) #endif php-xhprof-extension-5.0.2/timer.h000066400000000000000000000124531356327166500171370ustar00rootroot00000000000000#ifndef TRACER_TIMER_H #define TRACER_TIMER_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef PHP_WIN32 #include "win32/time.h" #include "win32/unistd.h" #include "win32/getrusage.h" #elif __APPLE__ #include #include #else #include "sys/time.h" #include #endif static int determine_clock_source(int clock_use_rdtsc) { #if defined(__APPLE__) return TIDEWAYS_XHPROF_CLOCK_MACH; #elif defined(__powerpc__) || defined(__ppc__) return TIDEWAYS_XHPROF_CLOCK_TSC; #elif defined(__s390__) // Covers both s390 and s390x. return TIDEWAYS_XHPROF_CLOCK_TSC; #elif defined(__ARM_ARCH) return TIDEWAYS_XHPROF_CLOCK_GTOD; #elif defined(PHP_WIN32) return TIDEWAYS_XHPROF_CLOCK_QPC; #else struct timespec res; if (clock_use_rdtsc == 1) { return TIDEWAYS_XHPROF_CLOCK_TSC; } #if HAVE_CLOCK_GETTIME if (clock_gettime(CLOCK_MONOTONIC, &res) == 0) { return TIDEWAYS_XHPROF_CLOCK_CGT; } #endif #if HAVE_GETTIMEOFDAY return TIDEWAYS_XHPROF_CLOCK_GTOD; #endif return TIDEWAYS_XHPROF_CLOCK_TSC; #endif } static zend_always_inline uint64 current_timestamp() { struct timeval tv; if (gettimeofday(&tv, NULL)) { php_error(E_ERROR, "tracer: Cannot acquire gettimeofday"); zend_bailout(); } return 1000 * (uint64) tv.tv_sec + (uint64) tv.tv_usec / 1000; } static zend_always_inline uint64 time_milliseconds_cgt() { #if HAVE_CLOCK_GETTIME struct timespec s; if (clock_gettime(CLOCK_MONOTONIC, &s) == 0) { return s.tv_sec * 1000000 + s.tv_nsec / 1000; } #endif return 0; } static zend_always_inline uint64 time_milliseconds_gtod() { #if HAVE_GETTIMEOFDAY struct timeval now; if (gettimeofday(&now, NULL) == 0) { return now.tv_sec * 1000000 + now.tv_usec; } #endif return 0; } static zend_always_inline uint64 time_milliseconds_tsc_query() { #if defined(__s390__) // Covers both s390 and s390x. uint64_t tsc; // Return the CPU clock. asm("stck %0" : "=Q" (tsc) : : "cc"); return tsc; #elif defined(__i386__) int64_t ret; __asm__ volatile("rdtsc" : "=A"(ret)); return ret; #elif defined(__x86_64__) || defined(__amd64__) uint64 val; uint32 a, d; asm volatile("rdtsc" : "=a" (a), "=d" (d)); (val) = ((uint64)a) | (((uint64)d)<<32); return val; #elif defined(__powerpc__) || defined(__ppc__) uint64 val; asm volatile ("mftb %0" : "=r" (val)); return val; #else return 0; #endif } /** * Get the current wallclock timer * * @return 64 bit unsigned integer * @author cjiang */ static zend_always_inline uint64 time_milliseconds(int source, double timebase_factor) { #if defined(__APPLE__) return mach_absolute_time() / timebase_factor; #elif defined(PHP_WIN32) LARGE_INTEGER count; if (!QueryPerformanceCounter(&count)) { return 0; } return (double)(count.QuadPart) / timebase_factor; #else if (source == TIDEWAYS_XHPROF_CLOCK_TSC) { return time_milliseconds_tsc_query() / timebase_factor; } else if (source == TIDEWAYS_XHPROF_CLOCK_GTOD) { return time_milliseconds_gtod(); } else if (source == TIDEWAYS_XHPROF_CLOCK_CGT) { return time_milliseconds_cgt(); } #endif return 0; } /** * Get time delta in microseconds. */ static long get_us_interval(struct timeval *start, struct timeval *end) { return (((end->tv_sec - start->tv_sec) * 1000000) + (end->tv_usec - start->tv_usec)); } static zend_always_inline double get_timebase_factor_tsc() { struct timeval start; struct timeval end; uint64 tsc_start; uint64 tsc_end; volatile int i; if (gettimeofday(&start, 0)) { perror("gettimeofday"); return 0.0; } tsc_start = time_milliseconds_tsc_query(); /* Busy loop for 5 miliseconds. */ do { for (i = 0; i < 1000000; i++); if (gettimeofday(&end, 0)) { perror("gettimeofday"); return 0.0; } tsc_end = time_milliseconds_tsc_query(); } while (get_us_interval(&start, &end) < 5000); return (tsc_end - tsc_start) * 1.0 / (get_us_interval(&start, &end)); } /** * Get the timebase factor necessary to divide by in time_milliseconds() */ static zend_always_inline double get_timebase_factor(int source) { #if defined(__APPLE__) mach_timebase_info_data_t sTimebaseInfo; (void) mach_timebase_info(&sTimebaseInfo); return (sTimebaseInfo.numer / sTimebaseInfo.denom) * 1000; #elif defined(PHP_WIN32) unsigned __int64 frequency; if (!QueryPerformanceFrequency( (LARGE_INTEGER*)&frequency)) { zend_error(E_ERROR, "QueryPerformanceFrequency"); } return (double)frequency/1000000.0; #else if (source == TIDEWAYS_XHPROF_CLOCK_TSC) { return get_timebase_factor_tsc(); } return 1.0; #endif } /** * Get the current real CPU clock timer */ static uint64 cpu_timer() { struct rusage ru; #if defined(CLOCK_PROCESS_CPUTIME_ID) struct timespec s; if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &s) == 0) { return s.tv_sec * 1000000 + s.tv_nsec / 1000; } #endif if (getrusage(RUSAGE_SELF, &ru) == 0) { return ru.ru_utime.tv_sec * 1000000 + ru.ru_utime.tv_usec + ru.ru_stime.tv_sec * 1000000 + ru.ru_stime.tv_usec; } return 0; } #endif php-xhprof-extension-5.0.2/tracing.c000066400000000000000000000232241356327166500174370ustar00rootroot00000000000000#ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "ext/standard/html.h" #include "php_tideways_xhprof.h" extern ZEND_DECLARE_MODULE_GLOBALS(tideways_xhprof); #include "tracing.h" static const char digits[] = "0123456789abcdef"; static void *(*_zend_malloc) (size_t); static void (*_zend_free) (void *); static void *(*_zend_realloc) (void *, size_t); void *tideways_malloc (size_t size); void tideways_free (void *ptr); void *tideways_realloc (void *ptr, size_t size); /** * Free any items in the free list. */ static zend_always_inline void tracing_free_the_free_list(TSRMLS_D) { xhprof_frame_t *frame = TXRG(frame_free_list); xhprof_frame_t *current; while (frame) { current = frame; frame = frame->previous_frame; efree(current); } } void tracing_enter_root_frame(TSRMLS_D) { TXRG(start_time) = time_milliseconds(TXRG(clock_source), TXRG(timebase_factor)); TXRG(start_timestamp) = current_timestamp(); TXRG(enabled) = 1; TXRG(root) = zend_string_init(TIDEWAYS_XHPROF_ROOT_SYMBOL, sizeof(TIDEWAYS_XHPROF_ROOT_SYMBOL)-1, 0); tracing_enter_frame_callgraph(TXRG(root), NULL TSRMLS_CC); } void tracing_end(TSRMLS_D) { if (TXRG(enabled) == 1) { if (TXRG(root)) { zend_string_release(TXRG(root)); } while (TXRG(callgraph_frames)) { tracing_exit_frame_callgraph(TSRMLS_C); } TXRG(enabled) = 0; TXRG(callgraph_frames) = NULL; if (TXRG(flags) & TIDEWAYS_XHPROF_FLAGS_MEMORY_ALLOC) { zend_mm_heap *heap = zend_mm_get_heap(); if (_zend_malloc || _zend_free || _zend_realloc) { zend_mm_set_custom_handlers(heap, _zend_malloc, _zend_free, _zend_realloc); _zend_malloc = NULL; _zend_free = NULL; _zend_realloc = NULL; } else { // zend_mm_heap is incomplete type, hence one can not access it // the following line is equivalent to heap->use_custom_heap = 0; *((int*) heap) = 0; } } } } void tracing_callgraph_bucket_free(xhprof_callgraph_bucket *bucket) { if (bucket->parent_class) { zend_string_release(bucket->parent_class); } if (bucket->parent_function) { zend_string_release(bucket->parent_function); } if (bucket->child_class) { zend_string_release(bucket->child_class); } if (bucket->child_function) { zend_string_release(bucket->child_function); } efree(bucket); } xhprof_callgraph_bucket *tracing_callgraph_bucket_find(xhprof_callgraph_bucket *bucket, xhprof_frame_t *current_frame, xhprof_frame_t *previous, zend_long key) { while (bucket) { if (bucket->key == key && bucket->child_recurse_level == current_frame->recurse_level && bucket->child_class == current_frame->class_name && zend_string_equals(bucket->child_function, current_frame->function_name)) { if (previous == NULL && bucket->parent_class == NULL && bucket->parent_function == NULL ) { // special handling for the root return bucket; } else if (previous && previous->recurse_level == bucket->parent_recurse_level && previous->class_name == bucket->parent_class && zend_string_equals(previous->function_name, bucket->parent_function)) { // parent matches as well return bucket; } } bucket = bucket->next; } return NULL; } zend_always_inline static zend_ulong hash_data(zend_ulong hash, char *data, size_t size) { size_t i; for (i = 0; i < size; ++i) { hash = hash * 33 + data[i]; } return hash; } zend_always_inline static zend_ulong hash_int(zend_ulong hash, int data) { return hash_data(hash, (char*) &data, sizeof(data)); } zend_ulong tracing_callgraph_bucket_key(xhprof_frame_t *frame) { zend_ulong hash = 5381; xhprof_frame_t *previous = frame->previous_frame; if (previous) { if (previous->class_name) { hash = hash_int(hash, ZSTR_HASH(previous->class_name)); } if (previous->function_name) { hash = hash_int(hash, ZSTR_HASH(previous->function_name)); } hash += previous->recurse_level; } if (frame->class_name) { hash = hash_int(hash, ZSTR_HASH(frame->class_name)); } if (frame->function_name) { hash = hash_int(hash, ZSTR_HASH(frame->function_name)); } hash += frame->recurse_level; return hash; } void tracing_callgraph_get_parent_child_name(xhprof_callgraph_bucket *bucket, char *symbol, size_t symbol_len TSRMLS_DC) { if (bucket->parent_class) { if (bucket->parent_recurse_level > 0) { snprintf(symbol, symbol_len, "%s::%s@%d==>", ZSTR_VAL(bucket->parent_class), ZSTR_VAL(bucket->parent_function), bucket->parent_recurse_level); } else { snprintf(symbol, symbol_len, "%s::%s==>", ZSTR_VAL(bucket->parent_class), ZSTR_VAL(bucket->parent_function)); } } else if (bucket->parent_function) { if (bucket->parent_recurse_level > 0) { snprintf(symbol, symbol_len, "%s@%d==>", ZSTR_VAL(bucket->parent_function), bucket->parent_recurse_level); } else { snprintf(symbol, symbol_len, "%s==>", ZSTR_VAL(bucket->parent_function)); } } else { snprintf(symbol, symbol_len, ""); } if (bucket->child_class) { if (bucket->child_recurse_level > 0) { snprintf(symbol, symbol_len, "%s%s::%s@%d", symbol, ZSTR_VAL(bucket->child_class), ZSTR_VAL(bucket->child_function), bucket->child_recurse_level); } else { snprintf(symbol, symbol_len, "%s%s::%s", symbol, ZSTR_VAL(bucket->child_class), ZSTR_VAL(bucket->child_function)); } } else if (bucket->child_function) { if (bucket->child_recurse_level > 0) { snprintf(symbol, symbol_len, "%s%s@%d", symbol, ZSTR_VAL(bucket->child_function), bucket->child_recurse_level); } else { snprintf(symbol, symbol_len, "%s%s", symbol, ZSTR_VAL(bucket->child_function)); } } } void tracing_callgraph_append_to_array(zval *return_value TSRMLS_DC) { int i = 0; xhprof_callgraph_bucket *bucket; char symbol[512] = ""; zval stats_zv, *stats = &stats_zv; int as_mu = (TXRG(flags) & (TIDEWAYS_XHPROF_FLAGS_MEMORY_ALLOC_AS_MU | TIDEWAYS_XHPROF_FLAGS_MEMORY_MU)) == TIDEWAYS_XHPROF_FLAGS_MEMORY_ALLOC_AS_MU; for (i = 0; i < TIDEWAYS_XHPROF_CALLGRAPH_SLOTS; i++) { bucket = TXRG(callgraph_buckets)[i]; while (bucket) { tracing_callgraph_get_parent_child_name(bucket, symbol, sizeof(symbol) TSRMLS_CC); array_init(stats); add_assoc_long(stats, "ct", bucket->count); add_assoc_long(stats, "wt", bucket->wall_time); if (TXRG(flags) & TIDEWAYS_XHPROF_FLAGS_MEMORY_ALLOC) { add_assoc_long(stats, "mem.na", bucket->num_alloc); add_assoc_long(stats, "mem.nf", bucket->num_free); add_assoc_long(stats, "mem.aa", bucket->amount_alloc); if (as_mu) { add_assoc_long(stats, "mu", bucket->amount_alloc); } } if (TXRG(flags) & TIDEWAYS_XHPROF_FLAGS_CPU) { add_assoc_long(stats, "cpu", bucket->cpu_time); } if (TXRG(flags) & TIDEWAYS_XHPROF_FLAGS_MEMORY_MU) { add_assoc_long(stats, "mu", bucket->memory); } if (TXRG(flags) & TIDEWAYS_XHPROF_FLAGS_MEMORY_PMU) { add_assoc_long(stats, "pmu", bucket->memory_peak); } add_assoc_zval(return_value, symbol, stats); TXRG(callgraph_buckets)[i] = bucket->next; tracing_callgraph_bucket_free(bucket); bucket = TXRG(callgraph_buckets)[i]; } } } void tracing_begin(zend_long flags TSRMLS_DC) { int i; TXRG(flags) = flags; TXRG(callgraph_frames) = NULL; for (i = 0; i < TIDEWAYS_XHPROF_CALLGRAPH_SLOTS; i++) { TXRG(callgraph_buckets)[i] = NULL; } for (i = 0; i < TIDEWAYS_XHPROF_CALLGRAPH_COUNTER_SIZE; i++) { TXRG(function_hash_counters)[i] = 0; } if (flags & TIDEWAYS_XHPROF_FLAGS_MEMORY_ALLOC) { zend_mm_heap *heap = zend_mm_get_heap(); zend_mm_get_custom_handlers (heap, &_zend_malloc, &_zend_free, &_zend_realloc); zend_mm_set_custom_handlers (heap, &tideways_malloc, &tideways_free, &tideways_realloc); } } void tracing_request_init(TSRMLS_D) { TXRG(timebase_factor) = get_timebase_factor(TXRG(clock_source)); TXRG(enabled) = 0; TXRG(flags) = 0; TXRG(frame_free_list) = NULL; TXRG(num_alloc) = 0; TXRG(num_free) = 0; TXRG(amount_alloc) = 0; } void tracing_request_shutdown() { tracing_free_the_free_list(TSRMLS_C); } void *tideways_malloc (size_t size) { TXRG(num_alloc) += 1; TXRG(amount_alloc) += size; if (_zend_malloc) { return _zend_malloc(size); } zend_mm_heap *heap = zend_mm_get_heap(); return zend_mm_alloc(heap, size); } void tideways_free (void *ptr) { TXRG(num_free) += 1; if (_zend_free) { return _zend_free(ptr); } zend_mm_heap *heap = zend_mm_get_heap(); return zend_mm_free(heap, ptr); } void *tideways_realloc (void *ptr, size_t size) { TXRG(num_alloc) += 1; TXRG(num_free) += 1; TXRG(amount_alloc) += size; if (_zend_realloc) { return _zend_realloc(ptr, size); } zend_mm_heap *heap = zend_mm_get_heap(); return zend_mm_realloc(heap, ptr, size); } php-xhprof-extension-5.0.2/tracing.h000066400000000000000000000176451356327166500174560ustar00rootroot00000000000000#include "timer.h" #define TIDEWAYS_XHPROF_ROOT_SYMBOL "main()" #define TIDEWAYS_XHPROF_CALLGRAPH_COUNTER_SIZE 1024 #define TIDEWAYS_XHPROF_CALLGRAPH_SLOTS 8192 #define TIDEWAYS_XHPROF_FLAGS_CPU 1 #define TIDEWAYS_XHPROF_FLAGS_MEMORY_MU 2 #define TIDEWAYS_XHPROF_FLAGS_MEMORY_PMU 4 #define TIDEWAYS_XHPROF_FLAGS_MEMORY 6 #define TIDEWAYS_XHPROF_FLAGS_MEMORY_ALLOC 16 #define TIDEWAYS_XHPROF_FLAGS_MEMORY_ALLOC_AS_MU (32|16) #define TIDEWAYS_XHPROF_FLAGS_NO_BUILTINS 8 void tracing_callgraph_append_to_array(zval *return_value TSRMLS_DC); void tracing_callgraph_get_parent_child_name(xhprof_callgraph_bucket *bucket, char *symbol, size_t symbol_len TSRMLS_DC); zend_ulong tracing_callgraph_bucket_key(xhprof_frame_t *frame); xhprof_callgraph_bucket *tracing_callgraph_bucket_find(xhprof_callgraph_bucket *bucket, xhprof_frame_t *current_frame, xhprof_frame_t *previous, zend_long key); void tracing_callgraph_bucket_free(xhprof_callgraph_bucket *bucket); void tracing_begin(zend_long flags TSRMLS_DC); void tracing_end(TSRMLS_D); void tracing_enter_root_frame(TSRMLS_D); void tracing_request_init(TSRMLS_D); void tracing_request_shutdown(); void tracing_determine_clock_source(); #define TXRG(v) ZEND_MODULE_GLOBALS_ACCESSOR(tideways_xhprof, v) #if defined(ZTS) && defined(COMPILE_DL_TIDEWAYS_XHPROF) ZEND_TSRMLS_CACHE_EXTERN() #endif static zend_always_inline void tracing_fast_free_frame(xhprof_frame_t *p TSRMLS_DC) { if (p->function_name != NULL) { zend_string_release(p->function_name); } if (p->class_name != NULL) { zend_string_release(p->class_name); } /* we use/overload the previous_frame field in the structure to link entries in * the free list. */ p->previous_frame = TXRG(frame_free_list); TXRG(frame_free_list) = p; } static zend_always_inline xhprof_frame_t* tracing_fast_alloc_frame(TSRMLS_D) { xhprof_frame_t *p; p = TXRG(frame_free_list); if (p) { TXRG(frame_free_list) = p->previous_frame; return p; } else { return (xhprof_frame_t *)emalloc(sizeof(xhprof_frame_t)); } } static zend_always_inline zend_string* tracing_get_class_name(zend_execute_data *data TSRMLS_DC) { zend_function *curr_func; if (!data) { return NULL; } curr_func = data->func; if (curr_func->common.scope != NULL) { zend_string_addref(curr_func->common.scope->name); return curr_func->common.scope->name; } return NULL; } static zend_always_inline zend_string* tracing_get_function_name(zend_execute_data *data TSRMLS_DC) { zend_function *curr_func; if (!data) { return NULL; } curr_func = data->func; if (!curr_func->common.function_name) { // This branch includes execution of eval and include/require(_once) calls // We assume it is not 1999 anymore and not much PHP code runs in the // body of a file and if it is, we are ok with adding it to the caller's wt. return NULL; } zend_string_addref(curr_func->common.function_name); return curr_func->common.function_name; } zend_always_inline static int tracing_enter_frame_callgraph(zend_string *root_symbol, zend_execute_data *execute_data TSRMLS_DC) { zend_string *function_name = (root_symbol != NULL) ? zend_string_copy(root_symbol) : tracing_get_function_name(execute_data TSRMLS_CC); xhprof_frame_t *current_frame; xhprof_frame_t *p; int recurse_level = 0; if (function_name == NULL) { return 0; } current_frame = tracing_fast_alloc_frame(TSRMLS_C); current_frame->class_name = (root_symbol == NULL) ? tracing_get_class_name(execute_data TSRMLS_CC) : NULL; current_frame->function_name = function_name; current_frame->previous_frame = TXRG(callgraph_frames); current_frame->recurse_level = 0; current_frame->wt_start = time_milliseconds(TXRG(clock_source), TXRG(timebase_factor)); if (TXRG(flags) & TIDEWAYS_XHPROF_FLAGS_CPU) { current_frame->cpu_start = cpu_timer(); } if (TXRG(flags) & TIDEWAYS_XHPROF_FLAGS_MEMORY_PMU) { current_frame->pmu_start = zend_memory_peak_usage(0 TSRMLS_CC); } if (TXRG(flags) & TIDEWAYS_XHPROF_FLAGS_MEMORY_MU) { current_frame->mu_start = zend_memory_usage(0 TSRMLS_CC); } current_frame->num_alloc = TXRG(num_alloc); current_frame->num_free = TXRG(num_free); current_frame->amount_alloc = TXRG(amount_alloc); /* We only need to compute the hash for the function name, * that should be "good" enough, we sort into 1024 buckets only anyways */ current_frame->hash_code = ZSTR_HASH(function_name) % TIDEWAYS_XHPROF_CALLGRAPH_COUNTER_SIZE; /* Update entries linked list */ TXRG(callgraph_frames) = current_frame; if (TXRG(function_hash_counters)[current_frame->hash_code] > 0) { /* Find this symbols recurse level */ for(p = current_frame->previous_frame; p; p = p->previous_frame) { if (zend_string_equals(current_frame->function_name, p->function_name) && (!current_frame->class_name || current_frame->class_name == p->class_name)) { recurse_level = (p->recurse_level) + 1; break; } } } TXRG(function_hash_counters)[current_frame->hash_code]++; /* Init current function's recurse level */ current_frame->recurse_level = recurse_level; return 1; } zend_always_inline static void tracing_exit_frame_callgraph(TSRMLS_D) { xhprof_frame_t *current_frame = TXRG(callgraph_frames); xhprof_frame_t *previous = current_frame->previous_frame; zend_long duration = time_milliseconds(TXRG(clock_source), TXRG(timebase_factor)) - current_frame->wt_start; zend_ulong key = tracing_callgraph_bucket_key(current_frame); unsigned int slot = (unsigned int)key % TIDEWAYS_XHPROF_CALLGRAPH_SLOTS; xhprof_callgraph_bucket *bucket = TXRG(callgraph_buckets)[slot]; bucket = tracing_callgraph_bucket_find(bucket, current_frame, previous, key); if (bucket == NULL) { bucket = emalloc(sizeof(xhprof_callgraph_bucket)); bucket->key = key; bucket->child_class = current_frame->class_name ? zend_string_copy(current_frame->class_name) : NULL; bucket->child_function = zend_string_copy(current_frame->function_name); if (previous) { bucket->parent_class = previous->class_name ? zend_string_copy(current_frame->previous_frame->class_name) : NULL; bucket->parent_function = zend_string_copy(previous->function_name); bucket->parent_recurse_level = previous->recurse_level; } else { bucket->parent_class = NULL; bucket->parent_function = NULL; bucket->parent_recurse_level = 0; } bucket->count = 0; bucket->wall_time = 0; bucket->cpu_time = 0; bucket->memory = 0; bucket->memory_peak = 0; bucket->num_alloc = 0; bucket->num_free = 0; bucket->amount_alloc = 0; bucket->child_recurse_level = current_frame->recurse_level; bucket->next = TXRG(callgraph_buckets)[slot]; TXRG(callgraph_buckets)[slot] = bucket; } bucket->count++; bucket->wall_time += duration; bucket->num_alloc += TXRG(num_alloc) - current_frame->num_alloc; bucket->num_free += TXRG(num_free) - current_frame->num_free; bucket->amount_alloc += TXRG(amount_alloc) - current_frame->amount_alloc; if (TXRG(flags) & TIDEWAYS_XHPROF_FLAGS_CPU) { bucket->cpu_time += (cpu_timer() - current_frame->cpu_start); } if (TXRG(flags) & TIDEWAYS_XHPROF_FLAGS_MEMORY_MU) { bucket->memory += (zend_memory_usage(0 TSRMLS_CC) - current_frame->mu_start); } if (TXRG(flags) & TIDEWAYS_XHPROF_FLAGS_MEMORY_PMU) { bucket->memory_peak += (zend_memory_peak_usage(0 TSRMLS_CC) - current_frame->pmu_start); } TXRG(function_hash_counters)[current_frame->hash_code]--; TXRG(callgraph_frames) = TXRG(callgraph_frames)->previous_frame; tracing_fast_free_frame(current_frame TSRMLS_CC); }