Skip to content

pg_test_timing

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 系统上,“clock”内核设置是进行此类更改的唯一方法。即使在一些较新的系统上,您能看到的时钟源选项也只有“jiffies”。Jiffies 是较旧的 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 无法提供准确的计时源有几种方法,这使得它不可靠。较旧的系统可能具有根据 CPU 温度变化的 TSC 时钟,使其无法用于计时。尝试在一些较旧的多核 CPU 上使用 TSC 会导致多个内核之间报告的时间不一致。这可能导致时间倒退,这是本程序检查的问题。即使是最新系统,在非常激进的省电配置下也可能无法提供准确的 TSC 计时。

较新的操作系统可能会检查已知的 TSC 问题,并在发现这些问题时切换到更慢、更稳定的时钟源。如果您的系统支持 TSC 时间但未默认使用它,则可能出于充分的理由禁用了它。某些操作系统可能无法正确检测所有可能的问题,或者即使已知 TSC 不准确,也会允许使用 TSC。

高精度事件计时器 (HPET) 是在系统中 TSC 不准确时可用的首选计时器。计时器芯片本身可编程,允许高达 100 纳秒的分辨率,但您可能不会在系统时钟中看到如此高的准确度。

高级配置和电源接口 (ACPI) 提供了电源管理 (PM) 计时器,Linux 称之为 acpi_pm。从 acpi_pm 派生的时钟最多可提供 300 纳秒的分辨率。

旧 PC 硬件上使用的计时器包括 8254 可编程间隔计时器 (PIT)、实时时钟 (RTC)、高级可编程中断控制器 (APIC) 计时器和 Cyclone 计时器。这些计时器的目标是毫秒分辨率。

另请参阅

EXPLAIN