Files
sdk/runtime/vm/metrics.cc
asiva fca032461a [VM/Runtime] Turn on isolate group metrics gathering in product mode
dart2js benchmarks use --print-metrics to track heap usage, with the
shift to running dart2js using aproduct mode AOT snapshot these
metrics are not printed resulting in errors from the benchmarks.
The size increase from turning on these isolate group metrics in product
mode is not very significant (about 2k).

TEST=ci

Change-Id: Ie9bbaecd57a2b45c27a158f6eb4988966a41ce67
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/405220
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Siva Annamalai <asiva@google.com>
2025-01-22 07:48:37 -08:00

220 lines
6.1 KiB
C++

// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/metrics.h"
#include "vm/isolate.h"
#include "vm/json_stream.h"
#include "vm/log.h"
#include "vm/native_entry.h"
#include "vm/object.h"
#include "vm/runtime_entry.h"
namespace dart {
DEFINE_FLAG(bool,
print_metrics,
false,
"Print metrics when isolates (and the VM) are shutdown.");
Metric* Metric::vm_list_head_ = nullptr;
Metric::Metric() : unit_(kCounter), value_(0) {}
Metric::~Metric() {}
void Metric::InitInstance(IsolateGroup* isolate_group,
const char* name,
const char* description,
Unit unit) {
// Only called once.
ASSERT(name != nullptr);
isolate_group_ = isolate_group;
name_ = name;
description_ = description;
unit_ = unit;
}
void Metric::InitInstance(Isolate* isolate,
const char* name,
const char* description,
Unit unit) {
// Only called once.
ASSERT(name != nullptr);
isolate_ = isolate;
name_ = name;
description_ = description;
unit_ = unit;
}
void Metric::InitInstance(const char* name,
const char* description,
Unit unit) {
// Only called once.
ASSERT(name != nullptr);
name_ = name;
description_ = description;
unit_ = unit;
}
#if !defined(PRODUCT)
static const char* UnitString(intptr_t unit) {
switch (unit) {
case Metric::kCounter:
return "counter";
case Metric::kByte:
return "byte";
case Metric::kMicrosecond:
return "us";
default:
UNREACHABLE();
}
UNREACHABLE();
return nullptr;
}
void Metric::PrintJSON(JSONStream* stream) {
JSONObject obj(stream);
obj.AddProperty("type", "Counter");
obj.AddProperty("name", name_);
obj.AddProperty("description", description_);
obj.AddProperty("unit", UnitString(unit()));
if (isolate_ == nullptr && isolate_group_ == nullptr) {
obj.AddFixedServiceId("vm/metrics/%s", name_);
} else {
obj.AddFixedServiceId("metrics/native/%s", name_);
}
// TODO(johnmccutchan): Overflow?
double value_as_double = static_cast<double>(Value());
obj.AddProperty("value", value_as_double);
}
#endif // !defined(PRODUCT)
char* Metric::ValueToString(int64_t value, Unit unit) {
Thread* thread = Thread::Current();
ASSERT(thread != nullptr);
Zone* zone = thread->zone();
ASSERT(zone != nullptr);
switch (unit) {
case kCounter:
return zone->PrintToString("%" Pd64 "", value);
case kByte: {
const char* scaled_suffix = "B";
double scaled_value = static_cast<double>(value);
if (value > GB) {
scaled_suffix = "GB";
scaled_value /= GB;
} else if (value > MB) {
scaled_suffix = "MB";
scaled_value /= MB;
} else if (value > KB) {
scaled_suffix = "kB";
scaled_value /= KB;
}
return zone->PrintToString("%.3f %s (%" Pd64 " B)", scaled_value,
scaled_suffix, value);
}
case kMicrosecond: {
const char* scaled_suffix = "us";
double scaled_value = static_cast<double>(value);
if (value > kMicrosecondsPerSecond) {
scaled_suffix = "s";
scaled_value /= kMicrosecondsPerSecond;
} else if (value > kMicrosecondsPerMillisecond) {
scaled_suffix = "ms";
scaled_value /= kMicrosecondsPerMillisecond;
}
return zone->PrintToString("%.3f %s (%" Pd64 " us)", scaled_value,
scaled_suffix, value);
}
default:
UNREACHABLE();
return nullptr;
}
}
char* Metric::ToString() {
Thread* thread = Thread::Current();
ASSERT(thread != nullptr);
Zone* zone = thread->zone();
ASSERT(zone != nullptr);
return zone->PrintToString("%s %s", name(), ValueToString(Value(), unit()));
}
int64_t MetricHeapOldUsed::Value() const {
ASSERT(isolate_group() == IsolateGroup::Current());
return isolate_group()->heap()->UsedInWords(Heap::kOld) * kWordSize;
}
int64_t MetricHeapOldCapacity::Value() const {
ASSERT(isolate_group() == IsolateGroup::Current());
return isolate_group()->heap()->CapacityInWords(Heap::kOld) * kWordSize;
}
int64_t MetricHeapOldExternal::Value() const {
ASSERT(isolate_group() == IsolateGroup::Current());
return isolate_group()->heap()->ExternalInWords(Heap::kOld) * kWordSize;
}
int64_t MetricHeapNewUsed::Value() const {
ASSERT(isolate_group() == IsolateGroup::Current());
// UsedInWords requires a safepoint to access all the TLAB pointers without a
// data race, so coarsen this metric to capacity. Preferable to locking during
// new-space allocation.
return isolate_group()->heap()->CapacityInWords(Heap::kNew) * kWordSize;
}
int64_t MetricHeapNewCapacity::Value() const {
ASSERT(isolate_group() == IsolateGroup::Current());
return isolate_group()->heap()->CapacityInWords(Heap::kNew) * kWordSize;
}
int64_t MetricHeapNewExternal::Value() const {
ASSERT(isolate_group() == IsolateGroup::Current());
return isolate_group()->heap()->ExternalInWords(Heap::kNew) * kWordSize;
}
int64_t MetricHeapUsed::Value() const {
ASSERT(isolate_group() == IsolateGroup::Current());
return isolate_group()->heap()->UsedInWords(Heap::kNew) * kWordSize +
isolate_group()->heap()->UsedInWords(Heap::kOld) * kWordSize;
}
int64_t MetricIsolateCount::Value() const {
return Isolate::IsolateListLength();
}
#if !defined(PRODUCT)
int64_t MetricCurrentRSS::Value() const {
return Service::CurrentRSS();
}
int64_t MetricPeakRSS::Value() const {
return Service::MaxRSS();
}
#endif // !defined(PRODUCT)
MaxMetric::MaxMetric() : Metric() {
set_value(kMinInt64);
}
void MaxMetric::SetValue(int64_t new_value) {
if (new_value > value()) {
set_value(new_value);
}
}
MinMetric::MinMetric() : Metric() {
set_value(kMaxInt64);
}
void MinMetric::SetValue(int64_t new_value) {
if (new_value < value()) {
set_value(new_value);
}
}
} // namespace dart