70
70
import com .oracle .graal .python .builtins .objects .frame .PFrame ;
71
71
import com .oracle .graal .python .builtins .objects .function .PArguments ;
72
72
import com .oracle .graal .python .builtins .objects .function .Signature ;
73
+ import com .oracle .graal .python .nodes .IndirectCallNode ;
73
74
import com .oracle .graal .python .nodes .PRootNode ;
74
75
import com .oracle .graal .python .nodes .call .GenericInvokeNode ;
75
76
import com .oracle .graal .python .runtime .AsyncHandler ;
76
77
import com .oracle .graal .python .runtime .ExecutionContext .CalleeContext ;
78
+ import com .oracle .graal .python .runtime .ExecutionContext .IndirectCallContext ;
77
79
import com .oracle .graal .python .runtime .PythonContext ;
78
80
import com .oracle .graal .python .runtime .PythonOptions ;
79
81
import com .oracle .truffle .api .CompilerAsserts ;
@@ -95,6 +97,8 @@ public final class CApiContext extends CExtContext {
95
97
96
98
public static final long REFERENCE_COUNT_BITS = Integer .SIZE ;
97
99
public static final long REFERENCE_COUNT_MARKER = (1L << REFERENCE_COUNT_BITS );
100
+ /* a random number between 1 and 20 */
101
+ private static final int MAX_COLLECTION_RETRIES = 17 ;
98
102
99
103
/** Total amount of allocated native memory (in bytes). */
100
104
private long allocatedMemory = 0 ;
@@ -108,7 +112,6 @@ public final class CApiContext extends CExtContext {
108
112
private Map <Object , AllocInfo > freedNativeMemory ;
109
113
110
114
@ CompilationFinal private RootCallTarget referenceCleanerCallTarget ;
111
- @ CompilationFinal private RootCallTarget triggerAsyncActionsCallTarget ;
112
115
113
116
/**
114
117
* This cache is used to cache native wrappers for frequently used primitives. This is strictly
@@ -208,14 +211,6 @@ private RootCallTarget getReferenceCleanerCallTarget() {
208
211
return referenceCleanerCallTarget ;
209
212
}
210
213
211
- RootCallTarget getTriggerAsyncActionsCallTarget () {
212
- if (triggerAsyncActionsCallTarget == null ) {
213
- CompilerDirectives .transferToInterpreterAndInvalidate ();
214
- triggerAsyncActionsCallTarget = Truffle .getRuntime ().createCallTarget (new TriggerAsyncActionsRootNode (getContext ()));
215
- }
216
- return triggerAsyncActionsCallTarget ;
217
- }
218
-
219
214
public TraceMallocDomain getTraceMallocDomain (int domainIdx ) {
220
215
return traceMallocDomains [domainIdx ];
221
216
}
@@ -419,43 +414,6 @@ public void execute(PythonContext context) {
419
414
}
420
415
}
421
416
422
- private static final class TriggerAsyncActionsRootNode extends PRootNode {
423
- private static final Signature SIGNATURE = new Signature (-1 , false , -1 , false , new String [0 ], new String [0 ]);
424
-
425
- @ Child private CalleeContext calleeContext = CalleeContext .create ();
426
-
427
- private final ConditionProfile customLocalsProfile = ConditionProfile .createBinaryProfile ();
428
- private final BranchProfile asyncProfile = BranchProfile .create ();
429
- private final PythonContext context ;
430
-
431
- protected TriggerAsyncActionsRootNode (PythonContext context ) {
432
- super (context .getLanguage ());
433
- this .context = context ;
434
- }
435
-
436
- @ Override
437
- public Object execute (VirtualFrame frame ) {
438
- CalleeContext .enter (frame , customLocalsProfile );
439
- try {
440
- doGc ();
441
- context .triggerAsyncActions (frame , asyncProfile );
442
- } finally {
443
- calleeContext .exit (frame , this );
444
- }
445
- return 0 ;
446
- }
447
-
448
- @ Override
449
- public Signature getSignature () {
450
- return SIGNATURE ;
451
- }
452
-
453
- @ Override
454
- public boolean isPythonInternal () {
455
- return true ;
456
- }
457
- }
458
-
459
417
public NativeObjectReference lookupNativeObjectReference (int idx ) {
460
418
return nativeObjectWrapperList .get (idx );
461
419
}
@@ -615,47 +573,53 @@ public boolean isAllocated(Object ptr) {
615
573
return true ;
616
574
}
617
575
618
- public void increaseMemoryPressure (GenericInvokeNode invokeNode , long size ) {
576
+ public void increaseMemoryPressure (long size ) {
619
577
if (allocatedMemory <= getContext ().getOption (PythonOptions .MaxNativeMemory )) {
620
578
allocatedMemory += size ;
621
579
return ;
622
580
}
623
-
624
- // Triggering the GC and the async actions is hidden behind a call target to keep this
625
- // method slim.
626
- invokeNode .execute (getTriggerAsyncActionsCallTarget (), PArguments .create ());
627
-
628
- if (allocatedMemory + size > getContext ().getOption (PythonOptions .MaxNativeMemory )) {
629
- throw new OutOfMemoryError ("native memory" );
630
- }
631
- allocatedMemory += size ;
581
+ triggerGC (size );
632
582
}
633
583
634
- public void increaseMemoryPressure (VirtualFrame frame , long size , BranchProfile asyncProfile ) {
635
- if (allocatedMemory <= getContext ().getOption (PythonOptions .MaxNativeMemory )) {
584
+ public void increaseMemoryPressure (VirtualFrame frame , PythonContext context , IndirectCallNode caller , long size ) {
585
+ if (allocatedMemory + size <= getContext ().getOption (PythonOptions .MaxNativeMemory )) {
636
586
allocatedMemory += size ;
637
587
return ;
638
588
}
639
589
640
- doGc ();
641
- getContext ().triggerAsyncActions (frame , asyncProfile );
590
+ Object savedState = IndirectCallContext .enter (frame , context , caller );
591
+ try {
592
+ triggerGC (size );
593
+ } finally {
594
+ IndirectCallContext .exit (frame , context , savedState );
595
+ }
596
+ }
642
597
643
- if (allocatedMemory + size > getContext ().getOption (PythonOptions .MaxNativeMemory )) {
644
- throw new OutOfMemoryError ("native memory" );
598
+ @ TruffleBoundary
599
+ private void triggerGC (long size ) {
600
+ long delay = 0 ;
601
+ for (int retries = 0 ; retries < MAX_COLLECTION_RETRIES ; retries ++) {
602
+ delay += 50 ;
603
+ doGc (delay );
604
+ getContext ().triggerAsyncActions (null , BranchProfile .getUncached ());
605
+ if (allocatedMemory + size <= getContext ().getOption (PythonOptions .MaxNativeMemory )) {
606
+ allocatedMemory += size ;
607
+ return ;
608
+ }
645
609
}
646
- allocatedMemory += size ;
610
+ throw new OutOfMemoryError ( "native memory" ) ;
647
611
}
648
612
649
613
public void reduceMemoryPressure (long size ) {
650
614
allocatedMemory -= size ;
651
615
}
652
616
653
617
@ TruffleBoundary
654
- private static void doGc () {
618
+ private static void doGc (long millis ) {
655
619
LOGGER .fine ("full GC due to native memory" );
656
620
System .gc ();
657
621
try {
658
- Thread .sleep (50 );
622
+ Thread .sleep (millis );
659
623
} catch (InterruptedException x ) {
660
624
// Restore interrupt status
661
625
Thread .currentThread ().interrupt ();
0 commit comments