1// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/metrics.h"
6
7#include "vm/isolate.h"
8#include "vm/json_stream.h"
9#include "vm/log.h"
10#include "vm/native_entry.h"
11#include "vm/object.h"
12#include "vm/runtime_entry.h"
13
14namespace dart {
15
16DEFINE_FLAG(bool,
17 print_metrics,
18 false,
19 "Print metrics when isolates (and the VM) are shutdown.");
20
21Metric* Metric::vm_list_head_ = NULL;
22
23Metric::Metric() : unit_(kCounter), value_(0) {}
24Metric::~Metric() {}
25
26void Metric::InitInstance(IsolateGroup* isolate_group,
27 const char* name,
28 const char* description,
29 Unit unit) {
30 // Only called once.
31 ASSERT(name != NULL);
32 isolate_group_ = isolate_group;
33 name_ = name;
34 description_ = description;
35 unit_ = unit;
36}
37
38#if !defined(PRODUCT)
39void Metric::InitInstance(Isolate* isolate,
40 const char* name,
41 const char* description,
42 Unit unit) {
43 // Only called once.
44 ASSERT(name != NULL);
45 isolate_ = isolate;
46 name_ = name;
47 description_ = description;
48 unit_ = unit;
49}
50
51void Metric::InitInstance(const char* name,
52 const char* description,
53 Unit unit) {
54 // Only called once.
55 ASSERT(name != NULL);
56 name_ = name;
57 description_ = description;
58 unit_ = unit;
59}
60
61static const char* UnitString(intptr_t unit) {
62 switch (unit) {
63 case Metric::kCounter:
64 return "counter";
65 case Metric::kByte:
66 return "byte";
67 case Metric::kMicrosecond:
68 return "us";
69 default:
70 UNREACHABLE();
71 }
72 UNREACHABLE();
73 return NULL;
74}
75
76void Metric::PrintJSON(JSONStream* stream) {
77 JSONObject obj(stream);
78 obj.AddProperty("type", "Counter");
79 obj.AddProperty("name", name_);
80 obj.AddProperty("description", description_);
81 obj.AddProperty("unit", UnitString(unit()));
82 if (isolate_ == nullptr && isolate_group_ == nullptr) {
83 obj.AddFixedServiceId("vm/metrics/%s", name_);
84 } else {
85 obj.AddFixedServiceId("metrics/native/%s", name_);
86 }
87 // TODO(johnmccutchan): Overflow?
88 double value_as_double = static_cast<double>(Value());
89 obj.AddProperty("value", value_as_double);
90}
91#endif // !defined(PRODUCT)
92
93char* Metric::ValueToString(int64_t value, Unit unit) {
94 Thread* thread = Thread::Current();
95 ASSERT(thread != NULL);
96 Zone* zone = thread->zone();
97 ASSERT(zone != NULL);
98 switch (unit) {
99 case kCounter:
100 return zone->PrintToString("%" Pd64 "", value);
101 case kByte: {
102 const char* scaled_suffix = "B";
103 double scaled_value = static_cast<double>(value);
104 if (value > GB) {
105 scaled_suffix = "GB";
106 scaled_value /= GB;
107 } else if (value > MB) {
108 scaled_suffix = "MB";
109 scaled_value /= MB;
110 } else if (value > KB) {
111 scaled_suffix = "kB";
112 scaled_value /= KB;
113 }
114 return zone->PrintToString("%.3f %s (%" Pd64 " B)", scaled_value,
115 scaled_suffix, value);
116 }
117 case kMicrosecond: {
118 const char* scaled_suffix = "us";
119 double scaled_value = static_cast<double>(value);
120 if (value > kMicrosecondsPerSecond) {
121 scaled_suffix = "s";
122 scaled_value /= kMicrosecondsPerSecond;
123 } else if (value > kMicrosecondsPerMillisecond) {
124 scaled_suffix = "ms";
125 scaled_value /= kMicrosecondsPerMillisecond;
126 }
127 return zone->PrintToString("%.3f %s (%" Pd64 " us)", scaled_value,
128 scaled_suffix, value);
129 }
130 default:
131 UNREACHABLE();
132 return NULL;
133 }
134}
135
136char* Metric::ToString() {
137 Thread* thread = Thread::Current();
138 ASSERT(thread != NULL);
139 Zone* zone = thread->zone();
140 ASSERT(zone != NULL);
141 return zone->PrintToString("%s %s", name(), ValueToString(Value(), unit()));
142}
143
144int64_t MetricHeapOldUsed::Value() const {
145 ASSERT(isolate_group() == IsolateGroup::Current());
146 return isolate_group()->heap()->UsedInWords(Heap::kOld) * kWordSize;
147}
148
149int64_t MetricHeapOldCapacity::Value() const {
150 ASSERT(isolate_group() == IsolateGroup::Current());
151 return isolate_group()->heap()->CapacityInWords(Heap::kOld) * kWordSize;
152}
153
154int64_t MetricHeapOldExternal::Value() const {
155 ASSERT(isolate_group() == IsolateGroup::Current());
156 return isolate_group()->heap()->ExternalInWords(Heap::kOld) * kWordSize;
157}
158
159int64_t MetricHeapNewUsed::Value() const {
160 ASSERT(isolate_group() == IsolateGroup::Current());
161 return isolate_group()->heap()->UsedInWords(Heap::kNew) * kWordSize;
162}
163
164int64_t MetricHeapNewCapacity::Value() const {
165 ASSERT(isolate_group() == IsolateGroup::Current());
166 return isolate_group()->heap()->CapacityInWords(Heap::kNew) * kWordSize;
167}
168
169int64_t MetricHeapNewExternal::Value() const {
170 ASSERT(isolate_group() == IsolateGroup::Current());
171 return isolate_group()->heap()->ExternalInWords(Heap::kNew) * kWordSize;
172}
173
174int64_t MetricHeapUsed::Value() const {
175 ASSERT(isolate_group() == IsolateGroup::Current());
176 return isolate_group()->heap()->UsedInWords(Heap::kNew) * kWordSize +
177 isolate_group()->heap()->UsedInWords(Heap::kOld) * kWordSize;
178}
179
180#if !defined(PRODUCT)
181int64_t MetricIsolateCount::Value() const {
182 return Isolate::IsolateListLength();
183}
184
185int64_t MetricCurrentRSS::Value() const {
186 return Service::CurrentRSS();
187}
188
189int64_t MetricPeakRSS::Value() const {
190 return Service::MaxRSS();
191}
192#endif // !defined(PRODUCT)
193
194#if !defined(PRODUCT)
195
196#define VM_METRIC_VARIABLE(type, variable, name, unit) \
197 type vm_metric_##variable;
198VM_METRIC_LIST(VM_METRIC_VARIABLE);
199#undef VM_METRIC_VARIABLE
200
201void Metric::Init() {
202#define VM_METRIC_INIT(type, variable, name, unit) \
203 vm_metric_##variable.InitInstance(name, NULL, Metric::unit);
204 VM_METRIC_LIST(VM_METRIC_INIT);
205#undef VM_METRIC_INIT
206}
207
208void Metric::Cleanup() {
209 if (FLAG_print_metrics || FLAG_print_benchmarking_metrics) {
210 // Create a zone to allocate temporary strings in.
211 StackZone sz(Thread::Current());
212 OS::PrintErr("Printing metrics for VM\n");
213
214#define VM_METRIC_INIT(type, variable, name, unit) \
215 OS::PrintErr("%s\n", vm_metric_##variable.ToString());
216 VM_METRIC_LIST(VM_METRIC_INIT);
217#undef VM_METRIC_INIT
218 OS::PrintErr("\n");
219 }
220}
221
222#endif // !defined(PRODUCT)
223
224MaxMetric::MaxMetric() : Metric() {
225 set_value(kMinInt64);
226}
227
228void MaxMetric::SetValue(int64_t new_value) {
229 if (new_value > value()) {
230 set_value(new_value);
231 }
232}
233
234MinMetric::MinMetric() : Metric() {
235 set_value(kMaxInt64);
236}
237
238void MinMetric::SetValue(int64_t new_value) {
239 if (new_value < value()) {
240 set_value(new_value);
241 }
242}
243
244} // namespace dart
245