- Notifications
You must be signed in to change notification settings - Fork69
low-overhead sampling profiler for PHP 7+
License
NotificationsYou must be signed in to change notification settings
adsr/phpspy
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
phpspy is a low-overhead sampling profiler for PHP. It works with non-ZTS PHP7.0+ with CLI, Apache, and FPM SAPIs on 64-bit Linux 3.2+.
You can profile PHP scripts:
You can attach to running PHP processes:
It has a top-like mode:
It can collect request info, memory usage, and variables:
You can also use it to make flamegraphs like this:
All with no changes to your application and minimal overhead.
$ git clone https://github.com/adsr/phpspy.gitCloning into 'phpspy'......$ cd phpspy$ make...$ sudo ./phpspy --limit=1000 --pid=$(pgrep -n httpd) >traces...$ ./stackcollapse-phpspy.pl <traces | ./vendor/flamegraph.pl >flame.svg$ google-chrome flame.svg # View flame.svg in browser$ make # Use built-in structs$ # or$ USE_ZEND=1 make ... # Use Zend structs (requires PHP development headers)$ ./phpspy -hUsage: phpspy [options] -p <pid> phpspy [options] -P <pgrep-args> phpspy [options] [--] <cmd>Options: -h, --help Show this help -p, --pid=<pid> Trace PHP process at `pid` -P, --pgrep=<args> Concurrently trace processes that match pgrep `args` (see also `-T`) -T, --threads=<num> Set number of threads to use with `-P` (default: 16) -s, --sleep-ns=<ns> Sleep `ns` nanoseconds between traces (see also `-H`) (default: 10101010) -H, --rate-hz=<hz> Trace `hz` times per second (see also `-s`) (default: 99) -V, --php-version=<ver> Set PHP version (default: auto; supported: 70 71 72 73 74 80 81 82) -l, --limit=<num> Limit total number of traces to capture (approximate limit in pgrep mode) (default: 0; 0=unlimited) -i, --time-limit-ms=<ms> Stop tracing after `ms` milliseconds (second granularity in pgrep mode) (default: 0; 0=unlimited) -n, --max-depth=<max> Set max stack trace depth (default: -1; -1=unlimited) -r, --request-info=<opts> Set request info parts to capture (q=query c=cookie u=uri p=path capital=negation) (default: QCUP; none) -m, --memory-usage Capture peak and current memory usage with each trace (requires target PHP process to have debug symbols) -o, --output=<path> Write phpspy output to `path` (default: -; -=stdout) -O, --child-stdout=<path> Write child stdout to `path` (default: phpspy.%d.out) -E, --child-stderr=<path> Write child stderr to `path` (default: phpspy.%d.err) -x, --addr-executor-globals=<hex> Set address of executor_globals in hex (default: 0; 0=find dynamically) -a, --addr-sapi-globals=<hex> Set address of sapi_globals in hex (default: 0; 0=find dynamically) -1, --single-line Output in single-line mode -b, --buffer-size=<size> Set output buffer size to `size`. Note: In `-P` mode, setting this above PIPE_BUF (4096) may lead to interlaced writes across threads unless `-J m` is specified. (default: 4096) -f, --filter=<regex> Filter output by POSIX regex (default: none) -F, --filter-negate=<regex> Same as `-f` except negated -d, --verbose-fields=<opts> Set verbose output fields (p=pid t=timestamp capital=negation) (default: PT; none) -c, --continue-on-error Attempt to continue tracing after encountering an error -#, --comment=<any> Ignored; intended for self-documenting commands -@, --nothing Ignored -v, --version Print phpspy version and exitExperimental options: -j, --event-handler=<handler> Set event handler (fout, callgrind) (default: fout) -J, --event-handler-opts=<opts> Set event handler options (fout: m=use mutex to prevent interlaced writes on stdout in `-P` mode) -S, --pause-process Pause process while reading stacktrace (unsafe for production!) -e, --peek-var=<varspec> Peek at the contents of the var located at `varspec`, which has the format: <varname>@<path>:<lineno> <varname>@<path>:<start>-<end> e.g., xyz@/path/to.php:10-20 -g, --peek-global=<glospec> Peek at the contents of a global var located at `glospec`, which has the format: <global>.<key> where <global> is one of: post|get|cookie|server|files|globals e.g., server.REQUEST_TIME -t, --top Show dynamic top-like output$ sudo ./phpspy -e 'i@/var/www/test/lib/test.php:12' -p $(pgrep -n httpd) | grep varpeek# varpeek i@/var/www/test/lib/test.php:12 = 42# varpeek i@/var/www/test/lib/test.php:12 = 42# varpeek i@/var/www/test/lib/test.php:12 = 43# varpeek i@/var/www/test/lib/test.php:12 = 44...$ sudo ./phpspy -H1 -T4 -P '-x php'0 proc_open <internal>:-11 system_with_timeout /home/adam/php-src/run-tests.php:11372 run_test /home/adam/php-src/run-tests.php:19373 run_all_tests /home/adam/php-src/run-tests.php:12154 <main> /home/adam/php-src/run-tests.php:986# - - - - -...^Cmain_pgrep finished gracefully$ sudo ./phpspy -p $(pgrep -n httpd)0 Memcached::get <internal>:-11 Cache_MemcachedToggleable::get /foo/bar/lib/Cache/MemcachedToggleable.php:262 Cache_Memcached::get /foo/bar/lib/Cache/Memcached.php:2513 IpDb_CacheBase::getFromCache /foo/bar/lib/IpDb/CacheBase.php:1654 IpDb_CacheBase::get /foo/bar/lib/IpDb/CacheBase.php:1075 IpDb_CacheBase::contains /foo/bar/lib/IpDb/CacheBase.php:706 IpDb_Botnet::has /foo/bar/lib/IpDb/Botnet.php:327 Security_Rule_IpAddr::__construct /foo/bar/lib/Security/Rule/IpAddr.php:538 Security_Rule_HttpRequestContext::initVariables /foo/bar/lib/Security/Rule/HttpRequestContext.php:229 Security_Rule_Context::__construct /foo/bar/lib/Security/Rule/Context.php:4410 Security_Rule_Engine::getContextByName /foo/bar/lib/Security/Rule/Engine.php:22511 Security_Rule_Engine::getContextByLocation /foo/bar/lib/Security/Rule/Engine.php:21012 Security_Rule_Engine::evaluateActionRules /foo/bar/lib/Security/Rule/Engine.php:11613 <main> /foo/bar/lib/bootstrap/api.php:4914 <main> /foo/bar/htdocs/v3/public.php:5# - - - - -...$ ./phpspy -- php -r 'usleep(100000);'0 usleep <internal>:-11 <main> <internal>:-10 usleep <internal>:-11 <main> <internal>:-10 usleep <internal>:-11 <main> <internal>:-10 usleep <internal>:-11 <main> <internal>:-10 usleep <internal>:-11 <main> <internal>:-10 usleep <internal>:-11 <main> <internal>:-1process_vm_readv: No such process$ php -r 'sleep(10);' &[1] 28586$ sudo ./phpspy -p 285860 sleep <internal>:-11 <main> <internal>:-1...$ docker build . -t phpspy$ docker run -it --cap-add SYS_PTRACE phpspy:latest ./phpspy/phpspy -V73 -r -- php -r 'sleep(1);'0 sleep <internal>:-11 <main> <internal>:-1...- phpspy may not work with a chrooted mod_php process whose binary lives inside overlayfs. (See#109.)
- rbspy for Ruby, the original inspiration for phpspy
- py-spy for Python
- Xdebug profiler, instrumented profiler
- php-profiler, similar to phpspy but pure PHP
- sample_prof
- php-trace
- Blackfire, commercial
- Tideways, commercial
- See
grep -ri todo - Seehttps://github.com/adsr/phpspy/issues
About
low-overhead sampling profiler for PHP 7+
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
No packages published
Uh oh!
There was an error while loading.Please reload this page.
Contributors13
Uh oh!
There was an error while loading.Please reload this page.





