Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions doc/src/sgml/config.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -2533,6 +2533,60 @@ include_dir 'conf.d'
</variablelist>
</sect2>

<sect2 id="runtime-config-resource-time">
<title>Timing</title>

<variablelist>
<varlistentry id="guc-timing-clock-source" xreflabel="timing_clock_source">
<term><varname>timing_clock_source</varname> (<type>enum</type>)
<indexterm>
<primary><varname>timing_clock_source</varname> configuration parameter</primary>
</indexterm>
</term>
<listitem>
<para>
Selects the method for making timing measurements using the OS or specialized CPU
instructions. Possible values are:
<itemizedlist>
<listitem>
<para>
<literal>auto</literal> (automatically chooses TSC clock source for modern CPUs,
otherwise uses the OS system clock)
</para>
</listitem>
<listitem>
<para>
<literal>system</literal> (measures timing using the OS system clock)
</para>
</listitem>
<listitem>
<para>
<literal>tsc</literal> (measures timing using the x86-64 Time-Stamp Counter (TSC)
by directly executing RDTSC/RDTSCP instructions, see below)
</para>
</listitem>
</itemizedlist>
The default is <literal>auto</literal>.
</para>
<para>
If enabled, the TSC clock source will use the RDTSC instruction for the x86-64
Time-Stamp Counter (TSC) to perform certain time measurements, for example during
EXPLAIN ANALYZE. The RDTSC instruction has less overhead than going through the OS
clock source, which for an EXPLAIN ANALYZE statement will show timing closer to the
actual runtime when timing is off. For timings that require higher precision the
RDTSCP instruction is used, which avoids inaccuracies due to CPU instruction re-ordering.
Use of RDTSC/RDTSC is not supported on older CPUs or hypervisors that don't pass the TSC
frequency to guest VMs, and is not advised on systems that utilize an emulated TSC.
</para>
<para>
To help decide which clock source to use on an x86-64 system you can run the
<application>pg_test_timing</application> utility to check TSC availability, and
perform timing measurements.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>

<sect2 id="runtime-config-resource-background-writer">
<title>Background Writer</title>
Expand Down
79 changes: 77 additions & 2 deletions src/backend/executor/instrument.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ InstrStartNode(Instrumentation *instr)
if (!INSTR_TIME_IS_ZERO(instr->starttime))
elog(ERROR, "InstrStartNode called twice in a row");
else
INSTR_TIME_SET_CURRENT(instr->starttime);
INSTR_TIME_SET_CURRENT_FAST(instr->starttime);
}

/* save buffer usage totals at node entry, if needed */
Expand All @@ -99,7 +99,7 @@ InstrStopNode(Instrumentation *instr, double nTuples)
if (INSTR_TIME_IS_ZERO(instr->starttime))
elog(ERROR, "InstrStopNode called without start");

INSTR_TIME_SET_CURRENT(endtime);
INSTR_TIME_SET_CURRENT_FAST(endtime);
INSTR_TIME_ACCUM_DIFF(instr->counter, endtime, instr->starttime);

INSTR_TIME_SET_ZERO(instr->starttime);
Expand Down Expand Up @@ -294,3 +294,78 @@ WalUsageAccumDiff(WalUsage *dst, const WalUsage *add, const WalUsage *sub)
dst->wal_fpi_bytes += add->wal_fpi_bytes - sub->wal_fpi_bytes;
dst->wal_buffers_full += add->wal_buffers_full - sub->wal_buffers_full;
}

/* GUC hooks for timing_clock_source */

#include "portability/instr_time.h"
#include "utils/guc_hooks.h"

bool
check_timing_clock_source(int *newval, void **extra, GucSource source)
{
/*
* Do nothing if timing is not initialized. This is only expected on child
* processes in EXEC_BACKEND builds, as GUC hooks can be called during
* InitializeGUCOptions() before InitProcessGlobals() has had a chance to
* run pg_initialize_timing(). Instead, TSC will be initialized via
* restore_backend_variables.
*/
#ifdef EXEC_BACKEND
if (!timing_initialized)
return true;
#else
Assert(timing_initialized);
#endif

#if PG_INSTR_TSC_CLOCK
pg_initialize_timing_tsc();

if (*newval == TIMING_CLOCK_SOURCE_TSC && timing_tsc_frequency_khz <= 0)
{
GUC_check_errdetail("TSC is not supported as timing clock source");
return false;
}
#endif

return true;
}

void
assign_timing_clock_source(int newval, void *extra)
{
#ifdef EXEC_BACKEND
if (!timing_initialized)
return;
#else
Assert(timing_initialized);
#endif

/*
* Ignore the return code since the check hook already verified TSC is
* usable if its explicitly requested.
*/
pg_set_timing_clock_source(newval);
}

const char *
show_timing_clock_source(void)
{
switch (timing_clock_source)
{
case TIMING_CLOCK_SOURCE_AUTO:
#if PG_INSTR_TSC_CLOCK
if (pg_current_timing_clock_source() == TIMING_CLOCK_SOURCE_TSC)
return "auto (tsc)";
#endif
return "auto (system)";
case TIMING_CLOCK_SOURCE_SYSTEM:
return "system";
#if PG_INSTR_TSC_CLOCK
case TIMING_CLOCK_SOURCE_TSC:
return "tsc";
#endif
}

/* unreachable */
return "?";
}
17 changes: 17 additions & 0 deletions src/backend/postmaster/launch_backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@

