NoiseByNorthwest/php-spx
GitHub: NoiseByNorthwest/php-spx
SPX 是一个轻量级 PHP 性能分析扩展,提供内置 Web UI 并完整保留调用栈上下文,用于定位脚本执行中的时间和内存瓶颈。
Stars: 2619 | Forks: 105
# SPX - 一个简单的 PHP 性能分析器
[][:link-ci:]



[][:link-license:]
[点击这里查看分析界面的实时演示](https://noisebynorthwest.github.io/php-spx/demo/report.html?key=spx-full-20191229_175636-06d2fe5ee423-3795-233665123)


SPX,即 _Simple Profiling eXtension_,是又一个 PHP 的性能分析扩展。
它与其他类似扩展的不同之处在于:
* 完全免费且仅限于你自己的基础设施(即没有数据泄露给 SaaS)。
* 非常易于使用:只需设置一个环境变量(命令行)或打开一个单选按钮(web 请求)即可分析你的脚本。因此,你可以免于:
* 手动插桩你的代码(甚至支持通过 Ctrl-C 中断长时间运行的命令行脚本)。
* 使用专门的浏览器扩展或命令行启动器。
* 支持[多指标](#available-metrics):目前支持 22 个(各种时间和内存指标、包含的文件、正在使用的对象、I/O...)。
* 能够在不丢失上下文的情况下收集数据。例如,Xhprof(及其潜在的分支)按调用者/被调用者对聚合数据,这意味着丢失了完整的调用栈,并禁止了基于时间线或 Flamegraph 的分析。
* 自带 [web UI](#web-ui),允许:
* 为当前浏览器会话启用/配置性能分析
* 列出已分析的脚本报告
* 选择报告进行深入分析,具有以下交互式可视化功能:
* 时间线(可扩展至数百万次函数调用)
* 平坦分析
* Flamegraph
## 要求
目前平台支持相当有限。如果你的平台不受支持,请随时提交 issue。
目前的要求是:
* x86-64 或 ARM64
* **GNU/Linux**、**macOS** 或 **FreeBSD**
* zlib 开发包(例如基于 Debian 的发行版上的 zlib1g-dev)
* PHP 5.4 到 8.5
## 安装
### 前置条件
* PHP 开发包(与你安装的 PHP 版本相对应)。
* zlib 开发包:
* 对于基于 Debian 的发行版(包括 Ubuntu、Kubuntu...),只需运行:`sudo apt-get install zlib1g-dev`。
* 对于基于 Fedora 的发行版(包括 CentOS、AlmaLinux、Rocky Linux...),只需运行:`sudo dnf install zlib-devel`。
### 安装扩展
#### 通过 PIE 安装
```
pie install noisebynorthwest/php-spx
```
#### 从源码安装
```
git clone https://github.com/NoiseByNorthwest/php-spx.git
cd php-spx
git checkout release/latest
phpize
./configure
make
sudo make install
```
#### 激活并配置 SPX
安装 SPX 后,将 `extension=spx.so` 添加到你的 *php.ini* 中,或者在包含目录中创建一个专门的 *spx.ini* 文件。
你可能还需要覆盖[默认 SPX 配置](#configuration)以便能够分析 web 请求,例如在本地开发环境中使用[这个配置](#private-environment)。
### ZTS PHP(多线程)
支持 ZTS PHP,但有以下额外限制:
- 即使未启用,加载 SPX 时也会增加一点开销(在大多数情况下理论上是不引人注意的)。
- 对 CLI 脚本使用 Ctrl-C 将无法使可能正在进行的性能分析会话正常结束。
- 发生段错误的可能性比 NTS PHP 更高。在这方面,比以往任何时候都更要避免将 SPX 与其他插桩扩展(调试器、分析器...)混合使用。
此外,ZTS PHP 的支持仍处于测试阶段。
### Linux、PHP-FPM 和 I/O 统计
在 GNU/Linux 上,SPX 使用 procfs(即通过读取 `/proc` 目录下的文件)来获取当前进程或线程的一些统计信息。这是当你至少选择以下指标之一:`mor`、`io`、`ior` 或 `iow` 时在底层所做的操作。
但是,在大多数 PHP-FPM 设置中,你会遇到权限问题,阻止 SPX 打开 `/proc/self` 目录下的文件。
这是因为 PHP-FPM 主进程以 root 用户身份运行,而子进程以其他非特权用户身份运行。
在这种情况下,必须将 `process.dumpable = yes` 行添加到 FPM 池配置中,以便子进程能够读取 `/proc/self` 下的任何文件。
## 开发状态
这仍然是**实验性**的。API 可能会更改,功能可能会添加或删除,或者开发可能会冻结。
你仍然可以在**非生产**环境中安全地使用它。
欢迎贡献,但请注意本项目的实验状态,并**请遵循**此处描述的贡献规则:[CONTRIBUTING.md](CONTRIBUTING.md)
## 基本用法
### Web 请求
假设开发环境具有[此处描述](#private-environment)的配置,并且你的应用程序可以通过 `http://localhost` 访问。
只需使用浏览器打开以下 URL:`http://localhost/?SPX_KEY=dev&SPX_UI_URI=/` 即可访问 web UI [控制面板](#control-panel)。
_注意:`http://localhost/` 必须通过目录索引或 URL 重写等标准 web 服务器功能由 PHP 脚本提供服务。然而,该 PHP 脚本不会被执行,SPX 将拦截并禁用其执行,转而提供其自身的内容。_
_如果你只看到空白页,请确保在 PHP 配置文件中设置 `zlib.output_compression = 0`_
然后你将看到以下表单:

然后打开“Enabled”。此时,将通过一组专用的 cookie 为当前域名和你当前的浏览器会话启用性能分析。
也可以像此示例所示那样使用 Curl 触发性能分析:
`curl --cookie "SPX_ENABLED=1; SPX_KEY=dev" http://localhost/`
_注意:你也可以通过 `spx.http_profiling_enabled` [设置](#configuration)在 INI 配置级别为所有 HTTP 请求启用性能分析。但是,请记住,在高流量环境中使用此设置可能会迅速耗尽 SPX 数据目录的存储设备容量。_
然后刷新你要分析的 web 请求,并刷新控制面板,以在控制面板表单下方的列表中查看生成的报告。

然后点击列表中的报告,享受 [分析界面](#analysis-screen)。
### 命令行脚本
#### 即时平坦分析
只需在你的命令前加上 `SPX_ENABLED=1` 即可触发性能分析。在执行结束时,你将在 STDERR 上看到打印的平坦分析,即使你通过按 Ctrl-C 中止它,如以下示例所示:
```
$ SPX_ENABLED=1 composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
^C
*** SPX Report ***
Global stats:
Called functions : 27.5K
Distinct functions : 714
Wall time : 7.39s
ZE memory : 62.6MB
Flat profile:
Wall time | ZE memory |
Inc. | *Exc. | Inc. | Exc. | Called | Function
----------+----------+----------+----------+----------+----------
101.6ms | 101.6ms | 41.8MB | 41.8MB | 12 | Composer\Json\JsonFile::parseJson
53.6ms | 53.6ms | 544B | 544B | 4 | Composer\Cache::sha256
6.91s | 41.5ms | 41.5MB | -7.5MB | 4 | Composer\Repository\ComposerRepository::fetchFile
6.85s | 32.3ms | 47.5MB | 5.4MB | 5 | 1@Composer\Repository\ComposerRepository::loadProviderListings
7.8ms | 7.8ms | 0B | 0B | 4 | Composer\Cache::write
1.1ms | 1.1ms | -72B | -72B | 1 | Composer\Console\Application::Composer\Console\{closure}
828.5us | 828.5us | 976B | 976B | 12 | Composer\Util\RemoteFilesystem::findHeaderValue
497.6us | 491.0us | 710.2KB | 710.2KB | 1 | Composer\Cache::read
2.4ms | 332.6us | 20.9KB | -378.8KB | 34 | 3@Symfony\Component\Finder\Iterator\FilterIterator::rewind
298.9us | 298.9us | 2.2KB | 2.2KB | 47 | Symfony\Component\Finder\Iterator\FileTypeFilterIterator::accept
```
注意:只需添加 `SPX_FP_LIVE=1` 即可在脚本执行期间启用平坦分析的实时刷新。
#### 为 web UI 生成性能分析报告
你只需指定 `SPX_REPORT=full` 即可生成可通过 web UI 访问的报告:
```
SPX_ENABLED=1 SPX_REPORT=full ./bin/console cache:clear
```
#### 处理长时间运行/守护进程
如果你的 CLI 脚本长时间运行和/或被守护(例如通过 supervisord),分析其整个生命周期可能没有意义。对于等待处理任务的服务来说尤其如此。
为了处理这种情况,SPX 允许禁用性能分析的自动启动,并公开了 2 个用户态函数 `spx_profiler_start(): void` 和 `spx_profiler_stop(): ?string`,以便分别控制已分析区间的开始和结束。
以下是如何对你的脚本进行插桩的方法:
```
process();
} finally {
spx_profiler_stop();
}
}
```
当然,运行此脚本时必须至少启用性能分析并禁用自动启动,如以下命令所示:
```
SPX_ENABLED=1 SPX_REPORT=full SPX_AUTO_START=0 my_script.php
```
对于 web 请求,也可以通过 `spx.http_profiling_auto_start` INI 参数或通过控制面板禁用自动启动。
旁注:
- `spx_profiler_start()` 和 `spx_profiler_stop()` 可以安全地嵌套。
- 当使用 _full_ 报告类型进行分析时,`spx_profiler_stop()` 返回报告密钥,以便你能够将其存储在某个地方,例如与已分析区间相关的其他信息中。使用报告密钥,你可以构建以该模式 `/?SPX_UI_URI=/report.html&key=` 结尾的分析界面 URL。
- 在 CLI 上下文中,当禁用自动启动时,SPX 不会注册任何信号处理程序(即针对 SIGINT/SIGTERM 的处理)。
#### 向当前完整报告添加自定义元数据
当使用 _full_ 报告作为输出进行性能分析时,将自定义元数据添加到当前报告中可能会很方便,以便你能够轻松检索它或将其与其他类似报告区分开来。
对于长时间运行的进程用例来说尤其如此,否则将无法区分同一进程的其他报告。
为此,SPX 提供了 `spx_profiler_full_report_set_custom_metadata_str(string $customMetadataStr): void` 函数。
你可能已经注意到,出于 SPX 端灵活性和简单性的考虑,此函数接受字符串作为自定义元数据。你可以自行将任何结构化数据编码为字符串,例如使用 JSON 格式。
元数据字符串限制为 4KB,这对于大多数用例来说已经足够了。如果你传递的字符串超过此限制,它将被丢弃并发出通知日志。
此字符串将与其他当前报告的元数据一起存储,你将在 web UI 端的报告列表中检索到它。
只要分析器已经启动且尚未结束,就可以随时调用 `spx_profiler_full_report_set_custom_metadata_str()`,这意味着:
- 启用自动启动(默认模式)时,在脚本执行期间的任何时刻。
- 禁用自动启动时,在调用 `spx_profiler_start()` 之后和调用 `spx_profiler_stop()` 之前的任何时刻。
这是一个示例:
```
$task->getId(),
]
));
try {
$task->process();
} finally {
spx_profiler_stop();
}
}
```
## 高级用法
### 配置
| 名称 | 默认值 | 可修改范围 | 描述 |
| --------------------- | -------- | ----------- | ------------ |
| _spx.data_dir_ | `/tmp/spx` | _PHP_INI_SYSTEM_ | 存储性能分析报告的目录。例如,在多服务器架构的情况下,你可以将其更改为指向共享文件系统。 |
| _spx.http_enabled_ | `0` | _PHP_INI_SYSTEM_ | 是否启用 web UI 和 HTTP 请求分析。 |
| _spx.http_key_ | | _PHP_INI_SYSTEM_ | 用于身份验证的密钥(有关更多详细信息,请参见[安全问题](#security-concern))。你可以使用以下命令生成一个 16 字节的随机十六进制字符串密钥:`openssl rand -hex 16`。 |
| _spx.http_ip_var_ | `REMOTE_ADDR` | _PHP_INI_SYSTEM_ | 包含用于身份验证的客户端 IP 地址的 `$_SERVER` 键(有关更多详细信息,请参见[安全问题](#security-concern))。当你的应用程序位于反向代理后面时,需要覆盖默认值。 |
| _spx.http_trusted_proxies_ | `127.0.0.1` | _PHP_INI_SYSTEM_ | 受信任的代理列表,表示为以逗号分隔的 IP 地址列表*。当 `spx.http_ip_var` 的值为 `REMOTE_ADDR` 时,此设置将被忽略。 |
| _spx.http_ip_whitelist_ | | _PHP_INI_SYSTEM_ | 用于身份验证的 IP 地址白名单,表示为以逗号分隔的 IP 地址列表*。 |
| _spx.http_ui_assets_dir_ | `/usr/local/share/misc/php-spx/assets/web-ui` | _PHP_INI_SYSTEM_ | 安装 [web UI](#web-ui) 文件的目录。在大多数情况下,你不必更改它。 |
| _spx.http_profiling_enabled_ | _NULL_ | _PHP_INI_SYSTEM_ | `SPX_ENABLED` 参数在 INI 级别的对应项,仅适用于 HTTP 请求。[详见此处](#available-parameters)。 |
| _spx.http_profiling_auto_start_ | _NULL_ | _PHP_INI_SYSTEM_ | `SPX_AUTO_START` 参数在 INI 级别的对应项,仅适用于 HTTP 请求。[详见此处](#available-parameters)。 |
| _spx.http_profiling_builtins_ | _NULL_ | _PHP_INI_SYSTEM_ | `SPX_BUILTINS` 参数在 INI 级别的对应项,仅适用于 HTTP 请求。[详见](#available-parameters)。 |
| _spx.http_profiling_sampling_period_ | _NULL_ | _PHP_INI_SYSTEM_ | `SPX_SAMPLING_PERIOD` 参数在 INI 级别的对应项,仅适用于 HTTP 请求。[详见此处](#available-parameters)。 |
| _spx.http_profiling_depth_ | _NULL_ | _PHP_INI_SYSTEM_ | `SPX_DEPTH` 参数在 INI 级别的对应项,仅适用于 HTTP 请求。[详见此处](#available-parameters)。 |
| _spx.http_profiling_metrics_ | _NULL_ | _PHP_INI_SYSTEM_ | `SPX_METRICS` 参数在 INI 级别的对应项,仅适用于 HTTP 请求。[详见此处](#available-parameters)。 |
_\*: 支持 `*`(匹配所有)和子网掩码(例如 `192.168.1.0/24`)。_
#### 私有环境
对于你的本地和私有开发环境,由于不需要身份验证,你可以使用以下配置:
```
spx.http_enabled=1
spx.http_key="dev"
spx.http_ip_whitelist="127.0.0.1"
```
然后通过 `http(s):///?SPX_KEY=dev&SPX_UI_URI=/` 访问 web UI。
### 可用指标
以下是可用于收集的指标列表。默认情况下,仅收集 _Wall time_ 和 _Zend Engine 内存使用量_。
| 键 (命令行) | 名称 | 描述 |
| ---- | ---------------- | ------ |
| _wt_ | Wall time | 绝对经过的时间。 |
| _ct_ | CPU 时间 | 在 CPU 上运行所花费的时间。 |
| _it_ | 空闲时间 | 在 CPU 外花费的时间,这意味着等待 CPU、I/O 完成、获取锁...或显式休眠。 |
| _zm_ | Zend Engine 内存使用量 | 等同于 `memory_get_usage(false)`。 |
| _zmac_ | Zend Engine 分配计数 | 执行的内存分配(即分配的块)数量。 |
| _zmab_ | Zend Engine 已分配字节* | 已分配的字节数。 |
| _zmfc_ | Zend Engine 释放计数 | 执行的内存释放(即释放的块)数量。 |
| _zmfb_ | Zend Engine 已释放字节* | 已释放的字节数。 |
| _zgr_ | Zend Engine GC 运行计数 | 触发 GC(循环收集器)的次数(手动或自动)。 |
| _zgb_ | Zend Engine GC 根缓冲区长度 | 根缓冲区长度,请参阅[此处](http://php.net/manual/en/features.gc.collecting-cycles.php)的解释。它有助于跟踪垃圾回收器的压力。 |
| _zgc_ | Zend Engine GC 收集循环计数 | 所有 GC 运行中收集的循环总数。 |
| _zif_ | Zend Engine 包含文件计数 | 包含的文件数量。 |
| _zil_ | Zend Engine 包含行数计数 | 包含的代码行数。 |
| _zuc_ | Zend Engine 用户类计数 | 用户态类的数量。 |
| _zuf_ | Zend Engine 用户函数计数 | 用户态函数(包括用户态类/实例方法)的数量。 |
| _zuo_ | Zend Engine 用户 opcode 计数 | 包含的用户态 opcode 数量(所有用户态文件/函数/方法 opcode 的总和)。 |
| _zo_ | Zend Engine 对象计数 | 用户代码当前持有的对象数量。 |
| _ze_ | Zend Engine 错误计数 | 引发的 PHP 错误数量。 |
| _mor_ | 进程自身的 RSS\*\* | 进程内存中保存在 RAM 中的部分。不考虑共享(与其他进程的)内存块。此指标可用于突出显示 PHP 扩展或更深层(例如第三方 C 库)内的内存泄漏。 |
| _io_ | I/O(读取 + 写入)**\*\*** | 执行 I/O 时读取或写入的字节数。 |
| _ior_ | I/O(读取)**\*\*** | 执行 I/O 时读取的字节数。 |
| _iow_ | I/O(写入)**\*\*** | 执行 I/O 时写入的字节数。 |
_\*: 如果你使用自定义分配器,或者通过将 `USE_ZEND_ALLOC` 环境变量设置为 `0` 来强制使用 libc 分配器,则不会收集已分配和已释放的字节计数。_
_\*\*: macOS 和 FreeBSD 不支持 RSS 和 I/O 指标。在 GNU/Linux 上,如果你使用 PHP-FPM,你应该[阅读此文](#linux-php-fpm--io-stats)。_
### 命令行脚本
#### 可用报告类型
与仅支持 _full_ 报告类型(可由 web UI 利用的类型)的 web 请求分析相反,命令行脚本分析支持多种报告类型。
以下是列表:
| 键 | 名称 | 描述 |
| ---- | ----- | ------------ |
| _fp_ | 平坦分析 | SPX 提供的平坦分析。它是**默认报告类型**,并直接在 STDERR 上打印。 |
| _full_ | 完整报告 | 这是 web UI 的报告类型。报告将存储在 SPX 数据目录中,因此可在 web UI 端进行分析。 |
| _trace_ | 跟踪文件 | 自定义格式(人类可读文本)的跟踪文件。 |
#### 可用参数
| 名称 | 默认值 | 描述 |
| ----- | -------- | ------------ |
| _SPX_ENABLED_ | `0` | 是否启用 SPX 分析器(即触发性能分析)。禁用时,你的应用程序不会受到任何性能影响(ZTS PHP 除外,在 ZTS PHP 中,禁用的 SPX 仍然会增加一点开销)。 |
| _SPX_AUTO_START_ | `1` | 是否启用 SPX 分析器的自动启动。当禁用自动启动时,你必须在运行时通过 `spx_profiler_start()` 和 `spx_profiler_stop()` 函数自行启动和停止性能分析。[详见此处](#handle-long-living--daemon-processes)。 |
| _SPX_BUILTINS_ | `0` | 是否分析内部函数、脚本编译、GC 运行和请求关闭。 |
| _SPX_DEPTH_ | `0` | 性能分析必须停止的堆栈深度(即聚合更深层调用的测量值)。0(默认值)表示无限制。 |
| _SPX_SAMPLING_PERIOD_ | `0` | 是否根据指定的采样周期(`0` 表示不采样)定期收集当前调用栈的数据。结果的准确性通常会降低,但在某些情况下,由于不过度评估被多次调用的小函数,结果可能要准确得多。如果你想准确找到时间瓶颈,建议尝试采样(使用不同的周期)。在分析长时间运行且 CPU 密集型的脚本时,此选项将允许你控制报告大小,从而使其保持足够小以便 [web UI](#web-ui) 能够处理。[详见此处](#performance-report-size--sampling)。 |
| _SPX_METRICS_ | `wt,zm` | 要收集的[可用指标键](#available-metrics)的逗号分隔列表。所有报告类型都利用了多指标分析。 |
| _SPX_REPORT_ | `fp` | 选定的[报告键](#available-report-types)。 |
| _SPX_FP_FOCUS_ | `wt` | 用于平坦分析排序的[指标键](#available-metrics)。 |
| _SPX_FP_INC_ | `0` | 在平坦分析中是否按包含值而不是排除值对函数进行排序。 |
| _SPX_FP_REL_ | `0` | 在平坦分析中是否以相对值(即百分比)显示指标值。 |
| _SPX_FP_LIMIT_ | `10` | 平坦分析的大小(即显示的前 N 个函数)。 |
| _SPX_FP_LIVE_ | `0` | 是否启用平坦分析实时刷新。由于它通过 ANSI 转义序列控制光标位置,因此它使用 STDOUT 作为输出,替换脚本输出(STDOUT 和 STDERR)。 |
| _SPX_FP_COLOR_ | `1` | 是否启用平坦分析颜色模式。 |
| _SPX_TRACE_SAFE_ | `0` | 默认情况下,跟踪文件的写入方式会强制保证准确性,但如果进程崩溃(例如段错误),可能会丢失一些日志。如果你想强制保证持久性(例如在崩溃前查找最后一个事件),只需将此参数设置为 1。 |
| _SPX_TRACE_FILE_ | | 自定义跟踪文件名。如果未指定,它将在 `/tmp` 中生成并在脚本结束时显示在 STDERR 上。 |
#### 设置参数
嗯,正如你可能在相应的[基本用法示例](#command-line-script)中注意到的那样,为命令行脚本设置 SPX 参数仅仅意味着设置具有相同名称的环境变量。
### Web UI
#### 支持的浏览器
由于 web UI 使用高级 JavaScript 功能,因此已知仅支持以下浏览器:
- 任何基于 Chromium 的浏览器的最新版本。
- Firefox 的最新版本。
#### 控制面板和报告列表
这是 web UI 的主页,分为 2 部分:
- 控制面板,用于为你当前的浏览器会话设置性能分析配置。
- 性能分析报告列表,显示为可排序的表格。点击某一行可转到相应报告的[分析界面](#analysis-screen)。
#### 分析界面
[点击这里查看分析界面的实时演示](https://noisebynorthwest.github.io/php-spx/demo/report.html?key=spx-full-20180603_211110-dev-3540-294703905)

##### 性能、报告大小和采样
在我的 i5 @ 3.3GHz / 8GB 台式机上使用 Chromium,分析界面可以很好地处理记录了数百万(超过 500 万)次函数调用的分析报告。
如果你想分析一个往往会生成庞大报告的长时间运行、CPU 密集型的脚本,你可以启用具有合适采样周期的采样模式。
命令行脚本请参见 _SPX_SAMPLING_PERIOD_ [参数](#available-parameters)。
##### 指标选择器
这只是一个用于选择当前分析指标的组合框。

##### 颜色方案选择器
默认情况下,可视化中与函数相关的块根据其开销着色,并在屏幕右上方显示色阶。
你还可以通过点击屏幕顶部指标选择器之后显示的颜色方案模式链接来定义自定义颜色方案。
随后将出现一个下拉窗口,允许你在 `default` 和 `category` 模式之间切换,并为 `category` 模式定义(添加/编辑/删除)你的类别(颜色、名称、模式列表)(参见下面的屏幕截图)。

##### 时间线概览
此可视化是所有调用函数的时间线概览。
你可以通过水平拖动由透明绿色矩形表示的选定时间范围来更改它。
除了 Wall time 之外,当前指标也会绘制(随时间变化的当前值)在前台图层上。
支持的控制:
- 水平左键拖动:移动选定的时间范围
- 在选定的时间范围矩形上调整大小点击:移动选定时间范围的其中一个边界

##### 时间线焦点
此可视化是一个交互式时间线,能够控制并保持对选定时间范围的焦点。
支持的控制:
- 左键拖动:时间范围移动(水平)或深度范围移动(垂直)
- 中键垂直拖动:时间范围放大/缩小
- 鼠标滚轮:时间范围放大/缩小
- 悬停在函数调用上以显示更多详细信息
- 双击函数调用:将当前时间范围设置为所选函数调用的时间范围
除了 Wall time 之外,当前指标也会绘制(随时间变化的当前值)在前台图层上。

##### 平坦分析
此可视化是选定时间范围和选定指标的平坦分析,显示为可排序的表格。
`Inc.` 和 `Exc.` 子列分别对应于:
- 该函数的包含资源消耗,包括其调用函数的消耗
- 该函数的排除资源消耗,不包括其调用函数的消耗

##### Flame Graph
此可视化由 [Brendan Gregg](http://www.brendangregg.com/flamegraphs.html) 设计,允许快速找到选定时间范围和选定指标点代码路径。
此可视化不支持与可释放资源(内存、正在使用的对象...)对应的指标。

##### 函数高亮显示
你可以通过点击时间线或 Flamegraph 小部件中函数的一个跨度,或者平坦分析小部件中它的名称来高亮显示一个函数。

## 安全问题
_关于此问题缺乏审查/反馈是 **SPX 尚不能被视为可用于生产环境** 的主要原因。_
SPX 允许你分析 web 请求以及命令行脚本,并允许通过其内置的 web UI 列出和分析性能分析报告。
这就是为什么存在巨大的安全风险的原因,因为攻击者可能会:
- 访问 web UI 并获取有关你的应用程序的敏感信息。
- 其次,通过代价高昂的性能分析设置对你的应用程序发起 DoS 攻击。
因此,除非对你的应用程序的访问已经在较低层受到限制(即在应用程序被访问之前,而不是由应用程序 / PHP 框架本身限制),否则触发性能分析或访问 web UI 的客户端必须经过身份验证。
SPX 提供了具有以下 2 个强制性锁的双因素身份验证:
* IP 地址白名单(精确字符串表示匹配)。
* 固定的随机密钥(由你自己生成),通过请求标头、cookie 或查询字符串参数提供。
因此,只有当 **其 IP 地址在白名单中并且其提供的密钥有效** 时,客户端才能通过 web 请求分析你的应用程序。
## 关于准确性的说明
在跟踪模式(默认)下,当测量的函数执行时间为以下情况时,SPX 对于与时间相关的指标会遇到准确性问题:
- 接近或低于计时器精度
- 接近或低于 SPX 自身的每个函数开销
第一个问题通过使用平台提供的最高分辨率计时器来缓解。在 Linux、FreeBSD 和最新版本的 macOS 上,计时器分辨率为 1ns;在 10.12/Sierra 之前的 macOS 上,计时器分辨率仅为 1us。
第二个问题通过在开始分析脚本之前评估 SPX 每个函数的固定开销,并将测量的函数执行时间减去 SPX 的时间(wall / cpu)开销来缓解。
但是,无论平台如何,如果你想最大化准确性以找到时间瓶颈,你还应该:
- 避免分析内部函数。
- 避免收集额外的指标。
- 尝试使用不同采样周期的采样模式。
- 尝试调整最大深度参数以在给定深度停止分析。
## Stubs
与 [Intelephense](https://www.npmjs.com/package/intelephense) 一起使用的 SPX 函数的 Stubs
```
composer require --dev 8ctopus/php-spx-stubs
```
## 致谢
我在阅读以下内容时找到了很多灵感和提示:
- [XHProf](https://github.com/phacility/xhprof)
- [Xdebug](https://github.com/xdebug/xdebug)
- [PHP](https://github.com/php/php-src)
## 许可证
**SPX** 是开源软件,根据 GNU 通用公共许可证 (GPL-3) 授权。
有关更多信息,请参见 [LICENSE][:link-license:] 文件。
标签:OpenVAS, PHP, SOC Prime, TCP SYN 扫描, Web UI, 客户端加密, 开发工具, 性能分析, 性能监控