[ VM / Service ] Allow for `profile_period` flag to be set via the service protocol
`profile_period` has been added to the list of flags which can be
changed at runtime via the `setFlag` RPC. Changing this flag at runtime will
cause the ThreadInterrupter to be shutdown, reinitialized, and started with the
new profiling period.
Fixes #35654.
Change-Id: I2f365fdf8e404270f2eed1e172c8d21b48e0aff9
Reviewed-on: https://dart-review.googlesource.com/c/89445
Auto-Submit: Ben Konyi <bkonyi@google.com>
Commit-Queue: Ben Konyi <bkonyi@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
Reviewed-by: Jacob Richman <jacobr@google.com>
diff --git a/runtime/observatory/tests/service/get_flag_list_rpc_test.dart b/runtime/observatory/tests/service/get_flag_list_rpc_test.dart
index 2240e01..472bfbb 100644
--- a/runtime/observatory/tests/service/get_flag_list_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_flag_list_rpc_test.dart
@@ -7,6 +7,17 @@
import 'test_helper.dart';
+Future getFlagValue(VM vm, String flagName) async {
+ var result = await vm.invokeRpcNoUpgrade('getFlagList', {});
+ expect(result['type'], equals('FlagList'));
+ final flags = result['flags'];
+ for (final flag in flags) {
+ if (flag['name'] == flagName) {
+ return flag['valueAsString'];
+ }
+ }
+}
+
var tests = <VMTest>[
(VM vm) async {
var result = await vm.invokeRpcNoUpgrade('getFlagList', {});
@@ -45,6 +56,32 @@
var result = await vm.invokeRpcNoUpgrade('setFlag', params);
expect(result['type'], equals('Success'));
},
+
+ // Modify a flag which cannot be set at runtime.
+ (VM vm) async {
+ var params = {
+ 'name': 'random_seed',
+ 'value': '42',
+ };
+ var result = await vm.invokeRpcNoUpgrade('setFlag', params);
+ expect(result['type'], equals('Error'));
+ expect(
+ result['message'], equals('Cannot set flag: cannot change at runtime'));
+ },
+
+ // Modify the profile_period at runtime.
+ (VM vm) async {
+ final kProfilePeriod = 'profile_period';
+ final kValue = 100;
+ expect(await getFlagValue(vm, kProfilePeriod), '1000');
+ var params = {
+ 'name': '$kProfilePeriod',
+ 'value': '$kValue',
+ };
+ var result = await vm.invokeRpcNoUpgrade('setFlag', params);
+ expect(result['type'], equals('Success'));
+ expect(await getFlagValue(vm, kProfilePeriod), kValue.toString());
+ }
];
main(args) async => runVMTests(args, tests);
diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart
index 9b1fb1a..ca2028a 100644
--- a/runtime/observatory/tests/service/get_version_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_version_rpc_test.dart
@@ -12,7 +12,7 @@
var result = await vm.invokeRpcNoUpgrade('getVersion', {});
expect(result['type'], equals('Version'));
expect(result['major'], equals(3));
- expect(result['minor'], equals(13));
+ expect(result['minor'], equals(14));
expect(result['_privateMajor'], equals(0));
expect(result['_privateMinor'], equals(0));
},
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 482dac0..5ff50f6 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -65,7 +65,6 @@
void Profiler::Init() {
// Place some sane restrictions on user controlled flags.
- SetSamplePeriod(FLAG_profile_period);
SetSampleDepth(FLAG_max_profile_depth);
Sample::Init();
if (!FLAG_profiler) {
@@ -77,7 +76,7 @@
// Zero counters.
memset(&counters_, 0, sizeof(counters_));
ThreadInterrupter::Init();
- ThreadInterrupter::SetInterruptPeriod(FLAG_profile_period);
+ SetSamplePeriod(FLAG_profile_period);
ThreadInterrupter::Startup();
initialized_ = true;
}
@@ -123,6 +122,11 @@
} else {
FLAG_profile_period = period;
}
+ ThreadInterrupter::SetInterruptPeriod(FLAG_profile_period);
+}
+
+void Profiler::UpdateSamplePeriod() {
+ SetSamplePeriod(FLAG_profile_period);
}
intptr_t Sample::pcs_length_ = 0;
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index 7ac6741..cb891a5 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -60,6 +60,9 @@
static void SetSampleDepth(intptr_t depth);
static void SetSamplePeriod(intptr_t period);
+ // Restarts sampling with a given profile period. This is called after the
+ // profile period is changed via the service protocol.
+ static void UpdateSamplePeriod();
static SampleBuffer* sample_buffer() { return sample_buffer_; }
static AllocationSampleBuffer* allocation_sample_buffer() {
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 282f198..580d290 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -4545,16 +4545,20 @@
// Changing most flags at runtime is dangerous because e.g., it may leave the
// behavior generated code and the runtime out of sync.
+ const uintptr_t kProfilePeriodIndex = 3;
const char* kAllowedFlags[] = {
"pause_isolates_on_start",
"pause_isolates_on_exit",
"pause_isolates_on_unhandled_exceptions",
+ "profile_period",
};
bool allowed = false;
+ bool profile_period = false;
for (size_t i = 0; i < ARRAY_SIZE(kAllowedFlags); i++) {
if (strcmp(flag_name, kAllowedFlags[i]) == 0) {
allowed = true;
+ profile_period = (i == kProfilePeriodIndex);
break;
}
}
@@ -4569,6 +4573,11 @@
const char* error = NULL;
if (Flags::SetFlag(flag_name, flag_value, &error)) {
PrintSuccess(js);
+ if (profile_period) {
+ // FLAG_profile_period has already been set to the new value. Now we need
+ // to notify the ThreadInterrupter to pick up the change.
+ Profiler::UpdateSamplePeriod();
+ }
return true;
} else {
JSONObject jsobj(js);
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index 90f3e64..3e54a6c 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -15,7 +15,7 @@
namespace dart {
#define SERVICE_PROTOCOL_MAJOR_VERSION 3
-#define SERVICE_PROTOCOL_MINOR_VERSION 13
+#define SERVICE_PROTOCOL_MINOR_VERSION 14
class Array;
class EmbedderServiceHandler;
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index 015ecfb..9d90108 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1,8 +1,8 @@
-# Dart VM Service Protocol 3.13
+# Dart VM Service Protocol 3.14
> Please post feedback to the [observatory-discuss group][discuss-list]
-This document describes of _version 3.13_ of the Dart VM Service Protocol. This
+This document describes of _version 3.14_ of the Dart VM Service Protocol. This
protocol is used to communicate with a running Dart Virtual Machine.
To use the Service Protocol, start the VM with the *--observe* flag.
@@ -842,6 +842,10 @@
* pause_isolates_on_start
* pause_isolates_on_exit
* pause_isolates_on_unhandled_exceptions
+ * profile_period
+
+Note: `profile_period` can be set to a minimum value of 50. Attempting to set
+`profile_period` to a lower value will result in a value of 50 being set.
See [Success](#success).
@@ -2732,5 +2736,6 @@
3.11 | Rename 'invoke' parameter 'receiverId' to 'targetId.
3.12 | Add 'getScripts' RPC and `ScriptList` object.
3.13 | Class 'mixin' field now properly set for kernel transformed mixin applications.
+3.14 | Flag 'profile_period' can now be set at runtime, allowing for the profiler sample rate to be changed while the program is running.
[discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/runtime/vm/service/service_dev.md b/runtime/vm/service/service_dev.md
index 869811e..5d59f09 100644
--- a/runtime/vm/service/service_dev.md
+++ b/runtime/vm/service/service_dev.md
@@ -1,8 +1,8 @@
-# Dart VM Service Protocol 3.14-dev
+# Dart VM Service Protocol 3.15-dev
> Please post feedback to the [observatory-discuss group][discuss-list]
-This document describes of _version 3.14-dev_ of the Dart VM Service Protocol. This
+This document describes of _version 3.15-dev_ of the Dart VM Service Protocol. This
protocol is used to communicate with a running Dart Virtual Machine.
To use the Service Protocol, start the VM with the *--observe* flag.
@@ -842,6 +842,10 @@
* pause_isolates_on_start
* pause_isolates_on_exit
* pause_isolates_on_unhandled_exceptions
+ * profile_period
+
+Note: `profile_period` can be set to a minimum value of 50. Attempting to set
+`profile_period` to a lower value will result in a value of 50 being set.
See [Success](#success).
@@ -2732,5 +2736,6 @@
3.11 | Rename 'invoke' parameter 'receiverId' to 'targetId.
3.12 | Add 'getScripts' RPC and `ScriptList` object.
3.13 | Class 'mixin' field now properly set for kernel transformed mixin applications.
+3.14 | Flag 'profile_period' can now be set at runtime, allowing for the profiler sample rate to be changed while the program is running.
[discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/runtime/vm/thread_interrupter.cc b/runtime/vm/thread_interrupter.cc
index d8d56b1..ebb07bd 100644
--- a/runtime/vm/thread_interrupter.cc
+++ b/runtime/vm/thread_interrupter.cc
@@ -116,6 +116,7 @@
// Delay between interrupts.
void ThreadInterrupter::SetInterruptPeriod(intptr_t period) {
+ MonitorLocker ml(monitor_);
if (shutdown_) {
return;
}
@@ -173,6 +174,9 @@
ASSERT(interrupted_thread_count == 0);
// Return to regular interrupts.
current_wait_time_ = interrupt_period_;
+ } else if (current_wait_time_ != interrupt_period_) {
+ // The interrupt period may have been updated via the service protocol.
+ current_wait_time_ = interrupt_period_;
}
// Reset count before interrupting any threads.