Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 056cc36

Browse files
committed
pgstat: reduce timer overhead by leaving timer running.
Previously the timer was enabled whenever there were any pending stats after executing a statement, just to then be disabled again when not idle anymore. That lead to an increase in GetCurrentTimestamp() calls from within timeout.c compared to 14. To avoid that increase, leave the timer enabled until stats are reported, rather than until idle. The timer is only disabled once the pending stats have been reported. For me this fixes the increase in GetCurrentTimestamp() calls, there now are fewer calls in 15 than in 14, in the previously slowed down workload. While at it, also update assertion in pgstat_report_stat() to be more precise. Author: Andres Freund <andres@anarazel.de> Discussion: https://postgr.es/m/20220616233130.rparivafipt6doj3@alap3.anarazel.de Backpatch: 15-
1 parent 67b2670 commit 056cc36

File tree

2 files changed

+32
-18
lines changed

2 files changed

+32
-18
lines changed

src/backend/tcop/postgres.c

+31-17
Original file line numberDiff line numberDiff line change
@@ -3371,10 +3371,13 @@ ProcessInterrupts(void)
33713371
IdleSessionTimeoutPending = false;
33723372
}
33733373

3374-
if (IdleStatsUpdateTimeoutPending)
3374+
/*
3375+
* If there are pending stats updates and we currently are truly idle
3376+
* (matching the conditions in PostgresMain(), report stats now.
3377+
*/
3378+
if (IdleStatsUpdateTimeoutPending &&
3379+
DoingCommandRead && !IsTransactionOrTransactionBlock())
33753380
{
3376-
/* timer should have been disarmed */
3377-
Assert(!IsTransactionBlock());
33783381
IdleStatsUpdateTimeoutPending = false;
33793382
pgstat_report_stat(true);
33803383
}
@@ -4050,7 +4053,6 @@ PostgresMain(const char *dbname, const char *username)
40504053
volatile bool send_ready_for_query = true;
40514054
bool idle_in_transaction_timeout_enabled = false;
40524055
bool idle_session_timeout_enabled = false;
4053-
bool idle_stats_update_timeout_enabled = false;
40544056

40554057
AssertArg(dbname != NULL);
40564058
AssertArg(username != NULL);
@@ -4427,13 +4429,31 @@ PostgresMain(const char *dbname, const char *username)
44274429
if (notifyInterruptPending)
44284430
ProcessNotifyInterrupt(false);
44294431

4430-
/* Start the idle-stats-update timer */
4432+
/*
4433+
* Check if we need to report stats. If pgstat_report_stat()
4434+
* decides it's too soon to flush out pending stats / lock
4435+
* contention prevented reporting, it'll tell us when we
4436+
* should try to report stats again (so that stats updates
4437+
* aren't unduly delayed if the connection goes idle for a
4438+
* long time). We only enable the timeout if we don't already
4439+
* have a timeout in progress, because we don't disable the
4440+
* timeout below. enable_timeout_after() needs to determine
4441+
* the current timestamp, which can have a negative
4442+
* performance impact. That's OK because pgstat_report_stat()
4443+
* won't have us wake up sooner than a prior call.
4444+
*/
44314445
stats_timeout = pgstat_report_stat(false);
44324446
if (stats_timeout > 0)
44334447
{
4434-
idle_stats_update_timeout_enabled = true;
4435-
enable_timeout_after(IDLE_STATS_UPDATE_TIMEOUT,
4436-
stats_timeout);
4448+
if (!get_timeout_active(IDLE_STATS_UPDATE_TIMEOUT))
4449+
enable_timeout_after(IDLE_STATS_UPDATE_TIMEOUT,
4450+
stats_timeout);
4451+
}
4452+
else
4453+
{
4454+
/* all stats flushed, no need for the timeout */
4455+
if (get_timeout_active(IDLE_STATS_UPDATE_TIMEOUT))
4456+
disable_timeout(IDLE_STATS_UPDATE_TIMEOUT, false);
44374457
}
44384458

44394459
set_ps_display("idle");
@@ -4469,10 +4489,9 @@ PostgresMain(const char *dbname, const char *username)
44694489
firstchar = ReadCommand(&input_message);
44704490

44714491
/*
4472-
* (4) turn off the idle-in-transaction, idle-session and
4473-
* idle-stats-update timeouts if active. We do this before step (5)
4474-
* so that any last-moment timeout is certain to be detected in step
4475-
* (5).
4492+
* (4) turn off the idle-in-transaction and idle-session timeouts if
4493+
* active. We do this before step (5) so that any last-moment timeout
4494+
* is certain to be detected in step (5).
44764495
*
44774496
* At most one of these timeouts will be active, so there's no need to
44784497
* worry about combining the timeout.c calls into one.
@@ -4487,11 +4506,6 @@ PostgresMain(const char *dbname, const char *username)
44874506
disable_timeout(IDLE_SESSION_TIMEOUT, false);
44884507
idle_session_timeout_enabled = false;
44894508
}
4490-
if (idle_stats_update_timeout_enabled)
4491-
{
4492-
disable_timeout(IDLE_STATS_UPDATE_TIMEOUT, false);
4493-
idle_stats_update_timeout_enabled = false;
4494-
}
44954509

44964510
/*
44974511
* (5) disable async signal conditions again.

src/backend/utils/activity/pgstat.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ pgstat_report_stat(bool force)
571571
bool nowait;
572572

573573
pgstat_assert_is_up();
574-
Assert(!IsTransactionBlock());
574+
Assert(!IsTransactionOrTransactionBlock());
575575

576576
/* "absorb" the forced flush even if there's nothing to flush */
577577
if (pgStatForceNextFlush)

0 commit comments

Comments
 (0)