blob: e1b7a9afaab190aa10412cffd381f88b05a0773d [file] [log] [blame]
// Copyright (c) 2016, 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
part of repositories;
class Metric implements M.Metric {
final String id;
String get name => internal.name;
String get description => internal.description;
final internal;
Metric(this.id, this.internal);
}
class MetricSample implements M.MetricSample {
final double value;
final DateTime time = new DateTime.now();
MetricSample(this.value);
}
class MetricRepository implements M.MetricRepository {
final Map<S.Isolate, Map<Metric, List<M.MetricSample>>> _samples =
<S.Isolate, Map<Metric, List<M.MetricSample>>>{};
final Map<S.Isolate, Map<Metric, int>> _rates =
<S.Isolate, Map<Metric, int>>{};
final Map<S.Isolate, Map<Metric, int>> _sizes =
<S.Isolate, Map<Metric, int>>{};
Timer? _timer;
int count = 0;
Future<Iterable<Metric>> list(M.IsolateRef i) async {
S.Isolate isolate = i as S.Isolate;
assert(isolate != null);
if (_samples.containsKey(isolate)) {
return _samples[isolate]!.keys;
}
return const [];
}
Future startSampling(M.IsolateRef i) async {
S.Isolate isolate = i as S.Isolate;
assert(isolate != null);
if (!_samples.containsKey(isolate)) {
await isolate.refreshMetrics();
final samples = _samples[isolate] = <Metric, List<M.MetricSample>>{};
final rates = _rates[isolate] = <Metric, int>{};
final sizes = _sizes[isolate] = <Metric, int>{};
final metrics = []
..addAll(isolate.dartMetrics.keys
.map((name) => new Metric(name, isolate.dartMetrics[name]))
.toList())
..addAll(isolate.nativeMetrics.keys
.map((name) => new Metric(name, isolate.nativeMetrics[name]))
.toList());
for (final metric in metrics) {
samples[metric] = [new MetricSample(metric.internal.value)];
rates[metric] = _rateToInteger(M.MetricSamplingRate.off);
sizes[metric] = _sizeToInteger(M.MetricBufferSize.n100samples);
}
if (_samples.length == 1) {
count = 0;
_timer = new Timer.periodic(new Duration(milliseconds: 100), _update);
}
}
}
Future stopSampling(M.IsolateRef isolate) async {
if (_samples.containsKey(isolate)) {
_samples.remove(isolate);
_rates.remove(isolate);
_sizes.remove(isolate);
if (_samples.isEmpty) {
_timer!.cancel();
}
}
}
M.MetricSamplingRate getSamplingRate(M.IsolateRef i, M.Metric m) {
if (_rates.containsKey(i)) {
final metrics = _rates[i]!;
if (metrics.containsKey(m)) {
switch (metrics[m]) {
case 0:
return M.MetricSamplingRate.off;
case 1:
return M.MetricSamplingRate.e100ms;
case 10:
return M.MetricSamplingRate.e1s;
case 20:
return M.MetricSamplingRate.e2s;
case 40:
return M.MetricSamplingRate.e4s;
case 80:
return M.MetricSamplingRate.e8s;
}
}
}
throw new Exception('Sampling for isolate ${i.id} is not started');
}
void setSamplingRate(M.IsolateRef i, M.Metric m, M.MetricSamplingRate r) {
if (_rates.containsKey(i)) {
final metrics = _rates[i]!;
if (metrics.containsKey(m)) {
metrics[m as Metric] = _rateToInteger(r);
}
} else {
throw new Exception('Sampling for isolate ${i.id} is not started');
}
}
M.MetricBufferSize getBufferSize(M.IsolateRef i, M.Metric m) {
if (_sizes.containsKey(i)) {
final metrics = _sizes[i]!;
if (metrics.containsKey(m)) {
switch (metrics[m]) {
case 10:
return M.MetricBufferSize.n10samples;
case 100:
return M.MetricBufferSize.n100samples;
case 1000:
return M.MetricBufferSize.n1000samples;
}
}
}
throw new Exception('Sampling for isolate ${i.id} is not started');
}
void setBufferSize(M.IsolateRef i, M.Metric m, M.MetricBufferSize s) {
if (_sizes.containsKey(i)) {
final metrics = _sizes[i]!;
if (metrics.containsKey(m)) {
metrics[m as Metric] = _sizeToInteger(s);
}
} else {
throw new Exception('Sampling for isolate ${i.id} is not started');
}
}
static int _rateToInteger(M.MetricSamplingRate r) {
switch (r) {
case M.MetricSamplingRate.off:
return 0;
case M.MetricSamplingRate.e100ms:
return 1;
case M.MetricSamplingRate.e1s:
return 10;
case M.MetricSamplingRate.e2s:
return 20;
case M.MetricSamplingRate.e4s:
return 40;
case M.MetricSamplingRate.e8s:
return 80;
}
throw new Exception('Unknown MetricSamplingRate ($r)');
}
static int _sizeToInteger(M.MetricBufferSize s) {
switch (s) {
case M.MetricBufferSize.n10samples:
return 10;
case M.MetricBufferSize.n100samples:
return 100;
case M.MetricBufferSize.n1000samples:
return 1000;
}
throw new Exception('Unknown MetricBufferSize ($s)');
}
Iterable<M.MetricSample>? getSamples(M.IsolateRef i, M.Metric m) {
if (_samples.containsKey(i)) {
final metrics = _samples[i]!;
if (metrics.containsKey(m)) {
return metrics[m];
}
}
return null;
}
double getMinValue(M.IsolateRef i, M.Metric m) {
Metric metric = m as Metric;
assert(metric != null);
return metric.internal.min;
}
double getMaxValue(M.IsolateRef i, M.Metric m) {
Metric metric = m as Metric;
assert(metric != null);
return metric.internal.max;
}
void _update(_) {
for (final isolate in _rates.keys) {
final metrics = _rates[isolate]!;
for (final metric in metrics.keys) {
final rate = metrics[metric]!;
if (rate != 0 && count % rate == 0) {
final size = _sizes[isolate]![metric]!;
final samples = _samples[isolate]![metric]!;
metric.internal.reload().then((m) {
if (samples.length >= size) {
samples.removeRange(0, samples.length - size + 1);
}
samples.add(new MetricSample(m.value));
});
}
}
}
++count;
}
}