[vm] Make profiler bailout counters available over the VM service.
Change-Id: I4c0d30b21371e33f66ab142636aa669a46f8a799
Reviewed-on: https://dart-review.googlesource.com/c/85547
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/observatory/lib/sample_profile.dart b/runtime/observatory/lib/sample_profile.dart
index f81f3bd..e755ad3 100644
--- a/runtime/observatory/lib/sample_profile.dart
+++ b/runtime/observatory/lib/sample_profile.dart
@@ -6,6 +6,7 @@
import 'dart:async';
import 'dart:typed_data';
+import 'package:logging/logging.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/service.dart';
import 'package:observatory/utils.dart';
diff --git a/runtime/observatory/lib/src/elements/sample_buffer_control.dart b/runtime/observatory/lib/src/elements/sample_buffer_control.dart
index c9b8452..0d5b38c 100644
--- a/runtime/observatory/lib/src/elements/sample_buffer_control.dart
+++ b/runtime/observatory/lib/src/elements/sample_buffer_control.dart
@@ -220,7 +220,7 @@
List<Element> _createTagSelect() {
var values = M.SampleProfileTag.values;
if (!_profileVM) {
- values = const [M.SampleProfileTag.userOnly, M.SampleProfileTag.none];
+ values = const [M.SampleProfileTag.userOnly, M.SampleProfileTag.vmOnly, M.SampleProfileTag.none];
}
var s;
return [
diff --git a/runtime/observatory/lib/src/sample_profile/sample_profile.dart b/runtime/observatory/lib/src/sample_profile/sample_profile.dart
index ebc625a..8ff90eb 100644
--- a/runtime/observatory/lib/src/sample_profile/sample_profile.dart
+++ b/runtime/observatory/lib/src/sample_profile/sample_profile.dart
@@ -830,6 +830,8 @@
}
Stream<double> loadProgress(ServiceObjectOwner owner, ServiceMap profile) {
+ Logger.root.info('sampling counters ${profile['counters']}');
+
var progress = new StreamController<double>.broadcast();
(() async {
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 4cb44d8..c0f8ecb 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -725,7 +725,8 @@
//
class ProfilerNativeStackWalker : public ProfilerStackWalker {
public:
- ProfilerNativeStackWalker(Dart_Port port_id,
+ ProfilerNativeStackWalker(ProfilerCounters* counters,
+ Dart_Port port_id,
Sample* sample,
SampleBuffer* sample_buffer,
uword stack_lower,
@@ -740,6 +741,7 @@
sample_buffer,
skip_count,
try_symbolize_dart_frames),
+ counters_(counters),
stack_upper_(stack_upper),
original_pc_(pc),
original_fp_(fp),
@@ -759,10 +761,14 @@
if (gap >= kMaxStep) {
// Gap between frame pointer and stack pointer is
// too large.
+ AtomicOperations::IncrementInt64By(&counters_->incomplete_sample_fp_step,
+ 1);
return;
}
if (!ValidFramePointer(fp)) {
+ AtomicOperations::IncrementInt64By(
+ &counters_->incomplete_sample_fp_bounds, 1);
return;
}
@@ -781,17 +787,23 @@
if (fp <= previous_fp) {
// Frame pointer did not move to a higher address.
+ AtomicOperations::IncrementInt64By(
+ &counters_->incomplete_sample_fp_step, 1);
return;
}
gap = fp - previous_fp;
if (gap >= kMaxStep) {
// Frame pointer step is too large.
+ AtomicOperations::IncrementInt64By(
+ &counters_->incomplete_sample_fp_step, 1);
return;
}
if (!ValidFramePointer(fp)) {
// Frame pointer is outside of isolate stack boundary.
+ AtomicOperations::IncrementInt64By(
+ &counters_->incomplete_sample_fp_bounds, 1);
return;
}
@@ -801,6 +813,8 @@
// the pc is so large that adding one to it will cause an
// overflow it is invalid and it will cause headaches later
// while we are building the profile. Discard it.
+ AtomicOperations::IncrementInt64By(&counters_->incomplete_sample_bad_pc,
+ 1);
return;
}
@@ -838,6 +852,7 @@
return r;
}
+ ProfilerCounters* const counters_;
const uword stack_upper_;
const uword original_pc_;
const uword original_fp_;
@@ -1146,7 +1161,8 @@
}
ProfilerNativeStackWalker native_stack_walker(
- ILLEGAL_PORT, NULL, NULL, stack_lower, stack_upper, pc, fp, sp,
+ &counters_, ILLEGAL_PORT, NULL, NULL, stack_lower, stack_upper, pc, fp,
+ sp,
/*skip_count=*/0,
/*try_symbolize_dart_frames=*/!for_crash);
native_stack_walker.walk();
@@ -1194,8 +1210,8 @@
if (FLAG_profile_vm_allocation) {
ProfilerNativeStackWalker native_stack_walker(
- (isolate != NULL) ? isolate->main_port() : ILLEGAL_PORT, sample,
- sample_buffer, stack_lower, stack_upper, pc, fp, sp);
+ &counters_, (isolate != NULL) ? isolate->main_port() : ILLEGAL_PORT,
+ sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp);
native_stack_walker.walk();
} else if (exited_dart_code) {
ProfilerDartStackWalker dart_exit_stack_walker(
@@ -1257,8 +1273,8 @@
sample->set_native_allocation_size_bytes(allocation_size);
ProfilerNativeStackWalker native_stack_walker(
- ILLEGAL_PORT, sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp,
- skip_count);
+ &counters_, ILLEGAL_PORT, sample, sample_buffer, stack_lower, stack_upper,
+ pc, fp, sp, skip_count);
native_stack_walker.walk();
@@ -1396,8 +1412,8 @@
}
ProfilerNativeStackWalker native_stack_walker(
- (isolate != NULL) ? isolate->main_port() : ILLEGAL_PORT, sample,
- sample_buffer, stack_lower, stack_upper, pc, fp, sp);
+ &counters_, (isolate != NULL) ? isolate->main_port() : ILLEGAL_PORT,
+ sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp);
const bool exited_dart_code = thread->HasExitedDartCode();
ProfilerDartStackWalker dart_stack_walker(thread, sample, sample_buffer,
stack_lower, stack_upper, pc, fp,
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index c6f868d..7ac6741 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -30,22 +30,26 @@
class SampleBuffer;
class ProfileTrieNode;
+#define PROFILER_COUNTERS(V) \
+ V(bail_out_unknown_task) \
+ V(bail_out_jump_to_exception_handler) \
+ V(bail_out_check_isolate) \
+ V(single_frame_sample_deoptimizing) \
+ V(single_frame_sample_register_check) \
+ V(single_frame_sample_get_and_validate_stack_bounds) \
+ V(stack_walker_native) \
+ V(stack_walker_dart_exit) \
+ V(stack_walker_dart) \
+ V(stack_walker_none) \
+ V(incomplete_sample_fp_bounds) \
+ V(incomplete_sample_fp_step) \
+ V(incomplete_sample_bad_pc) \
+ V(failure_native_allocation_sample)
+
struct ProfilerCounters {
- // Count of bail out reasons:
- ALIGN8 int64_t bail_out_unknown_task;
- ALIGN8 int64_t bail_out_jump_to_exception_handler;
- ALIGN8 int64_t bail_out_check_isolate;
- // Count of single frame sampling reasons:
- ALIGN8 int64_t single_frame_sample_deoptimizing;
- ALIGN8 int64_t single_frame_sample_register_check;
- ALIGN8 int64_t single_frame_sample_get_and_validate_stack_bounds;
- // Count of stack walkers used:
- ALIGN8 int64_t stack_walker_native;
- ALIGN8 int64_t stack_walker_dart_exit;
- ALIGN8 int64_t stack_walker_dart;
- ALIGN8 int64_t stack_walker_none;
- // Count of failed checks:
- ALIGN8 int64_t failure_native_allocation_sample;
+#define DECLARE_PROFILER_COUNTER(name) ALIGN8 int64_t name;
+ PROFILER_COUNTERS(DECLARE_PROFILER_COUNTER)
+#undef DECLARE_PROFILER_COUNTER
};
class Profiler : public AllStatic {
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index b2405f8..27eb4fe 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -2542,6 +2542,14 @@
ASSERT(root != NULL);
root->PrintToJSONArray(&function_trie);
}
+ {
+ ProfilerCounters counters = Profiler::counters();
+ JSONObject js_counters(&obj, "counters");
+#define ADD_PROFILER_COUNTER(name) \
+ js_counters.AddProperty64("" #name, counters.name);
+PROFILER_COUNTERS(ADD_PROFILER_COUNTER)
+#undef ADD_PROFILER_COUNTER
+ }
}
void ProfileTrieWalker::Reset(Profile::TrieKind trie_kind) {