Skip to content

Commit b20d681

Browse files
committed
[GR-54688] Return None from gc.collect, at least pyperformance benchmarks assert that collect returns either None or the correct number of cycles collected
1 parent 032dc13 commit b20d681

File tree

2 files changed

+27
-17
lines changed

2 files changed

+27
-17
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_gc.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -42,7 +42,7 @@
4242

4343

4444
def test_gc_collect():
45-
assert isinstance(gc.collect(), int)
45+
assert isinstance(gc.collect(), (int, type(None)))
4646

4747

4848
def test_gc_count():

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/GcModuleBuiltins.java

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public void initialize(Python3Core core) {
8989
@GenerateNodeFactory
9090
abstract static class GcCollectNode extends PythonBuiltinNode {
9191
@Specialization
92-
static int collect(VirtualFrame frame, PythonModule self, @SuppressWarnings("unused") Object level,
92+
static PNone collect(VirtualFrame frame, PythonModule self, @SuppressWarnings("unused") Object level,
9393
@Bind("this") Node inliningTarget,
9494
@Cached PyObjectGetAttr getAttr,
9595
@Cached PyObjectGetIter getIter,
@@ -105,30 +105,35 @@ static int collect(VirtualFrame frame, PythonModule self, @SuppressWarnings("unu
105105
if (cb != null) {
106106
phase = START;
107107
info = factory.createDict(new PKeyword[]{
108-
new PKeyword(GENERATION, 2),
109-
new PKeyword(COLLECTED, 0),
110-
new PKeyword(UNCOLLECTABLE, 0),
108+
new PKeyword(GENERATION, 2),
109+
new PKeyword(COLLECTED, 0),
110+
new PKeyword(UNCOLLECTABLE, 0),
111111
});
112112
do {
113113
call.executeObject(frame, cb, phase, info);
114114
} while ((cb = next.execute(frame, iter)) != null);
115115
}
116-
try {
117-
return javaCollect(inliningTarget, gil);
118-
} finally {
119-
if (phase != null) {
120-
phase = STOP;
121-
iter = getIter.execute(frame, inliningTarget, callbacks);
122-
while ((cb = next.execute(frame, iter)) != null) {
123-
call.executeObject(frame, cb, phase, info);
124-
}
116+
long freedMemory = javaCollect(inliningTarget, gil);
117+
if (phase != null) {
118+
phase = STOP;
119+
info = factory.createDict(new PKeyword[]{
120+
new PKeyword(GENERATION, 2),
121+
new PKeyword(COLLECTED, freedMemory),
122+
new PKeyword(UNCOLLECTABLE, 0),
123+
});
124+
iter = getIter.execute(frame, inliningTarget, callbacks);
125+
while ((cb = next.execute(frame, iter)) != null) {
126+
call.executeObject(frame, cb, phase, info);
125127
}
126128
}
129+
return PNone.NONE;
127130
}
128131

129132
@TruffleBoundary
130-
static int javaCollect(Node inliningTarget, GilNode gil) {
133+
static long javaCollect(Node inliningTarget, GilNode gil) {
131134
gil.release(true);
135+
Runtime runtime = Runtime.getRuntime();
136+
long freeMemory = runtime.freeMemory();
132137
try {
133138
PythonUtils.forceFullGC();
134139
try {
@@ -142,7 +147,12 @@ static int javaCollect(Node inliningTarget, GilNode gil) {
142147
// collect some weak references now
143148
PythonContext.triggerAsyncActions(inliningTarget);
144149
CApiTransitions.pollReferenceQueue();
145-
return 0;
150+
/*
151+
* CPython's GC returns the number of collected cycles. This is not something we can
152+
* determine, but to return some useful info to the Python program, we return the amount
153+
* of memory gained.
154+
*/
155+
return Math.max(0, runtime.freeMemory() - freeMemory);
146156
}
147157
}
148158

0 commit comments

Comments
 (0)