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
20 changes: 12 additions & 8 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -17746,7 +17746,7 @@ $as_echo "#define HAVE__CPUID 1" >>confdefs.h
fi
fi

# Check for __get_cpuid_count() and __cpuidex() in a similar fashion.
# Check for __get_cpuid_count()
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __get_cpuid_count" >&5
$as_echo_n "checking for __get_cpuid_count... " >&6; }
if ${pgac_cv__get_cpuid_count+:} false; then :
Expand Down Expand Up @@ -17779,21 +17779,26 @@ if test x"$pgac_cv__get_cpuid_count" = x"yes"; then

$as_echo "#define HAVE__GET_CPUID_COUNT 1" >>confdefs.h

else
# __cpuidex()
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __cpuidex" >&5
fi

# Check for __cpuidex()
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __cpuidex" >&5
$as_echo_n "checking for __cpuidex... " >&6; }
if ${pgac_cv__cpuidex+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <intrin.h>
#ifdef _MSC_VER
#include <intrin.h>
#else
#include <cpuid.h>
#endif
int
main ()
{
unsigned int exx[4] = {0, 0, 0, 0};
__cpuidex(exx, 7, 0);
__cpuidex((int *) exx, 7, 0);

;
return 0;
Expand All @@ -17809,11 +17814,10 @@ rm -f core conftest.err conftest.$ac_objext \
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv__cpuidex" >&5
$as_echo "$pgac_cv__cpuidex" >&6; }
if test x"$pgac_cv__cpuidex" = x"yes"; then
if test x"$pgac_cv__cpuidex" = x"yes"; then

$as_echo "#define HAVE__CPUIDEX 1" >>confdefs.h

fi
fi

# Check for XSAVE intrinsics
Expand Down
30 changes: 17 additions & 13 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2107,7 +2107,7 @@ else
fi
fi

# Check for __get_cpuid_count() and __cpuidex() in a similar fashion.
# Check for __get_cpuid_count()
AC_CACHE_CHECK([for __get_cpuid_count], [pgac_cv__get_cpuid_count],
[AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <cpuid.h>],
[[unsigned int exx[4] = {0, 0, 0, 0};
Expand All @@ -2117,18 +2117,22 @@ AC_CACHE_CHECK([for __get_cpuid_count], [pgac_cv__get_cpuid_count],
[pgac_cv__get_cpuid_count="no"])])
if test x"$pgac_cv__get_cpuid_count" = x"yes"; then
AC_DEFINE(HAVE__GET_CPUID_COUNT, 1, [Define to 1 if you have __get_cpuid_count.])
else
# __cpuidex()
AC_CACHE_CHECK([for __cpuidex], [pgac_cv__cpuidex],
[AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <intrin.h>],
[[unsigned int exx[4] = {0, 0, 0, 0};
__cpuidex(exx, 7, 0);
]])],
[pgac_cv__cpuidex="yes"],
[pgac_cv__cpuidex="no"])])
if test x"$pgac_cv__cpuidex" = x"yes"; then
AC_DEFINE(HAVE__CPUIDEX, 1, [Define to 1 if you have __cpuidex.])
fi
fi

# Check for __cpuidex()
AC_CACHE_CHECK([for __cpuidex], [pgac_cv__cpuidex],
[AC_LINK_IFELSE([AC_LANG_PROGRAM([#ifdef _MSC_VER
#include <intrin.h>
#else
#include <cpuid.h>
#endif],
[[unsigned int exx[4] = {0, 0, 0, 0};
__cpuidex((int *) exx, 7, 0);
]])],
[pgac_cv__cpuidex="yes"],
[pgac_cv__cpuidex="no"])])
if test x"$pgac_cv__cpuidex" = x"yes"; then
AC_DEFINE(HAVE__CPUIDEX, 1, [Define to 1 if you have __cpuidex.])
fi

# Check for XSAVE intrinsics
Expand Down
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
13 changes: 10 additions & 3 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -2132,7 +2132,7 @@ elif cc.links('''
endif


# Check for __get_cpuid_count() and __cpuidex() in a similar fashion.
# Check for __get_cpuid_count()
if cc.links('''
#include <cpuid.h>
int main(int arg, char **argv)
Expand All @@ -2143,12 +2143,19 @@ if cc.links('''
''', name: '__get_cpuid_count',
args: test_c_args)
cdata.set('HAVE__GET_CPUID_COUNT', 1)
elif cc.links('''
endif

# Check for __cpuidex()
if cc.links('''
#ifdef _MSC_VER
#include <intrin.h>
#else
#include <cpuid.h>
#endif
int main(int arg, char **argv)
{
unsigned int exx[4] = {0, 0, 0, 0};
__cpuidex(exx, 7, 0);
__cpuidex((int *) exx, 7, 0);
}
''', name: '__cpuidex',
args: test_c_args)
Expand Down
65 changes: 63 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,64 @@ 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)
{
/*
* Ensure timing is initialized. On Windows (EXEC_BACKEND), GUC hooks can
* be called during InitializeGUCOptions() before InitProcessGlobals() has
* had a chance to run pg_initialize_timing().
*/
pg_initialize_timing();

#if PG_INSTR_TSC_CLOCK
pg_initialize_timing_tsc();

if (*newval == TIMING_CLOCK_SOURCE_TSC && 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)
{
/*
* 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 "?";
}
13 changes: 13 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 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->tsc_frequency_khz = tsc_frequency_khz;
#endif

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

#if PG_INSTR_TSC_CLOCK
tsc_frequency_khz = param->tsc_frequency_khz;
#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