Skip to content

Implement a time barrier for the GC #100421

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
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
5 changes: 5 additions & 0 deletions Include/internal/pycore_gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ struct _gc_runtime_state {
collections, and are awaiting to undergo a full collection for
the first time. */
Py_ssize_t long_lived_pending;

clock_t last_call_time;
size_t num_calls;
double running_average_time;
double running_average_since_last_call_time;
};


Expand Down
4 changes: 4 additions & 0 deletions Include/internal/pycore_runtime_init.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ extern "C" {
}, \
.gc = { \
.enabled = 1, \
.last_call_time = 0, \
.num_calls = 0, \
.running_average_time = 0, \
.running_average_since_last_call_time = 0, \
.generations = { \
/* .head is set in _PyGC_InitState(). */ \
{ .threshold = 700, }, \
Expand Down
17 changes: 17 additions & 0 deletions Modules/gcmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2290,8 +2290,25 @@ void
_Py_RunGC(PyThreadState *tstate)
{
GCState *gcstate = &tstate->interp->gc;

clock_t start_time = clock(); // record start time
size_t num_calls = gcstate->num_calls++;
double elapsed_time_since_last_call = (double)(start_time - gcstate->last_call_time) / CLOCKS_PER_SEC; // calculate elapsed time since last call in seconds
gcstate->running_average_since_last_call_time = (gcstate->running_average_since_last_call_time * num_calls + elapsed_time_since_last_call) / (num_calls + 1);

if (gcstate->running_average_time / gcstate->running_average_since_last_call_time * 100 > 1.0) {
// If the fraction of gc time over runtime is greater than 1%, don't run gc
return;
}

gcstate->collecting = 1;
gc_collect_generations(tstate);
clock_t end_time = clock(); // record end time

double ellapsed_time = (double)(end_time - start_time) / CLOCKS_PER_SEC; // calculate elapsed time in seconds
gcstate->last_call_time = start_time;
gcstate->running_average_time = (gcstate->running_average_time * num_calls + ellapsed_time) / (num_calls + 1);

gcstate->collecting = 0;
}

Expand Down
2 changes: 1 addition & 1 deletion Python/ceval_gil.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
at every turn of the eval loop. That variable is set after a wait of
`interval` microseconds on `gil_cond` has timed out.

[Actually, another volatile boolean variable (eval_breaker) is used
[Actually, another volatile boolean variablcre (eval_breaker) is used
which ORs several conditions into one. Volatile booleans are
sufficient as inter-thread signalling means since Python is run
on cache-coherent architectures only.]
Expand Down