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

Commit 4a37527

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 5a1ab89 commit 4a37527

File tree

2 files changed

+32
-18
lines changed

2 files changed

+32
-18
lines changed

src/backend/tcop/postgres.c

Lines changed: 31 additions & 17 deletions
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
}
@@ -4051,7 +4054,6 @@ PostgresMain(const char *dbname, const char *username)
40514054
volatile bool send_ready_for_query = true;
40524055
bool idle_in_transaction_timeout_enabled = false;
40534056
bool idle_session_timeout_enabled = false;
4054-
bool idle_stats_update_timeout_enabled = false;
40554057

40564058
AssertArg(dbname != NULL);
40574059
AssertArg(username != NULL);
@@ -4428,13 +4430,31 @@ PostgresMain(const char *dbname, const char *username)
44284430
if (notifyInterruptPending)
44294431
ProcessNotifyInterrupt(false);
44304432

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

44404460
set_ps_display("idle");
@@ -4470,10 +4490,9 @@ PostgresMain(const char *dbname, const char *username)
44704490
firstchar = ReadCommand(&input_message);
44714491

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

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

src/backend/utils/activity/pgstat.c

Lines changed: 1 addition & 1 deletion
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)