#ifdef EXEC_BACKEND
#include "nodes/queryjumble.h"
#include "portability/instr_time.h"
#include "storage/pg_shmem.h"
#include "storage/spin.h"
#endif
Expand Down Expand Up @@ -127,6 +128,10 @@ typedef struct

int MyPMChildSlot;

#if PG_INSTR_TSC_CLOCK
int32 timing_tsc_frequency_khz;
#endif

/*
* These are only used by backend processes, but are here because passing
* a socket needs some special handling on Windows. 'client_sock' is an
Expand Down Expand Up @@ -743,6 +748,10 @@ save_backend_variables(BackendParameters *param,
param->MaxBackends = MaxBackends;
param->num_pmchild_slots = num_pmchild_slots;

#if PG_INSTR_TSC_CLOCK
param->timing_tsc_frequency_khz = timing_tsc_frequency_khz;
#endif

#ifdef WIN32
param->PostmasterHandle = PostmasterHandle;
if (!write_duplicated_handle(&param->initial_signal_pipe,
Expand Down Expand Up @@ -997,6 +1006,14 @@ restore_backend_variables(BackendParameters *param)
MaxBackends = param->MaxBackends;
num_pmchild_slots = param->num_pmchild_slots;

#if PG_INSTR_TSC_CLOCK
timing_tsc_frequency_khz = param->timing_tsc_frequency_khz;

/* Re-run logic usually done by assign_timing_clock_source */
pg_initialize_timing();
pg_set_timing_clock_source(timing_clock_source);
#endif

#ifdef WIN32
PostmasterHandle = param->PostmasterHandle;
pgwin32_initial_signal_pipe = param->initial_signal_pipe;
Expand Down
5 changes: 5 additions & 0 deletions src/backend/postmaster/postmaster.c
Original file line number Diff line number Diff line change
Expand Up @@ -1937,6 +1937,11 @@ InitProcessGlobals(void)
MyStartTimestamp = GetCurrentTimestamp();
MyStartTime = timestamptz_to_time_t(MyStartTimestamp);

/*
* Initialize timing infrastructure
*/
pg_initialize_timing();

/*
* Set a different global seed in every process. We want something
* unpredictable, so if possible, use high-quality random bits for the
Expand Down
11 changes: 11 additions & 0 deletions src/backend/utils/misc/guc_parameters.dat
Original file line number Diff line number Diff line change
Expand Up @@ -3043,6 +3043,17 @@
assign_hook => 'assign_timezone_abbreviations',
},

{ name => 'timing_clock_source', type => 'enum', context => 'PGC_USERSET', group => 'RESOURCES_TIME',
short_desc => 'Controls the clock source used for collecting timing measurements.',
long_desc => 'This enables the use of specialized clock sources, specifically the RDTSC clock source on x86-64 systems (if available), to support timing measurements with lower overhead during EXPLAIN and other instrumentation.',
variable => 'timing_clock_source',
boot_val => 'TIMING_CLOCK_SOURCE_AUTO',
options => 'timing_clock_source_options',
check_hook => 'check_timing_clock_source',
assign_hook => 'assign_timing_clock_source',
show_hook => 'show_timing_clock_source',
},

{ name => 'trace_connection_negotiation', type => 'bool', context => 'PGC_POSTMASTER', group => 'DEVELOPER_OPTIONS',
short_desc => 'Logs details of pre-authentication connection handshake.',
flags => 'GUC_NOT_IN_SAMPLE',
Expand Down
11 changes: 11 additions & 0 deletions src/backend/utils/misc/guc_tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
#include "tcop/tcopprot.h"
#include "tsearch/ts_cache.h"
#include "utils/builtins.h"
#include "portability/instr_time.h"
#include "utils/bytea.h"
#include "utils/float.h"
#include "utils/guc_hooks.h"
Expand Down Expand Up @@ -373,6 +374,15 @@ static const struct config_enum_entry huge_pages_options[] = {
{NULL, 0, false}
};

static const struct config_enum_entry timing_clock_source_options[] = {
{"auto", TIMING_CLOCK_SOURCE_AUTO, false},
{"system", TIMING_CLOCK_SOURCE_SYSTEM, false},
#if PG_INSTR_TSC_CLOCK
{"tsc", TIMING_CLOCK_SOURCE_TSC, false},
#endif
{NULL, 0, false}
};

static const struct config_enum_entry huge_pages_status_options[] = {
{"off", HUGE_PAGES_OFF, false},
{"on", HUGE_PAGES_ON, false},
Expand Down Expand Up @@ -724,6 +734,7 @@ const char *const config_group_names[] =
[CONN_AUTH_TCP] = gettext_noop("Connections and Authentication / TCP Settings"),
[CONN_AUTH_AUTH] = gettext_noop("Connections and Authentication / Authentication"),
[CONN_AUTH_SSL] = gettext_noop("Connections and Authentication / SSL"),
[RESOURCES_TIME] = gettext_noop("Resource Usage / Time"),
[RESOURCES_MEM] = gettext_noop("Resource Usage / Memory"),
[RESOURCES_DISK] = gettext_noop("Resource Usage / Disk"),
[RESOURCES_KERNEL] = gettext_noop("Resource Usage / Kernel Resources"),
Expand Down
4 changes: 4 additions & 0 deletions src/backend/utils/misc/postgresql.conf.sample
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@
#max_files_per_process = 1000 # min 64
# (change requires restart)

# - Time -

#timing_clock_source = auto # auto, system, tsc (if supported)

# - Background Writer -

#bgwriter_delay = 200ms # 10-10000ms between rounds
Expand Down
Loading