pg_test_timing — 测量时序开销
pg_test_timing
[选项
...]
pg_test_timing 是一个用于测量系统上的时序开销并确认系统时间永远不会向后移动的工具。收集时序数据的速度较慢的系统可能会提供不太准确的 EXPLAIN ANALYZE
结果。
pg_test_timing 接受以下命令行选项
-d 持续时间
--duration=持续时间
指定测试持续时间(以秒为单位)。持续时间越长,准确性越好,并且更有可能发现系统时钟向后移动的问题。默认测试持续时间为 3 秒。
-V
--version
打印 pg_test_timing 版本并退出。
-?
--help
显示有关 pg_test_timing 命令行参数的帮助,然后退出。
良好的结果将显示大多数(>90%)单独的时序调用耗时不到一微秒。每个循环的平均开销将更低,低于 100 纳秒。此示例来自使用 TSC 时钟源的 Intel i7-860 系统,显示了卓越的性能
Testing timing overhead for 3 seconds. Per loop time including overhead: 35.96 ns Histogram of timing durations: < us % of total count 1 96.40465 80435604 2 3.59518 2999652 4 0.00015 126 8 0.00002 13 16 0.00000 2
请注意,每个循环时间与直方图使用不同的单位。此循环可以在几纳秒 (ns) 内具有分辨率,而单独的时序调用只能解析到一微秒 (us)。
当查询执行器使用 EXPLAIN ANALYZE
运行语句时,将对各个操作进行计时以及显示摘要。可使用 psql 程序通过计数行来检查系统开销
CREATE TABLE t AS SELECT * FROM generate_series(1,100000); \timing SELECT COUNT(*) FROM t; EXPLAIN ANALYZE SELECT COUNT(*) FROM t;
所测量的 i7-860 系统在 9.8 毫秒内运行计数查询,而 EXPLAIN ANALYZE
版本耗时 16.6 毫秒,两者都仅处理了 100,000 多行。这 6.8 毫秒的差异意味着每行的时序开销为 68 纳秒,大约是 pg_test_timing 估计值的两倍。即使是如此相对较小的开销,也会使时序计算语句的执行时间延长将近 70%。对于更大的查询,时序开销问题会更小。
在某些较新的 Linux 系统上,可以随时更改用于收集时序数据的时钟源。第二个示例显示了在相同系统(用于上面快速结果的系统)上切换到较慢的 acpi_pm 时间源后可能造成的减速
# cat /sys/devices/system/clocksource/clocksource0/available_clocksource tsc hpet acpi_pm # echo acpi_pm > /sys/devices/system/clocksource/clocksource0/current_clocksource # pg_test_timing Per loop time including overhead: 722.92 ns Histogram of timing durations: < us % of total count 1 27.84870 1155682 2 72.05956 2990371 4 0.07810 3241 8 0.01357 563 16 0.00007 3
在此配置中,上述 EXPLAIN ANALYZE
样例耗时 115.9 毫秒。这是 1061 纳秒的时序开销,再次是该实用工具直接度量的几倍。如此多的时序开销意味着实际查询本身只占到记录时间的极小一部分,其中大部分则花在了开销上。在此配置中,任何涉及多个时序操作的 EXPLAIN ANALYZE
总数都会因时序开销而大幅增加。
FreeBSD 也允许动态更改时间源,并且会记录有关引导期间所选计时器的信息
# dmesg | grep "Timecounter" Timecounter "ACPI-fast" frequency 3579545 Hz quality 900 Timecounter "i8254" frequency 1193182 Hz quality 0 Timecounters tick every 10.000 msec Timecounter "TSC" frequency 2531787134 Hz quality 800 # sysctl kern.timecounter.hardware=TSC kern.timecounter.hardware: ACPI-fast -> TSC
其他系统可能仅允许在引导时设置时间源。在较旧的 Linux 系统上,“时钟”内核设置是执行此类更改的唯一方法。即使在一些较新的系统上,您能看到的时钟源选项也只有“节拍”。节拍是较旧的 Linux 软件时钟实现,当它由足够快的时序硬件(如本例所示)支持时,可以具有良好的分辨率
$ cat /sys/devices/system/clocksource/clocksource0/available_clocksource jiffies $ dmesg | grep time.c time.c: Using 3.579545 MHz WALL PM GTOD PIT/TSC timer. time.c: Detected 2400.153 MHz processor. $ pg_test_timing Testing timing overhead for 3 seconds. Per timing duration including loop overhead: 97.75 ns Histogram of timing durations: < us % of total count 1 90.23734 27694571 2 9.75277 2993204 4 0.00981 3010 8 0.00007 22 16 0.00000 1 32 0.00000 1
在计算机上收集精确的计时信息通常使用具有不同精度级别的硬件时钟来完成。对于某些硬件,操作系统几乎可以直接将系统时钟时间传递给程序。系统时钟还可以从芯片中派生出来,该芯片仅提供时序中断,即在已知时间间隔内进行周期性时钟脉冲。无论哪种情况,操作系统内核都会提供一个隐藏着这些详细信息的时钟源。但是,该时钟源的精度以及其返回结果的速度会根据底层硬件而异。
不准确的时间记录可能会导致系统不稳定。非常小心地测试对时钟源的任何更改。有时会对操作系统默认设置进行更改,以优先考虑可靠性,而不是最佳精度。如果您使用的是虚拟机,请查看与之兼容的推荐时间源。在模拟计时器时,虚拟硬件面临着额外的困难,并且通常由供应商建议针对每个操作系统进行设置。
时间戳计数器 (TSC) 时钟源是当前一代 CPU 上最精确的时钟源。当操作系统支持且 TSC 时钟可靠时,这是跟踪系统时间首选的方式。TSC 无法提供精确计时源的途径有很多,这使得它变得不可靠。较旧的系统可能有 TSC 时钟,该时钟会根据 CPU 温度而变化,这使其无法用于计时。尝试在某些较老的多核 CPU 上使用 TSC,可能会导致多个内核之间报告的时间不一致。这可能会导致时间倒退,这是一个由本程序检查的问题。即使是最新的系统,也可能无法在非常激进的节能配置下提供精确的 TSC 计时。
较新的操作系统可能会检查已知的 TSC 问题,并在发现这些问题时切换到速度较慢、更稳定的时钟源。如果您的系统支持 TSC 时间但未默认为该时间,则可能是出于充分的理由将其禁用。有些操作系统可能无法正确检测到所有可能的问题,或者即使已知 TSC 不准确,也会允许使用 TSC。
高精度事件计时器 (HPET) 是在可以使用 TSC 且 TSC 不准确的系统上首选的计时器。计时器芯片本身可编程,可允许高达 100 纳秒的分辨率,但您可能在系统时钟中看不到那么高的精度。
高级配置电源接口 (ACPI) 提供了一个电源管理 (PM) 计时器,Linux 称之为 acpi_pm。从 acpi_pm 得到的时钟最能提供 300 纳秒的分辨率。
旧 PC 硬件上使用的计时器包括 8254 可编程间隔计时器 (PIT)、实时时钟 (RTC)、高级可编程中断控制器 (APIC) 计时器和 Cyclone 计时器。这些计时器的目标是毫秒精度。