Skip to content

Commit c6a1eb1

Browse files
rmacnak-googleCommit Bot
authored andcommitted
[vm, gc] Very basic RAIL.
Related to #47574 TEST=ci Change-Id: I2f07be6150b025a301e6e4d10935b606087cdf00 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/252462 Reviewed-by: Siva Annamalai <asiva@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
1 parent 1c45840 commit c6a1eb1

8 files changed

Lines changed: 125 additions & 7 deletions

File tree

runtime/include/dart_api.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,6 +1277,40 @@ DART_EXPORT void Dart_NotifyIdle(int64_t deadline);
12771277
*/
12781278
DART_EXPORT void Dart_NotifyLowMemory(void);
12791279

1280+
typedef enum {
1281+
/**
1282+
* Balanced
1283+
*/
1284+
Dart_PerformanceMode_Default,
1285+
/**
1286+
* Optimize for low latency, at the expense of throughput and memory overhead
1287+
* by performing work in smaller batches (requiring more overhead) or by
1288+
* delaying work (requiring more memory). An embedder should not remain in
1289+
* this mode indefinitely.
1290+
*/
1291+
Dart_PerformanceMode_Latency,
1292+
/**
1293+
* Optimize for high throughput, at the expense of latency and memory overhead
1294+
* by performing work in larger batches with more intervening growth.
1295+
*/
1296+
Dart_PerformanceMode_Throughput,
1297+
/**
1298+
* Optimize for low memory, at the expensive of throughput and latency by more
1299+
* frequently performing work.
1300+
*/
1301+
Dart_PerformanceMode_Memory,
1302+
} Dart_PerformanceMode;
1303+
1304+
/**
1305+
* Set the desired performance trade-off.
1306+
*
1307+
* Requires a current isolate.
1308+
*
1309+
* Returns the previous performance mode.
1310+
*/
1311+
DART_EXPORT Dart_PerformanceMode
1312+
Dart_SetPerformanceMode(Dart_PerformanceMode mode);
1313+
12801314
/**
12811315
* Starts the CPU sampling profiler.
12821316
*/

runtime/vm/dart_api_impl.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1829,6 +1829,14 @@ DART_EXPORT void Dart_NotifyLowMemory() {
18291829
// caches.
18301830
}
18311831

1832+
DART_EXPORT Dart_PerformanceMode
1833+
Dart_SetPerformanceMode(Dart_PerformanceMode mode) {
1834+
Thread* T = Thread::Current();
1835+
CHECK_ISOLATE(T->isolate());
1836+
TransitionNativeToVM transition(T);
1837+
return T->heap()->SetMode(mode);
1838+
}
1839+
18321840
DART_EXPORT void Dart_ExitIsolate() {
18331841
Thread* T = Thread::Current();
18341842
CHECK_ISOLATE(T->isolate());

runtime/vm/dart_api_impl_test.cc

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9685,6 +9685,50 @@ void main() {
96859685
EXPECT_VALID(result);
96869686
}
96879687

9688+
static void SetPerformanceModeDefault(Dart_NativeArguments args) {
9689+
Dart_SetPerformanceMode(Dart_PerformanceMode_Default);
9690+
}
9691+
static void SetPerformanceModeLatency(Dart_NativeArguments args) {
9692+
Dart_SetPerformanceMode(Dart_PerformanceMode_Latency);
9693+
}
9694+
9695+
static Dart_NativeFunction SetMode_native_lookup(Dart_Handle name,
9696+
int argument_count,
9697+
bool* auto_setup_scope) {
9698+
const char* cstr = nullptr;
9699+
Dart_StringToCString(name, &cstr);
9700+
if (strcmp(cstr, "SetPerformanceModeDefault") == 0) {
9701+
return SetPerformanceModeDefault;
9702+
} else if (strcmp(cstr, "SetPerformanceModeLatency") == 0) {
9703+
return SetPerformanceModeLatency;
9704+
}
9705+
return NULL;
9706+
}
9707+
9708+
TEST_CASE(DartAPI_SetPerformanceMode) {
9709+
const char* kScriptChars = R"(
9710+
import "dart:typed_data";
9711+
@pragma("vm:external-name", "SetPerformanceModeDefault")
9712+
external void setPerformanceModeDefault();
9713+
@pragma("vm:external-name", "SetPerformanceModeLatency")
9714+
external void setPerformanceModeLatency();
9715+
void main() {
9716+
for (var i = 0; i < 10; i++) {
9717+
setPerformanceModeLatency();
9718+
var t = [];
9719+
for (var j = 0; j < 32; j++) {
9720+
t.add(Uint8List(1000000));
9721+
}
9722+
setPerformanceModeDefault();
9723+
}
9724+
}
9725+
)";
9726+
Dart_Handle lib =
9727+
TestCase::LoadTestScript(kScriptChars, &SetMode_native_lookup);
9728+
Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
9729+
EXPECT_VALID(result);
9730+
}
9731+
96889732
static void NotifyLowMemoryNative(Dart_NativeArguments args) {
96899733
Dart_NotifyLowMemory();
96909734
}

