{"id":15003610,"url":"https://github.com/jbboehr/php-perfidious","last_synced_at":"2026-02-09T16:08:11.624Z","repository":{"id":229579685,"uuid":"777085726","full_name":"jbboehr/php-perfidious","owner":"jbboehr","description":"Provides access to the performance monitoring counters exposed by the Linux perf_events kernel API.","archived":false,"fork":false,"pushed_at":"2024-09-28T20:06:10.000Z","size":252,"stargazers_count":5,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-30T11:46:32.811Z","etag":null,"topics":["deus-vult","linux","linux-kernel","perf","perf-events","performance","php","php-extension","php-extensions","php8"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jbboehr.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-03-25T07:03:50.000Z","updated_at":"2025-03-27T21:44:16.000Z","dependencies_parsed_at":"2024-04-07T08:21:36.881Z","dependency_job_id":"f6ce2346-078a-4903-a40d-3394b7f3a485","html_url":"https://github.com/jbboehr/php-perfidious","commit_stats":null,"previous_names":["jbboehr/php-perf","jbboehr/php-perfidious"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/jbboehr/php-perfidious","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbboehr%2Fphp-perfidious","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbboehr%2Fphp-perfidious/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbboehr%2Fphp-perfidious/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbboehr%2Fphp-perfidious/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jbboehr","download_url":"https://codeload.github.com/jbboehr/php-perfidious/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbboehr%2Fphp-perfidious/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29271899,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-09T13:47:44.167Z","status":"ssl_error","status_checked_at":"2026-02-09T13:47:43.721Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["deus-vult","linux","linux-kernel","perf","perf-events","performance","php","php-extension","php-extensions","php8"],"created_at":"2024-09-24T18:59:19.165Z","updated_at":"2026-02-09T16:08:11.592Z","avatar_url":"https://github.com/jbboehr.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# php-perfidious\n\n[![ci](https://github.com/jbboehr/php-perfidious/actions/workflows/ci.yml/badge.svg)](https://github.com/jbboehr/php-perfidious/actions/workflows/ci.yml)\n[![Codecov](https://codecov.io/gh/jbboehr/php-perfidious/graph/badge.svg?token=DSLDXIWHC5)](https://codecov.io/gh/jbboehr/php-perfidious)\n[![Coveralls](https://coveralls.io/repos/github/jbboehr/php-perfidious/badge.svg?branch=master)](https://coveralls.io/github/jbboehr/php-perfidious?branch=master)\n[![License: AGPL v3+](https://img.shields.io/badge/License-AGPL_v3%2b-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)\n![Language](https://img.shields.io/github/languages/top/jbboehr/php-perfidious)\n![Tag](https://img.shields.io/github/v/tag/jbboehr/php-perfidious)\n![stability-experimental](https://img.shields.io/badge/stability-experimental-orange.svg)\n\nThis extension provides access to the performance monitoring *counters* exposed\nby the Linux `perf_events` kernel API.\n\n## Requirements\n\nAs we are calling Linux kernel APIs, this extension will only work on **Linux**.\n\n* PHP 8.1 - 8.3\n* libcap\n* libpfm4\n\n## Installation\n\n### Source\n\nYou will need a few packages, including libcap and libpfm4. On Ubuntu and\nDebian, this should be:\n\n```bash\napt install build-essential libcap-dev libpfm4-dev php-dev\n```\n\nNow clone the repo and compile the extension:\n\n```bash\ngit clone https://github.com/jbboehr/php-perfidious.git\ncd php-perfidious\nphpize\n./configure\nmake\nmake test\nsudo make install\n````\n\nAdd the extension to your *php.ini*:\n\n```ini\necho extension=perfidious.so | tee -a /path/to/your/php.ini\n```\n\nFinally, *restart the web server*.\n\n## Usage\n\nSee also the [`examples`](./examples) directory and the [`stub`](./perfidious.stub.php).\n\nFor example, you can programmatically open and access the counters.\n\n```php\n$handle = Perfidious\\open([\"perf::PERF_COUNT_SW_CPU_CLOCK:u\"]);\n$handle-\u003eenable();\n\nfor ($i = 0; $i \u003c 3; $i++) {\n    var_dump($handle-\u003ereadArray());\n    sleep(1);\n}\n```\n\n```text\narray(1) {\n  [\"perf::PERF_COUNT_SW_CPU_CLOCK:u\"]=\u003e\n  int(3190)\n}\narray(1) {\n  [\"perf::PERF_COUNT_SW_CPU_CLOCK:u\"]=\u003e\n  int(51270)\n}\narray(1) {\n  [\"perf::PERF_COUNT_SW_CPU_CLOCK:u\"]=\u003e\n  int(86560)\n}\n```\n\nOr you can configure a global or per-request handle:\n\n```php\n// with the following INI settings:\n// perfidious.request.enable=1\n// perfidious.request.metrics=perf::PERF_COUNT_SW_CPU_CLOCK:u,perf::PERF_COUNT_SW_PAGE_FAULTS:u,perf::PERF_COUNT_SW_CONTEXT_SWITCHES:u\nvar_dump(Perfidious\\request_handle()?-\u003eread());\n```\n\n```text\nobject(Perfidious\\ReadResult)#%d (%d) {\n  [\"timeEnabled\"]=\u003e\n  int(260840)\n  [\"timeRunning\"]=\u003e\n  int(260840)\n  [\"values\"]=\u003e\n  array(3) {\n    [\"perf::PERF_COUNT_SW_CPU_CLOCK:u\"]=\u003e\n    int(142740)\n    [\"perf::PERF_COUNT_SW_PAGE_FAULTS:u\"]=\u003e\n    int(64)\n    [\"perf::PERF_COUNT_SW_CONTEXT_SWITCHES:u\"]=\u003e\n    int(0)\n  }\n}\n```\n\n## Events\n\nWe use the libpfm4 event name encoding to open events. To see a list of all events,\nexecute [examples/all-events.php](examples/all-events.php) with the extension loaded\nor see the [libpfm4 documentation](https://perfmon2.sourceforge.net/docs_v4.html).\nSome notable generic perf events are:\n\n* `perf::PERF_COUNT_HW_CPU_CYCLES:u`\n* `perf::PERF_COUNT_HW_INSTRUCTIONS:u`\n* `perf::PERF_COUNT_SW_PAGE_FAULTS:u`\n* `perf::PERF_COUNT_SW_CONTEXT_SWITCHES:u`\n\n## Configuration\n\n| Name | Default | Changeable | Description  |\n| --------------------- | -------- | ----------- | ------------ |\n| `perfidious.global.enable` | `0` | `PHP_INI_SYSTEM` | Set to `1` to enable the global handle. This handle is kept open between requests. You can read from this handle via e.g. `var_dump(Perfidious\\global_handle()?-\u003eread());`. |\n| `perfidious.global.metrics` | `perf::PERF_COUNT_HW_CPU_CYCLES:u`, `perf::PERF_COUNT_HW_INSTRUCTIONS:u`  | `PHP_INI_SYSTEM` | The metrics to monitor with the global handle. |\n| `perfidious.overflow_mode` | `0` | `PHP_INI_SYSTEM` | Sets the overflow behavior when casting counters from `uint64_t` to `zend_long`. See the constants `Perfidious\\OVERFLOW_*` for other values. Note that when set to `Perfidious\\OVERFLOW_WARN`, `read` and `readArray` may return `NULL`, despite their type signatures indicating otherwise. |\n| `perfidious.request.enable` | `0` | `PHP_INI_SYSTEM` | Set to `1` to enable the per-request handle. This handle is kept open between requests, but reset before and after. You can read from this handle via e.g. `var_dump(Perfidious\\request_handle()?-\u003eread());` |\n| `perfidious.request.metrics` | `perf::PERF_COUNT_HW_CPU_CYCLES:u`, `perf::PERF_COUNT_HW_INSTRUCTIONS:u`  | `PHP_INI_SYSTEM` | The metrics to monitor with the request handle. |\n\n## Troubleshooting\n\n**Q:** I get an error `pid greater than zero and CAP_PERFMON not set`\n\n**A:** You need to grant `CAP_PERFMON` when monitoring a process other than the\ncurrent process, for example:\n\n```bash\nsudo capsh --caps=\"cap_perfmon,cap_setgid,cap_setuid,cap_setpcap+eip\" \\\n  --user=`whoami` \\\n  --addamb='cap_perfmon' \\\n  -- -c 'php -d extension=modules/perfidious.so examples/watch.php --interval 2 --pid 1'\n```\n\n**Q:** I get an error like\n`perf_event_open() failed for perf::PERF_COUNT_HW_INSTRUCTIONS: Permission denied`\n\n**A:** You may need to adjust `kernel.perf_event_paranoid`, for example:\n\n```bash\nsudo sysctl -w kernel.perf_event_paranoid=1\n```\n\n**Q:** I get an error like\n`perf_event_open() failed for perf::PERF_COUNT_SW_DUMMY: Operation not permitted`\nwhen running inside of docker.\n\n**A:** You may need to run your docker container with CAP_PERFMON:\n\n```bash\ndocker run --rm -ti --cap-add CAP_PERFMON\n```\n\nIf it still doesn't work, and you're running an older release of docker, see\n[this issue](https://github.com/docker/cli/issues/3960).\n\n**Q:** I get an error like\n`perf_event_open() failed for perf::PERF_COUNT_HW_INSTRUCTIONS: No such file or directory`\n\n**A:** If you are using GitHub Actions, or on some other kind of virtualization,\nperf events may not be supported. For GitHub Actions, see\n[this issue](https://github.com/actions/runner-images/issues/4974)\n\n**Q:** I'm able to read data, but the counters are all zero.\n\n**A:** This may happen for a few reasons:\n\n1. If you are monitoring several hardware events (e.g.\n`perf::PERF_COUNT_HW_INSTRUCTIONS`), the PMU may not have enough capacity to\nhandle all of them. The limit appears to be per physical CPU core. In testing\non my Zen4 CPU, it appeared that the maximum hardware counters was around 4-6.\nIf you have any more information on how to tell how many \"slots\" are available,\nplease let me know.\n\n2. If, for some reason, the kernel is unable to schedule all events in the\ngroup, it will not schedule any of them. Try removing events until you get\nsome non-zero data, or opening separate handles. Note also that some events\nmay be low-frequency.\n\n## References\n\n* [Linux perf Wiki](https://perf.wiki.kernel.org/index.php/Main_Page)\n* [man perf_events_open](https://man7.org/linux/man-pages/man2/perf_event_open.2.html)\n* [libpfm4 Documentation](https://perfmon2.sourceforge.net/docs_v4.html)\n* [HHVM perf-event](https://github.com/facebook/hhvm/blob/master/hphp/util/perf-event.cpp)\n\n## License\n\nThis project is licensed under the [AGPLv3.0 or later](LICENSE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjbboehr%2Fphp-perfidious","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjbboehr%2Fphp-perfidious","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjbboehr%2Fphp-perfidious/lists"}