| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/metrics.h" | 5 #include "vm/metrics.h" |
| 6 | 6 |
| 7 #include "vm/isolate.h" | 7 #include "vm/isolate.h" |
| 8 #include "vm/json_stream.h" | 8 #include "vm/json_stream.h" |
| 9 #include "vm/log.h" |
| 9 #include "vm/native_entry.h" | 10 #include "vm/native_entry.h" |
| 11 #include "vm/object.h" |
| 10 #include "vm/runtime_entry.h" | 12 #include "vm/runtime_entry.h" |
| 11 #include "vm/object.h" | |
| 12 #include "vm/log.h" | |
| 13 | 13 |
| 14 namespace dart { | 14 namespace dart { |
| 15 | 15 |
| 16 DEFINE_FLAG(bool, | 16 DEFINE_FLAG(bool, |
| 17 print_metrics, | 17 print_metrics, |
| 18 false, | 18 false, |
| 19 "Print metrics when isolates (and the VM) are shutdown."); | 19 "Print metrics when isolates (and the VM) are shutdown."); |
| 20 | 20 |
| 21 Metric* Metric::vm_list_head_ = NULL; | 21 Metric* Metric::vm_list_head_ = NULL; |
| 22 | 22 |
| 23 Metric::Metric() | 23 Metric::Metric() |
| 24 : isolate_(NULL), | 24 : isolate_(NULL), |
| 25 name_(NULL), | 25 name_(NULL), |
| 26 description_(NULL), | 26 description_(NULL), |
| 27 unit_(kCounter), | 27 unit_(kCounter), |
| 28 value_(0), | 28 value_(0), |
| 29 next_(NULL) {} | 29 next_(NULL) {} |
| 30 | 30 |
| 31 | |
| 32 void Metric::Init(Isolate* isolate, | 31 void Metric::Init(Isolate* isolate, |
| 33 const char* name, | 32 const char* name, |
| 34 const char* description, | 33 const char* description, |
| 35 Unit unit) { | 34 Unit unit) { |
| 36 // Only called once. | 35 // Only called once. |
| 37 ASSERT(next_ == NULL); | 36 ASSERT(next_ == NULL); |
| 38 ASSERT(name != NULL); | 37 ASSERT(name != NULL); |
| 39 isolate_ = isolate; | 38 isolate_ = isolate; |
| 40 name_ = name; | 39 name_ = name; |
| 41 description_ = description; | 40 description_ = description; |
| 42 unit_ = unit; | 41 unit_ = unit; |
| 43 RegisterWithIsolate(); | 42 RegisterWithIsolate(); |
| 44 } | 43 } |
| 45 | 44 |
| 46 | |
| 47 void Metric::Init(const char* name, const char* description, Unit unit) { | 45 void Metric::Init(const char* name, const char* description, Unit unit) { |
| 48 // Only called once. | 46 // Only called once. |
| 49 ASSERT(next_ == NULL); | 47 ASSERT(next_ == NULL); |
| 50 ASSERT(name != NULL); | 48 ASSERT(name != NULL); |
| 51 name_ = name; | 49 name_ = name; |
| 52 description_ = description; | 50 description_ = description; |
| 53 unit_ = unit; | 51 unit_ = unit; |
| 54 RegisterWithVM(); | 52 RegisterWithVM(); |
| 55 } | 53 } |
| 56 | 54 |
| 57 | |
| 58 Metric::~Metric() { | 55 Metric::~Metric() { |
| 59 // Only deregister metrics which had been registered. Metrics without a name | 56 // Only deregister metrics which had been registered. Metrics without a name |
| 60 // are from shallow copy isolates. | 57 // are from shallow copy isolates. |
| 61 if (name_ != NULL) { | 58 if (name_ != NULL) { |
| 62 if (isolate_ == NULL) { | 59 if (isolate_ == NULL) { |
| 63 DeregisterWithVM(); | 60 DeregisterWithVM(); |
| 64 } else { | 61 } else { |
| 65 DeregisterWithIsolate(); | 62 DeregisterWithIsolate(); |
| 66 } | 63 } |
| 67 } | 64 } |
| 68 } | 65 } |
| 69 | 66 |
| 70 | |
| 71 #ifndef PRODUCT | 67 #ifndef PRODUCT |
| 72 static const char* UnitString(intptr_t unit) { | 68 static const char* UnitString(intptr_t unit) { |
| 73 switch (unit) { | 69 switch (unit) { |
| 74 case Metric::kCounter: | 70 case Metric::kCounter: |
| 75 return "counter"; | 71 return "counter"; |
| 76 case Metric::kByte: | 72 case Metric::kByte: |
| 77 return "byte"; | 73 return "byte"; |
| 78 case Metric::kMicrosecond: | 74 case Metric::kMicrosecond: |
| 79 return "us"; | 75 return "us"; |
| 80 default: | 76 default: |
| 81 UNREACHABLE(); | 77 UNREACHABLE(); |
| 82 } | 78 } |
| 83 UNREACHABLE(); | 79 UNREACHABLE(); |
| 84 return NULL; | 80 return NULL; |
| 85 } | 81 } |
| 86 | 82 |
| 87 | |
| 88 void Metric::PrintJSON(JSONStream* stream) { | 83 void Metric::PrintJSON(JSONStream* stream) { |
| 89 if (!FLAG_support_service) { | 84 if (!FLAG_support_service) { |
| 90 return; | 85 return; |
| 91 } | 86 } |
| 92 JSONObject obj(stream); | 87 JSONObject obj(stream); |
| 93 obj.AddProperty("type", "Counter"); | 88 obj.AddProperty("type", "Counter"); |
| 94 obj.AddProperty("name", name_); | 89 obj.AddProperty("name", name_); |
| 95 obj.AddProperty("description", description_); | 90 obj.AddProperty("description", description_); |
| 96 obj.AddProperty("unit", UnitString(unit())); | 91 obj.AddProperty("unit", UnitString(unit())); |
| 97 if (isolate_ == NULL) { | 92 if (isolate_ == NULL) { |
| 98 obj.AddFixedServiceId("vm/metrics/%s", name_); | 93 obj.AddFixedServiceId("vm/metrics/%s", name_); |
| 99 } else { | 94 } else { |
| 100 obj.AddFixedServiceId("metrics/native/%s", name_); | 95 obj.AddFixedServiceId("metrics/native/%s", name_); |
| 101 } | 96 } |
| 102 // TODO(johnmccutchan): Overflow? | 97 // TODO(johnmccutchan): Overflow? |
| 103 double value_as_double = static_cast<double>(Value()); | 98 double value_as_double = static_cast<double>(Value()); |
| 104 obj.AddProperty("value", value_as_double); | 99 obj.AddProperty("value", value_as_double); |
| 105 } | 100 } |
| 106 #endif // !PRODUCT | 101 #endif // !PRODUCT |
| 107 | 102 |
| 108 | |
| 109 char* Metric::ValueToString(int64_t value, Unit unit) { | 103 char* Metric::ValueToString(int64_t value, Unit unit) { |
| 110 Thread* thread = Thread::Current(); | 104 Thread* thread = Thread::Current(); |
| 111 ASSERT(thread != NULL); | 105 ASSERT(thread != NULL); |
| 112 Zone* zone = thread->zone(); | 106 Zone* zone = thread->zone(); |
| 113 ASSERT(zone != NULL); | 107 ASSERT(zone != NULL); |
| 114 switch (unit) { | 108 switch (unit) { |
| 115 case kCounter: | 109 case kCounter: |
| 116 return zone->PrintToString("%" Pd64 "", value); | 110 return zone->PrintToString("%" Pd64 "", value); |
| 117 case kByte: { | 111 case kByte: { |
| 118 const char* scaled_suffix = "B"; | 112 const char* scaled_suffix = "B"; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 142 } | 136 } |
| 143 return zone->PrintToString("%.3f %s (%" Pd64 " us)", scaled_value, | 137 return zone->PrintToString("%.3f %s (%" Pd64 " us)", scaled_value, |
| 144 scaled_suffix, value); | 138 scaled_suffix, value); |
| 145 } | 139 } |
| 146 default: | 140 default: |
| 147 UNREACHABLE(); | 141 UNREACHABLE(); |
| 148 return NULL; | 142 return NULL; |
| 149 } | 143 } |
| 150 } | 144 } |
| 151 | 145 |
| 152 | |
| 153 char* Metric::ToString() { | 146 char* Metric::ToString() { |
| 154 Thread* thread = Thread::Current(); | 147 Thread* thread = Thread::Current(); |
| 155 ASSERT(thread != NULL); | 148 ASSERT(thread != NULL); |
| 156 Zone* zone = thread->zone(); | 149 Zone* zone = thread->zone(); |
| 157 ASSERT(zone != NULL); | 150 ASSERT(zone != NULL); |
| 158 return zone->PrintToString("%s %s", name(), ValueToString(Value(), unit())); | 151 return zone->PrintToString("%s %s", name(), ValueToString(Value(), unit())); |
| 159 } | 152 } |
| 160 | 153 |
| 161 | |
| 162 bool Metric::NameExists(Metric* head, const char* name) { | 154 bool Metric::NameExists(Metric* head, const char* name) { |
| 163 ASSERT(name != NULL); | 155 ASSERT(name != NULL); |
| 164 while (head != NULL) { | 156 while (head != NULL) { |
| 165 const char* metric_name = head->name(); | 157 const char* metric_name = head->name(); |
| 166 ASSERT(metric_name != NULL); | 158 ASSERT(metric_name != NULL); |
| 167 if (strcmp(metric_name, name) == 0) { | 159 if (strcmp(metric_name, name) == 0) { |
| 168 return true; | 160 return true; |
| 169 } | 161 } |
| 170 head = head->next(); | 162 head = head->next(); |
| 171 } | 163 } |
| 172 return false; | 164 return false; |
| 173 } | 165 } |
| 174 | 166 |
| 175 | |
| 176 void Metric::RegisterWithIsolate() { | 167 void Metric::RegisterWithIsolate() { |
| 177 ASSERT(isolate_ != NULL); | 168 ASSERT(isolate_ != NULL); |
| 178 ASSERT(next_ == NULL); | 169 ASSERT(next_ == NULL); |
| 179 // No duplicate names allowed. | 170 // No duplicate names allowed. |
| 180 ASSERT(!NameExists(isolate_->metrics_list_head(), name())); | 171 ASSERT(!NameExists(isolate_->metrics_list_head(), name())); |
| 181 Metric* head = isolate_->metrics_list_head(); | 172 Metric* head = isolate_->metrics_list_head(); |
| 182 if (head != NULL) { | 173 if (head != NULL) { |
| 183 set_next(head); | 174 set_next(head); |
| 184 } | 175 } |
| 185 isolate_->set_metrics_list_head(this); | 176 isolate_->set_metrics_list_head(this); |
| 186 } | 177 } |
| 187 | 178 |
| 188 | |
| 189 void Metric::DeregisterWithIsolate() { | 179 void Metric::DeregisterWithIsolate() { |
| 190 Metric* head = isolate_->metrics_list_head(); | 180 Metric* head = isolate_->metrics_list_head(); |
| 191 ASSERT(head != NULL); | 181 ASSERT(head != NULL); |
| 192 // Handle head of list case. | 182 // Handle head of list case. |
| 193 if (head == this) { | 183 if (head == this) { |
| 194 isolate_->set_metrics_list_head(next()); | 184 isolate_->set_metrics_list_head(next()); |
| 195 set_next(NULL); | 185 set_next(NULL); |
| 196 return; | 186 return; |
| 197 } | 187 } |
| 198 Metric* previous = NULL; | 188 Metric* previous = NULL; |
| 199 while (true) { | 189 while (true) { |
| 200 previous = head; | 190 previous = head; |
| 201 ASSERT(previous != NULL); | 191 ASSERT(previous != NULL); |
| 202 head = head->next(); | 192 head = head->next(); |
| 203 if (head == NULL) { | 193 if (head == NULL) { |
| 204 break; | 194 break; |
| 205 } | 195 } |
| 206 if (head == this) { | 196 if (head == this) { |
| 207 // Remove this from list. | 197 // Remove this from list. |
| 208 previous->set_next(head->next()); | 198 previous->set_next(head->next()); |
| 209 set_next(NULL); | 199 set_next(NULL); |
| 210 return; | 200 return; |
| 211 } | 201 } |
| 212 ASSERT(head != NULL); | 202 ASSERT(head != NULL); |
| 213 } | 203 } |
| 214 UNREACHABLE(); | 204 UNREACHABLE(); |
| 215 } | 205 } |
| 216 | 206 |
| 217 | |
| 218 void Metric::RegisterWithVM() { | 207 void Metric::RegisterWithVM() { |
| 219 ASSERT(isolate_ == NULL); | 208 ASSERT(isolate_ == NULL); |
| 220 ASSERT(next_ == NULL); | 209 ASSERT(next_ == NULL); |
| 221 // No duplicate names allowed. | 210 // No duplicate names allowed. |
| 222 ASSERT(!NameExists(vm_list_head_, name())); | 211 ASSERT(!NameExists(vm_list_head_, name())); |
| 223 Metric* head = vm_list_head_; | 212 Metric* head = vm_list_head_; |
| 224 if (head != NULL) { | 213 if (head != NULL) { |
| 225 set_next(head); | 214 set_next(head); |
| 226 } | 215 } |
| 227 vm_list_head_ = this; | 216 vm_list_head_ = this; |
| 228 } | 217 } |
| 229 | 218 |
| 230 | |
| 231 void Metric::DeregisterWithVM() { | 219 void Metric::DeregisterWithVM() { |
| 232 ASSERT(isolate_ == NULL); | 220 ASSERT(isolate_ == NULL); |
| 233 Metric* head = vm_list_head_; | 221 Metric* head = vm_list_head_; |
| 234 if (head == NULL) { | 222 if (head == NULL) { |
| 235 return; | 223 return; |
| 236 } | 224 } |
| 237 // Handle head of list case. | 225 // Handle head of list case. |
| 238 if (head == this) { | 226 if (head == this) { |
| 239 vm_list_head_ = next(); | 227 vm_list_head_ = next(); |
| 240 set_next(NULL); | 228 set_next(NULL); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 252 // Remove this from list. | 240 // Remove this from list. |
| 253 previous->set_next(head->next()); | 241 previous->set_next(head->next()); |
| 254 set_next(NULL); | 242 set_next(NULL); |
| 255 return; | 243 return; |
| 256 } | 244 } |
| 257 ASSERT(head != NULL); | 245 ASSERT(head != NULL); |
| 258 } | 246 } |
| 259 UNREACHABLE(); | 247 UNREACHABLE(); |
| 260 } | 248 } |
| 261 | 249 |
| 262 | |
| 263 int64_t MetricHeapOldUsed::Value() const { | 250 int64_t MetricHeapOldUsed::Value() const { |
| 264 ASSERT(isolate() == Isolate::Current()); | 251 ASSERT(isolate() == Isolate::Current()); |
| 265 return isolate()->heap()->UsedInWords(Heap::kOld) * kWordSize; | 252 return isolate()->heap()->UsedInWords(Heap::kOld) * kWordSize; |
| 266 } | 253 } |
| 267 | 254 |
| 268 | |
| 269 int64_t MetricHeapOldCapacity::Value() const { | 255 int64_t MetricHeapOldCapacity::Value() const { |
| 270 ASSERT(isolate() == Isolate::Current()); | 256 ASSERT(isolate() == Isolate::Current()); |
| 271 return isolate()->heap()->CapacityInWords(Heap::kOld) * kWordSize; | 257 return isolate()->heap()->CapacityInWords(Heap::kOld) * kWordSize; |
| 272 } | 258 } |
| 273 | 259 |
| 274 | |
| 275 int64_t MetricHeapOldExternal::Value() const { | 260 int64_t MetricHeapOldExternal::Value() const { |
| 276 ASSERT(isolate() == Isolate::Current()); | 261 ASSERT(isolate() == Isolate::Current()); |
| 277 return isolate()->heap()->ExternalInWords(Heap::kOld) * kWordSize; | 262 return isolate()->heap()->ExternalInWords(Heap::kOld) * kWordSize; |
| 278 } | 263 } |
| 279 | 264 |
| 280 | |
| 281 int64_t MetricHeapNewUsed::Value() const { | 265 int64_t MetricHeapNewUsed::Value() const { |
| 282 ASSERT(isolate() == Isolate::Current()); | 266 ASSERT(isolate() == Isolate::Current()); |
| 283 return isolate()->heap()->UsedInWords(Heap::kNew) * kWordSize; | 267 return isolate()->heap()->UsedInWords(Heap::kNew) * kWordSize; |
| 284 } | 268 } |
| 285 | 269 |
| 286 | |
| 287 int64_t MetricHeapNewCapacity::Value() const { | 270 int64_t MetricHeapNewCapacity::Value() const { |
| 288 ASSERT(isolate() == Isolate::Current()); | 271 ASSERT(isolate() == Isolate::Current()); |
| 289 return isolate()->heap()->CapacityInWords(Heap::kNew) * kWordSize; | 272 return isolate()->heap()->CapacityInWords(Heap::kNew) * kWordSize; |
| 290 } | 273 } |
| 291 | 274 |
| 292 | |
| 293 int64_t MetricHeapNewExternal::Value() const { | 275 int64_t MetricHeapNewExternal::Value() const { |
| 294 ASSERT(isolate() == Isolate::Current()); | 276 ASSERT(isolate() == Isolate::Current()); |
| 295 return isolate()->heap()->ExternalInWords(Heap::kNew) * kWordSize; | 277 return isolate()->heap()->ExternalInWords(Heap::kNew) * kWordSize; |
| 296 } | 278 } |
| 297 | 279 |
| 298 | |
| 299 int64_t MetricHeapUsed::Value() const { | 280 int64_t MetricHeapUsed::Value() const { |
| 300 ASSERT(isolate() == Isolate::Current()); | 281 ASSERT(isolate() == Isolate::Current()); |
| 301 return isolate()->heap()->UsedInWords(Heap::kNew) * kWordSize + | 282 return isolate()->heap()->UsedInWords(Heap::kNew) * kWordSize + |
| 302 isolate()->heap()->UsedInWords(Heap::kOld) * kWordSize; | 283 isolate()->heap()->UsedInWords(Heap::kOld) * kWordSize; |
| 303 } | 284 } |
| 304 | 285 |
| 305 int64_t MetricIsolateCount::Value() const { | 286 int64_t MetricIsolateCount::Value() const { |
| 306 return Isolate::IsolateListLength(); | 287 return Isolate::IsolateListLength(); |
| 307 } | 288 } |
| 308 | 289 |
| 309 | |
| 310 int64_t MetricPeakRSS::Value() const { | 290 int64_t MetricPeakRSS::Value() const { |
| 311 return OS::MaxRSS(); | 291 return OS::MaxRSS(); |
| 312 } | 292 } |
| 313 | 293 |
| 314 #define VM_METRIC_VARIABLE(type, variable, name, unit) \ | 294 #define VM_METRIC_VARIABLE(type, variable, name, unit) \ |
| 315 static type vm_metric_##variable##_; | 295 static type vm_metric_##variable##_; |
| 316 VM_METRIC_LIST(VM_METRIC_VARIABLE); | 296 VM_METRIC_LIST(VM_METRIC_VARIABLE); |
| 317 #undef VM_METRIC_VARIABLE | 297 #undef VM_METRIC_VARIABLE |
| 318 | 298 |
| 319 | |
| 320 void Metric::InitOnce() { | 299 void Metric::InitOnce() { |
| 321 #define VM_METRIC_INIT(type, variable, name, unit) \ | 300 #define VM_METRIC_INIT(type, variable, name, unit) \ |
| 322 vm_metric_##variable##_.Init(name, NULL, Metric::unit); | 301 vm_metric_##variable##_.Init(name, NULL, Metric::unit); |
| 323 VM_METRIC_LIST(VM_METRIC_INIT); | 302 VM_METRIC_LIST(VM_METRIC_INIT); |
| 324 #undef VM_METRIC_INIT | 303 #undef VM_METRIC_INIT |
| 325 } | 304 } |
| 326 | 305 |
| 327 void Metric::Cleanup() { | 306 void Metric::Cleanup() { |
| 328 if (FLAG_print_metrics || FLAG_print_benchmarking_metrics) { | 307 if (FLAG_print_metrics || FLAG_print_benchmarking_metrics) { |
| 329 // Create a zone to allocate temporary strings in. | 308 // Create a zone to allocate temporary strings in. |
| 330 StackZone sz(Thread::Current()); | 309 StackZone sz(Thread::Current()); |
| 331 OS::PrintErr("Printing metrics for VM\n"); | 310 OS::PrintErr("Printing metrics for VM\n"); |
| 332 Metric* current = Metric::vm_head(); | 311 Metric* current = Metric::vm_head(); |
| 333 while (current != NULL) { | 312 while (current != NULL) { |
| 334 OS::PrintErr("%s\n", current->ToString()); | 313 OS::PrintErr("%s\n", current->ToString()); |
| 335 current = current->next(); | 314 current = current->next(); |
| 336 } | 315 } |
| 337 OS::PrintErr("\n"); | 316 OS::PrintErr("\n"); |
| 338 } | 317 } |
| 339 } | 318 } |
| 340 | 319 |
| 341 | |
| 342 MaxMetric::MaxMetric() : Metric() { | 320 MaxMetric::MaxMetric() : Metric() { |
| 343 set_value(kMinInt64); | 321 set_value(kMinInt64); |
| 344 } | 322 } |
| 345 | 323 |
| 346 | |
| 347 void MaxMetric::SetValue(int64_t new_value) { | 324 void MaxMetric::SetValue(int64_t new_value) { |
| 348 if (new_value > value()) { | 325 if (new_value > value()) { |
| 349 set_value(new_value); | 326 set_value(new_value); |
| 350 } | 327 } |
| 351 } | 328 } |
| 352 | 329 |
| 353 | |
| 354 MinMetric::MinMetric() : Metric() { | 330 MinMetric::MinMetric() : Metric() { |
| 355 set_value(kMaxInt64); | 331 set_value(kMaxInt64); |
| 356 } | 332 } |
| 357 | 333 |
| 358 | |
| 359 void MinMetric::SetValue(int64_t new_value) { | 334 void MinMetric::SetValue(int64_t new_value) { |
| 360 if (new_value < value()) { | 335 if (new_value < value()) { |
| 361 set_value(new_value); | 336 set_value(new_value); |
| 362 } | 337 } |
| 363 } | 338 } |
| 364 | 339 |
| 365 } // namespace dart | 340 } // namespace dart |
| OLD | NEW |