runtime/vm/heap/heap.cc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,11 @@ void Heap::CheckExternalGC(Thread* thread) {
180180
ASSERT(thread->no_safepoint_scope_depth() == 0);
181181
ASSERT(thread->no_callback_scope_depth() == 0);
182182
ASSERT(!thread->force_growth());
183+
184+
if (mode_ == Dart_PerformanceMode_Latency) {
185+
return;
186+
}
187+
183188
if (new_space_.ExternalInWords() >= (4 * new_space_.CapacityInWords())) {
184189
// Attempt to free some external allocation by a scavenge. (If the total
185190
// remains above the limit, next external alloc will trigger another.)
@@ -426,6 +431,15 @@ void Heap::NotifyIdle(int64_t deadline) {
426431
}
427432
}
428433

434+
Dart_PerformanceMode Heap::SetMode(Dart_PerformanceMode new_mode) {
435+
Dart_PerformanceMode old_mode = mode_.exchange(new_mode);
436+
if ((old_mode == Dart_PerformanceMode_Latency) &&
437+
(new_mode == Dart_PerformanceMode_Default)) {
438+
CheckCatchUp(Thread::Current());
439+
}
440+
return old_mode;
441+
}
442+
429443
void Heap::CollectNewSpaceGarbage(Thread* thread,
430444
GCType type,
431445
GCReason reason) {
@@ -564,6 +578,15 @@ void Heap::CollectAllGarbage(GCReason reason, bool compact) {
564578
WaitForSweeperTasks(thread);
565579
}
566580

581+
void Heap::CheckCatchUp(Thread* thread) {
582+
ASSERT(thread->CanCollectGarbage());
583+
if (old_space()->ReachedHardThreshold()) {
584+
CollectGarbage(thread, GCType::kMarkSweep, GCReason::kCatchUp);
585+
} else {
586+
CheckConcurrentMarking(thread, GCReason::kCatchUp, 0);
587+
}
588+
}
589+
567590
void Heap::CheckConcurrentMarking(Thread* thread,
568591
GCReason reason,
569592
intptr_t size) {
@@ -859,6 +882,8 @@ const char* Heap::GCReasonToString(GCReason gc_reason) {
859882
return "idle";
860883
case GCReason::kDebugging:
861884
return "debugging";
885+
case GCReason::kCatchUp:
886+
return "catch-up";
862887
default:
863888
UNREACHABLE();
864889
return "";

runtime/vm/heap/heap.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ class Heap {
107107

108108
void NotifyIdle(int64_t deadline);
109109

110+
Dart_PerformanceMode mode() const { return mode_; }
111+
Dart_PerformanceMode SetMode(Dart_PerformanceMode mode);
112+
110113
// Collect a single generation.
111114
void CollectGarbage(Thread* thread, GCType type, GCReason reason);
112115

@@ -125,6 +128,7 @@ class Heap {
125128
void CollectAllGarbage(GCReason reason = GCReason::kFull,
126129
bool compact = false);
127130

131+
void CheckCatchUp(Thread* thread);
128132
void CheckConcurrentMarking(Thread* thread, GCReason reason, intptr_t size);
129133
void StartConcurrentMarking(Thread* thread, GCReason reason);
130134
void WaitForMarkerTasks(Thread* thread);
@@ -362,6 +366,8 @@ class Heap {
362366
// GC stats collection.
363367
GCStats stats_;
364368

369+
RelaxedAtomic<Dart_PerformanceMode> mode_ = {Dart_PerformanceMode_Default};
370+
365371
// This heap is in read-only mode: No allocation is allowed.
366372
bool read_only_;
367373

runtime/vm/heap/pages.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1524,13 +1524,19 @@ bool PageSpaceController::ReachedHardThreshold(SpaceUsage after) const {
15241524
if (heap_growth_ratio_ == 100) {
15251525
return false;
15261526
}
1527+
if ((heap_ != nullptr) && (heap_->mode() == Dart_PerformanceMode_Latency)) {
1528+
return false;
1529+
}
15271530
return after.CombinedUsedInWords() > hard_gc_threshold_in_words_;
15281531
}
15291532

15301533
bool PageSpaceController::ReachedSoftThreshold(SpaceUsage after) const {
15311534
if (heap_growth_ratio_ == 100) {
15321535
return false;
15331536
}
1537+
if ((heap_ != nullptr) && (heap_->mode() == Dart_PerformanceMode_Latency)) {
1538+
return false;
1539+
}
15341540
return after.CombinedUsedInWords() > soft_gc_threshold_in_words_;
15351541
}
15361542

runtime/vm/heap/safepoint.cc

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,8 @@ ForceGrowthSafepointOperationScope::~ForceGrowthSafepointOperationScope() {
5454

5555
T->DecrementForceGrowthScopeDepth();
5656
if (!T->force_growth()) {
57-
ASSERT(T->CanCollectGarbage());
5857
// Check if we passed the growth limit during the scope.
59-
Heap* heap = T->heap();
60-
if (heap->old_space()->ReachedHardThreshold()) {
61-
heap->CollectGarbage(T, GCType::kMarkSweep, GCReason::kOldSpace);
62-
} else {
63-
heap->CheckConcurrentMarking(T, GCReason::kOldSpace, 0);
64-
}
58+
T->heap()->CheckCatchUp(T);
6559
}
6660
}
6761

runtime/vm/heap/spaces.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ enum class GCReason {
4747
kExternal, // Dart_NewFinalizableHandle Dart_NewWeakPersistentHandle
4848
kIdle, // Dart_NotifyIdle
4949
kDebugging, // service request, etc.
50+
kCatchUp, // End of ForceGrowthScope or Dart_PerformanceMode_Latency.
5051
};
5152

5253
} // namespace dart

0 commit comments

Comments
 (0)