Commit 27c3e3de authored by Tom Lane's avatar Tom Lane

Remove redundant gettimeofday() calls to the extent practical without

changing semantics too much.  statement_timestamp is now set immediately
upon receipt of a client command message, and the various places that used
to do their own gettimeofday() calls to mark command startup are referenced
to that instead.  I have also made stats_command_string use that same
value for pg_stat_activity.query_start for both the command itself and
its eventual replacement by <IDLE> or <idle in transaction>.  There was
some debate about that, but no argument that seemed convincing enough to
justify an extra gettimeofday() call.
parent 47a37aee
......@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.220 2006/04/25 00:25:17 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.221 2006/06/20 22:51:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -167,9 +167,10 @@ static SubTransactionId currentSubTransactionId;
static CommandId currentCommandId;
/*
* This is the value of now(), ie, the transaction start time.
* This does not change as we enter and exit subtransactions, so we don't
* keep it inside the TransactionState stack.
* xactStartTimestamp is the value of transaction_timestamp().
* stmtStartTimestamp is the value of statement_timestamp().
* These do not change as we enter and exit subtransactions, so we don't
* keep them inside the TransactionState stack.
*/
static TimestampTz xactStartTimestamp;
static TimestampTz stmtStartTimestamp;
......@@ -1386,7 +1387,9 @@ StartTransaction(void)
XactLockTableInsert(s->transactionId);
/*
* now() and statement_timestamp() should be the same time
* set transaction_timestamp() (a/k/a now()). We want this to be the
* same as the first command's statement_timestamp(), so don't do a
* fresh GetCurrentTimestamp() call (which'd be expensive anyway).
*/
xactStartTimestamp = stmtStartTimestamp;
......
......@@ -10,7 +10,7 @@
* Copyright (c) 2002-2006, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.52 2006/04/25 14:11:54 momjian Exp $
* $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.53 2006/06/20 22:51:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -373,7 +373,7 @@ StorePreparedStatement(const char *stmt_name,
entry->plan_list = plan_list;
entry->argtype_list = argtype_list;
entry->context = entrycxt;
entry->prepare_time = GetCurrentTimestamp();
entry->prepare_time = GetCurrentStatementStartTimestamp();
entry->from_sql = from_sql;
MemoryContextSwitchTo(oldcxt);
......
......@@ -13,7 +13,7 @@
*
* Copyright (c) 2001-2006, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.129 2006/06/19 01:51:21 tgl Exp $
* $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.130 2006/06/20 22:52:00 tgl Exp $
* ----------
*/
#include "postgres.h"
......@@ -1368,8 +1368,14 @@ pgstat_bestart(void)
/*
* To minimize the time spent modifying the entry, fetch all the
* needed data first.
*
* If we have a MyProcPort, use its session start time (for consistency,
* and to save a kernel call).
*/
proc_start_timestamp = GetCurrentTimestamp();
if (MyProcPort)
proc_start_timestamp = MyProcPort->SessionStartTime;
else
proc_start_timestamp = GetCurrentTimestamp();
userid = GetSessionUserId();
/*
......@@ -1464,7 +1470,7 @@ pgstat_report_activity(const char *cmd_str)
* To minimize the time spent modifying the entry, fetch all the
* needed data first.
*/
start_timestamp = GetCurrentTimestamp();
start_timestamp = GetCurrentStatementStartTimestamp();
len = strlen(cmd_str);
len = pg_mbcliplen(cmd_str, len, PGBE_ACTIVITY_SIZE - 1);
......
......@@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.487 2006/06/19 01:51:21 tgl Exp $
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.488 2006/06/20 22:52:00 tgl Exp $
*
* NOTES
*
......@@ -99,7 +99,6 @@
#include "commands/async.h"
#include "lib/dllist.h"
#include "libpq/auth.h"
#include "libpq/crypt.h"
#include "libpq/libpq.h"
#include "libpq/pqcomm.h"
#include "libpq/pqsignal.h"
......@@ -2609,8 +2608,9 @@ BackendInitialize(Port *port)
ClientAuthInProgress = true; /* limit visibility of log messages */
/* save start time for end of session reporting */
gettimeofday(&(port->session_start), NULL);
/* save process start time */
port->SessionStartTime = GetCurrentTimestamp();
port->session_start = timestamptz_to_time_t(port->SessionStartTime);
/* set these to empty in case they are needed before we set them up */
port->remote_host = "";
......@@ -2749,6 +2749,8 @@ BackendRun(Port *port)
char **av;
int maxac;
int ac;
long secs;
int usecs;
char protobuf[32];
int i;
......@@ -2758,7 +2760,9 @@ BackendRun(Port *port)
* a new random sequence in the random() library function.
*/
random_seed = 0;
srandom((unsigned int) (MyProcPid ^ port->session_start.tv_usec));
/* slightly hacky way to get integer microseconds part of timestamptz */
TimestampDifference(0, port->SessionStartTime, &secs, &usecs);
srandom((unsigned int) (MyProcPid ^ usecs));
/* ----------------
* Now, build the argv vector that will be given to PostgresMain.
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.174 2006/04/14 03:38:55 tgl Exp $
* $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.175 2006/06/20 22:52:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -42,6 +42,7 @@
#include "storage/proc.h"
#include "storage/procarray.h"
#include "storage/spin.h"
#include "utils/timestamp.h"
/* GUC variables */
......@@ -73,7 +74,7 @@ static volatile bool deadlock_timeout_active = false;
volatile bool cancel_from_timeout = false;
/* statement_fin_time is valid only if statement_timeout_active is true */
static struct timeval statement_fin_time;
static TimestampTz statement_fin_time;
static void RemoveProcFromArray(int code, Datum arg);
......@@ -1105,29 +1106,32 @@ ProcSendSignal(int pid)
bool
enable_sig_alarm(int delayms, bool is_statement_timeout)
{
struct timeval fin_time;
TimestampTz fin_time;
struct itimerval timeval;
/* Compute target timeout time if we will need it */
if (is_statement_timeout || statement_timeout_active)
{
gettimeofday(&fin_time, NULL);
fin_time.tv_sec += delayms / 1000;
fin_time.tv_usec += (delayms % 1000) * 1000;
if (fin_time.tv_usec >= 1000000)
{
fin_time.tv_sec++;
fin_time.tv_usec -= 1000000;
}
}
if (is_statement_timeout)
{
/* Begin statement-level timeout */
/*
* Begin statement-level timeout
*
* Note that we compute statement_fin_time with reference to the
* statement_timestamp, but apply the specified delay without any
* correction; that is, we ignore whatever time has elapsed since
* statement_timestamp was set. In the normal case only a small
* interval will have elapsed and so this doesn't matter, but there
* are corner cases (involving multi-statement query strings with
* embedded COMMIT or ROLLBACK) where we might re-initialize the
* statement timeout long after initial receipt of the message.
* In such cases the enforcement of the statement timeout will be
* a bit inconsistent. This annoyance is judged not worth the cost
* of performing an additional gettimeofday() here.
*/
Assert(!deadlock_timeout_active);
fin_time = GetCurrentStatementStartTimestamp();
fin_time = TimestampTzPlusMilliseconds(fin_time, delayms);
statement_fin_time = fin_time;
statement_timeout_active = true;
cancel_from_timeout = false;
statement_timeout_active = true;
}
else if (statement_timeout_active)
{
......@@ -1145,10 +1149,10 @@ enable_sig_alarm(int delayms, bool is_statement_timeout)
* to the state variables. The deadlock checker may get run earlier
* than normal, but that does no harm.
*/
fin_time = GetCurrentTimestamp();
fin_time = TimestampTzPlusMilliseconds(fin_time, delayms);
deadlock_timeout_active = true;
if (fin_time.tv_sec > statement_fin_time.tv_sec ||
(fin_time.tv_sec == statement_fin_time.tv_sec &&
fin_time.tv_usec >= statement_fin_time.tv_usec))
if (fin_time >= statement_fin_time)
return true;
}
else
......@@ -1225,16 +1229,14 @@ disable_sig_alarm(bool is_statement_timeout)
static bool
CheckStatementTimeout(void)
{
struct timeval now;
TimestampTz now;
if (!statement_timeout_active)
return true; /* do nothing if not active */
gettimeofday(&now, NULL);
now = GetCurrentTimestamp();
if (now.tv_sec > statement_fin_time.tv_sec ||
(now.tv_sec == statement_fin_time.tv_sec &&
now.tv_usec >= statement_fin_time.tv_usec))
if (now >= statement_fin_time)
{
/* Time to die */
statement_timeout_active = false;
......@@ -1244,16 +1246,21 @@ CheckStatementTimeout(void)
else
{
/* Not time yet, so (re)schedule the interrupt */
long secs;
int usecs;
struct itimerval timeval;
TimestampDifference(now, statement_fin_time,
&secs, &usecs);
/*
* It's possible that the difference is less than a microsecond;
* ensure we don't cancel, rather than set, the interrupt.
*/
if (secs == 0 && usecs == 0)
usecs = 1;
MemSet(&timeval, 0, sizeof(struct itimerval));
timeval.it_value.tv_sec = statement_fin_time.tv_sec - now.tv_sec;
timeval.it_value.tv_usec = statement_fin_time.tv_usec - now.tv_usec;
if (timeval.it_value.tv_usec < 0)
{
timeval.it_value.tv_sec--;
timeval.it_value.tv_usec += 1000000;
}
timeval.it_value.tv_sec = secs;
timeval.it_value.tv_usec = usecs;
if (setitimer(ITIMER_REAL, &timeval, NULL))
return false;
}
......
This diff is collapsed.
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.163 2006/04/25 00:25:18 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.164 2006/06/20 22:52:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -963,6 +963,39 @@ GetCurrentTimestamp(void)
return result;
}
/*
* TimestampDifference -- convert the difference between two timestamps
* into integer seconds and microseconds
*
* Both inputs must be ordinary finite timestamps (in current usage,
* they'll be results from GetCurrentTimestamp()).
*
* We expect start_time <= stop_time. If not, we return zeroes; for current
* callers there is no need to be tense about which way division rounds on
* negative inputs.
*/
void
TimestampDifference(TimestampTz start_time, TimestampTz stop_time,
long *secs, int *microsecs)
{
TimestampTz diff = stop_time - start_time;
if (diff <= 0)
{
*secs = 0;
*microsecs = 0;
}
else
{
#ifdef HAVE_INT64_TIMESTAMP
*secs = (long) (diff / USECS_PER_SEC);
*microsecs = (int) (diff % USECS_PER_SEC);
#else
*secs = (long) diff;
*microsecs = (int) ((diff - *secs) * 1000000.0);
#endif
}
}
/*
* Convert a time_t to TimestampTz.
......@@ -985,6 +1018,27 @@ time_t_to_timestamptz(time_t tm)
return result;
}
/*
* Convert a TimestampTz to time_t.
*
* This too is just marginally useful, but some places need it.
*/
time_t
timestamptz_to_time_t(TimestampTz t)
{
time_t result;
#ifdef HAVE_INT64_TIMESTAMP
result = (time_t) (t / USECS_PER_SEC +
((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY));
#else
result = (time_t) (t +
((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY));
#endif
return result;
}
void
dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
......
......@@ -42,7 +42,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.169 2006/03/05 15:58:46 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.170 2006/06/20 22:52:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1408,7 +1408,7 @@ log_line_prefix(StringInfo buf)
if (MyProcPort)
{
appendStringInfo(buf, "%lx.%x",
(long) (MyProcPort->session_start.tv_sec),
(long) (MyProcPort->session_start),
MyProcPid);
}
break;
......@@ -1440,7 +1440,7 @@ log_line_prefix(StringInfo buf)
strftime(strfbuf, sizeof(strfbuf),
/* leave room for milliseconds... */
/* Win32 timezone names are too long so don't print them. */
/* Win32 timezone names are too long so don't print them */
#ifndef WIN32
"%Y-%m-%d %H:%M:%S %Z",
#else
......@@ -1474,12 +1474,11 @@ log_line_prefix(StringInfo buf)
case 's':
if (MyProcPort)
{
time_t stamp_time = MyProcPort->session_start.tv_sec;
char strfbuf[128];
strftime(strfbuf, sizeof(strfbuf),
"%Y-%m-%d %H:%M:%S %Z",
localtime(&stamp_time));
localtime(&MyProcPort->session_start));
appendStringInfoString(buf, strfbuf);
}
break;
......
......@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.87 2006/04/25 14:11:58 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.88 2006/06/20 22:52:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -202,7 +202,7 @@ CreatePortal(const char *name, bool allowDup, bool dupSilent)
portal->atStart = true;
portal->atEnd = true; /* disallow fetches until query is set */
portal->visible = true;
portal->creation_time = GetCurrentTimestamp();
portal->creation_time = GetCurrentStatementStartTimestamp();
/* put portal in table (sets portal->name) */
PortalHashTableInsert(portal, name);
......
......@@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/libpq/libpq-be.h,v 1.55 2006/03/05 15:58:56 momjian Exp $
* $PostgreSQL: pgsql/src/include/libpq/libpq-be.h,v 1.56 2006/06/20 22:52:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -31,6 +31,7 @@
#include "libpq/hba.h"
#include "libpq/pqcomm.h"
#include "utils/timestamp.h"
typedef enum CAC_state
......@@ -80,7 +81,8 @@ typedef struct Port
* but since it gets used by elog.c in the same way as database_name and
* other members of this struct, we may as well keep it here.
*/
struct timeval session_start; /* for session duration logging */
TimestampTz SessionStartTime; /* backend start time */
time_t session_start; /* same, in time_t format */
/*
* TCP keepalive settings.
......@@ -97,7 +99,8 @@ typedef struct Port
int keepalives_count;
/*
* SSL structures
* SSL structures (keep these last so that USE_SSL doesn't affect
* locations of other fields)
*/
#ifdef USE_SSL
SSL *ssl;
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.60 2006/04/25 00:25:22 momjian Exp $
* $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.61 2006/06/20 22:52:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -177,6 +177,12 @@ typedef double fsec_t;
#define INTERVAL_PRECISION(t) ((t) & INTERVAL_PRECISION_MASK)
#define INTERVAL_RANGE(t) (((t) >> 16) & INTERVAL_RANGE_MASK)
#ifdef HAVE_INT64_TIMESTAMP
#define TimestampTzPlusMilliseconds(tz,ms) ((tz) + ((ms) * 1000))
#else
#define TimestampTzPlusMilliseconds(tz,ms) ((tz) + ((ms) / 1000.0))
#endif
/* Set at postmaster start */
extern TimestampTz PgStartTime;
......@@ -293,7 +299,11 @@ extern Datum pgsql_postmaster_start_time(PG_FUNCTION_ARGS);
extern TimestampTz GetCurrentTimestamp(void);
extern void TimestampDifference(TimestampTz start_time, TimestampTz stop_time,
long *secs, int *microsecs);
extern TimestampTz time_t_to_timestamptz(time_t tm);
extern time_t timestamptz_to_time_t(TimestampTz t);
extern int tm2timestamp(struct pg_tm * tm, fsec_t fsec, int *tzp, Timestamp *dt);
extern int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment