blob: 59515fcf35812fd3d8536e5d4fa84c792552244e [file] [log] [blame]
// 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;
}
#if !defined(PRODUCT)
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;
}
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;
}
#if !defined(PRODUCT)
int64_t MetricIsolateCount::Value() const {
return Isolate::IsolateListLength();
}
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