| <!DOCTYPE html> |
| <!-- |
| Copyright 2016 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| |
| <link rel="import" href="/tracing/core/test_utils.html"> |
| <link rel="import" href="/tracing/extras/importer/trace_event_importer.html"> |
| <link rel="import" href="/tracing/metrics/blink/gc_metric.html"> |
| <link rel="import" href="/tracing/metrics/v8/utils.html"> |
| <link rel="import" href="/tracing/model/slice_group.html"> |
| <link rel="import" href="/tracing/value/histogram_set.html"> |
| |
| <script> |
| 'use strict'; |
| |
| tr.b.unittest.testSuite(function() { |
| function createModel(start, end, slices) { |
| const opts = { |
| customizeModelCallback(model) { |
| const process = model.getOrCreateProcess(1); |
| const thread = process.getOrCreateThread(2); |
| const group = thread.sliceGroup; |
| slices.forEach(function(slice) { |
| group.pushSlice(tr.c.TestUtils.newSliceEx(slice)); |
| }); |
| group.createSubSlices(); |
| } |
| }; |
| const model = tr.c.TestUtils.newModelWithEvents([], opts); |
| return model; |
| } |
| |
| function constructName(name, suffix) { |
| return name + '_' + suffix; |
| } |
| |
| function run(slices) { |
| const histograms = new tr.v.HistogramSet(); |
| const startTime = slices.reduce( |
| (acc, slice) => (Math.min(acc, slice.start))); |
| const endTime = slices.reduce((acc, slice) => (Math.max(acc, slice.end))); |
| const model = createModel(startTime - 1, endTime + 1, slices); |
| tr.metrics.blink.blinkGcMetric(histograms, model); |
| return histograms; |
| } |
| |
| test('topEvents', function() { |
| const events = { |
| 'BlinkGC.AtomicPhase': 'blink-gc-atomic-phase', |
| 'BlinkGC.CompleteSweep': 'blink-gc-complete-sweep', |
| 'BlinkGC.LazySweepInIdle': 'blink-gc-lazy-sweep-idle' |
| }; |
| for (const [timelineName, telemetryName] of Object.entries(events)) { |
| const slices = [ |
| { |
| title: timelineName, args: {}, start: 100, end: 200, |
| cpuStart: 100, cpuEnd: 200 |
| } |
| ]; |
| const actual = run(slices); |
| |
| let value = actual.getHistogramNamed(telemetryName); |
| assert.strictEqual(value.running.sum, 100); |
| assert.strictEqual(value.numValues, 1); |
| assert.strictEqual(value.average, 100); |
| assert.strictEqual(value.running.max, 100); |
| assert.closeTo(value.getApproximatePercentile(0.90), 100, 1); |
| |
| value = actual.getHistogramNamed( |
| `${telemetryName}_idle_deadline_overrun`); |
| assert.strictEqual(value.running.sum, 0); |
| assert.strictEqual(value.numValues, 1); |
| assert.strictEqual(value.average, 0); |
| assert.strictEqual(value.running.max, 0); |
| |
| value = actual.getHistogramNamed(`${telemetryName}_outside_idle`); |
| assert.strictEqual(value.running.sum, 100); |
| assert.strictEqual(value.numValues, 1); |
| assert.strictEqual(value.average, 100); |
| |
| value = actual.getHistogramNamed(`${telemetryName}_percentage_idle`); |
| assert.strictEqual(value.average, 0); |
| } |
| }); |
| |
| test('idleTimes', function() { |
| const histograms = new tr.v.HistogramSet(); |
| const slices = [ |
| { |
| title: 'SingleThreadIdleTaskRunner::RunTask', |
| args: {'allotted_time_ms': 100}, start: 100, end: 200, |
| cpuStart: 100, cpuEnd: 200 |
| }, |
| { |
| title: 'BlinkGC.AtomicPhase', args: {}, start: 110, end: 190, |
| cpuStart: 110, cpuEnd: 190 |
| } |
| ]; |
| const actual = run(slices); |
| |
| let value = actual.getHistogramNamed('blink-gc-atomic-phase'); |
| assert.strictEqual(value.running.sum, 80); |
| assert.strictEqual(value.numValues, 1); |
| assert.strictEqual(value.average, 80); |
| assert.strictEqual(value.running.max, 80); |
| |
| value = actual.getHistogramNamed( |
| 'blink-gc-atomic-phase_idle_deadline_overrun'); |
| assert.strictEqual(value.running.sum, 0); |
| assert.strictEqual(value.average, 0); |
| assert.strictEqual(value.running.max, 0); |
| |
| value = actual.getHistogramNamed('blink-gc-atomic-phase_outside_idle'); |
| assert.strictEqual(value.running.sum, 0); |
| assert.strictEqual(value.average, 0); |
| assert.strictEqual(value.running.max, 0); |
| |
| value = actual.getHistogramNamed('blink-gc-atomic-phase_percentage_idle'); |
| assert.strictEqual(value.average, 1); |
| }); |
| |
| test('idleTimeOverrun', function() { |
| const histograms = new tr.v.HistogramSet(); |
| const slices = [ |
| { |
| title: 'SingleThreadIdleTaskRunner::RunTask', |
| args: {'allotted_time_ms': 10}, start: 100, end: 200, |
| cpuStart: 100, cpuEnd: 200 |
| }, |
| { |
| title: 'BlinkGC.AtomicPhase', args: {}, start: 110, end: 190, |
| cpuStart: 110, cpuEnd: 190 |
| } |
| ]; |
| const actual = run(slices); |
| |
| let value = actual.getHistogramNamed('blink-gc-atomic-phase'); |
| assert.strictEqual(value.running.sum, 80); |
| assert.strictEqual(value.numValues, 1); |
| assert.strictEqual(value.average, 80); |
| assert.strictEqual(value.running.max, 80); |
| |
| value = actual.getHistogramNamed( |
| 'blink-gc-atomic-phase_idle_deadline_overrun'); |
| assert.strictEqual(value.running.sum, 70); |
| assert.strictEqual(value.average, 70); |
| assert.strictEqual(value.running.max, 70); |
| |
| value = actual.getHistogramNamed('blink-gc-atomic-phase_outside_idle'); |
| assert.strictEqual(value.running.sum, 70); |
| assert.strictEqual(value.average, 70); |
| assert.strictEqual(value.running.max, 70); |
| |
| value = actual.getHistogramNamed('blink-gc-atomic-phase_percentage_idle'); |
| assert.closeTo(value.average, 1 / 8, 1e-6); |
| }); |
| |
| test('totalTimeForBlinkGC', function() { |
| const histograms = new tr.v.HistogramSet(); |
| const slices = [ |
| { |
| title: 'BlinkGC.AtomicPhase', args: {}, start: 100, end: 200, |
| cpuStart: 100, cpuEnd: 200 |
| }, |
| { |
| title: 'BlinkGC.LazySweepInIdle', args: {}, start: 210, |
| end: 290, cpuStart: 210, cpuEnd: 290 |
| } |
| ]; |
| const actual = run(slices); |
| |
| let value = actual.getHistogramNamed('blink-gc-total'); |
| assert.strictEqual(value.running.sum, 180); |
| assert.strictEqual(value.numValues, 2); |
| assert.strictEqual(value.average, 90); |
| assert.strictEqual(value.running.max, 100); |
| |
| value = actual.getHistogramNamed('blink-gc-total_idle_deadline_overrun'); |
| assert.strictEqual(value.running.sum, 0); |
| assert.strictEqual(value.average, 0); |
| assert.strictEqual(value.running.max, 0); |
| |
| value = actual.getHistogramNamed('blink-gc-total_outside_idle'); |
| assert.strictEqual(value.running.sum, 180); |
| assert.strictEqual(value.average, 90); |
| assert.strictEqual(value.running.max, 100); |
| |
| value = actual.getHistogramNamed('blink-gc-total_percentage_idle'); |
| assert.strictEqual(value.average, 0); |
| }); |
| |
| test('totalTimeForUnifiedGC', function() { |
| const histograms = new tr.v.HistogramSet(); |
| const slices = [ |
| { |
| title: 'V8.GCFinalizeMC', args: {}, |
| start: 100, end: 300, cpuStart: 100, cpuEnd: 300 |
| }, |
| { |
| title: 'BlinkGC.AtomicPhase', args: {}, |
| start: 310, end: 410, cpuStart: 310, cpuEnd: 410 |
| } |
| ]; |
| const actual = run(slices); |
| |
| const value = actual.getHistogramNamed('unified-gc-total'); |
| assert.strictEqual(value.running.sum, 300); |
| assert.strictEqual(value.numValues, 2); |
| assert.strictEqual(value.average, 150); |
| assert.strictEqual(value.running.max, 200); |
| }); |
| |
| test('totalTimeForUnifiedGCBlinkNestedInV8', function() { |
| // Nested Blink GC in V8 top-level GC can happen during unified garbage |
| // collection, or when callbacks that trigger e.g. sweeping are fired |
| // from V8's GC. These should only be accounted once. |
| const histograms = new tr.v.HistogramSet(); |
| const slices = [ |
| { |
| title: 'V8.GCFinalizeMC', args: {}, |
| start: 100, end: 300, cpuStart: 100, cpuEnd: 300 |
| }, |
| // Nested events should be ignored. |
| { |
| title: 'BlinkGC.CompleteSweep', args: {}, |
| start: 200, end: 270, cpuStart: 200, cpuEnd: 270 |
| }, |
| { |
| title: 'BlinkGC.IncrementalMarkingStartMarking', args: {}, |
| start: 280, end: 290, cpuStart: 280, cpuEnd: 290 |
| }, |
| // Next event is outside of nesting and should be accounted for. |
| { |
| title: 'BlinkGC.IncrementalMarkingStartMarking', args: {}, |
| start: 310, end: 320, cpuStart: 310, cpuEnd: 320 |
| }, |
| ]; |
| const actual = run(slices); |
| |
| const value = actual.getHistogramNamed('unified-gc-total'); |
| assert.strictEqual(value.running.sum, 210); |
| assert.strictEqual(value.numValues, 2); |
| assert.strictEqual(value.average, 105); |
| assert.strictEqual(value.running.max, 200); |
| }); |
| |
| function getSlicesWithForcedV8GCs() { |
| return [ |
| { |
| title: tr.metrics.v8.utils.forcedGCEventName(), args: {}, |
| start: 100, end: 300, cpuStart: 100, cpuEnd: 300 |
| }, |
| // Following nested events should be ignored. |
| { |
| title: 'V8.GCFinalizeMC', args: {}, |
| start: 100, end: 300, cpuStart: 100, cpuEnd: 300 |
| }, |
| { |
| title: 'BlinkGC.CompleteSweep', args: {}, |
| start: 200, end: 270, cpuStart: 200, cpuEnd: 270 |
| }, |
| { |
| title: 'BlinkGC.IncrementalMarkingStartMarking', args: {}, |
| start: 280, end: 290, cpuStart: 280, cpuEnd: 290 |
| }, |
| // Next event happens after the forced GC and should be accounted for. |
| { |
| title: 'BlinkGC.IncrementalMarkingStartMarking', args: {}, |
| start: 310, end: 320, cpuStart: 310, cpuEnd: 320 |
| }, |
| { |
| title: 'BlinkGC.AtomicPhase', args: {'forced': false}, |
| start: 320, end: 330, cpuStart: 320, cpuEnd: 330 |
| }, |
| ]; |
| } |
| |
| test('ignoreForcedV8GCEventsForUnifiedMetric', function() { |
| // Any events nested in a forced GC should be ignored. |
| const histograms = new tr.v.HistogramSet(); |
| const actual = run(getSlicesWithForcedV8GCs()); |
| const value = actual.getHistogramNamed('unified-gc-total'); |
| assert.strictEqual(value.running.sum, 20); |
| assert.strictEqual(value.numValues, 2); |
| assert.strictEqual(value.average, 10); |
| assert.strictEqual(value.running.max, 10); |
| }); |
| |
| test('ignoreForcedV8GCEventsForBlinkMetric', function() { |
| // Any events nested in a forced GC should be ignored. |
| const histograms = new tr.v.HistogramSet(); |
| const actual = run(getSlicesWithForcedV8GCs()); |
| const value = actual.getHistogramNamed('blink-gc-total'); |
| assert.strictEqual(value.running.sum, 20); |
| assert.strictEqual(value.numValues, 2); |
| assert.strictEqual(value.average, 10); |
| assert.strictEqual(value.running.max, 10); |
| }); |
| |
| function getSlicesWithForcedBlinkGCs() { |
| return [ |
| // Following nested events should be ignored. |
| { |
| title: 'BlinkGC.CompleteSweep', args: {'forced': true}, |
| start: 200, end: 270, cpuStart: 200, cpuEnd: 270 |
| }, |
| { |
| title: 'BlinkGC.AtomicPhase', args: {'forced': true}, |
| start: 280, end: 290, cpuStart: 280, cpuEnd: 290 |
| }, |
| // Next events are not forced and should be accounted for. |
| { |
| title: 'BlinkGC.AtomicPhase', args: {}, |
| start: 310, end: 320, cpuStart: 310, cpuEnd: 320 |
| }, |
| { |
| title: 'BlinkGC.AtomicPhase', args: {'forced': false}, |
| start: 320, end: 330, cpuStart: 320, cpuEnd: 330 |
| }, |
| ]; |
| } |
| |
| test('ignoreForcedBlinkGCEventsForUnifiedMetric', function() { |
| // Any forced Blink GC events should be ignored. |
| const histograms = new tr.v.HistogramSet(); |
| const actual = run(getSlicesWithForcedBlinkGCs()); |
| const value = actual.getHistogramNamed('unified-gc-total'); |
| assert.strictEqual(value.running.sum, 20); |
| assert.strictEqual(value.numValues, 2); |
| assert.strictEqual(value.average, 10); |
| assert.strictEqual(value.running.max, 10); |
| }); |
| |
| test('ignoreForcedBlinkGCEventsForBlinkMetric', function() { |
| // Any forced Blink GC events should be ignored. |
| const histograms = new tr.v.HistogramSet(); |
| const actual = run(getSlicesWithForcedBlinkGCs()); |
| const value = actual.getHistogramNamed('blink-gc-total'); |
| assert.strictEqual(value.running.sum, 20); |
| assert.strictEqual(value.numValues, 2); |
| assert.strictEqual(value.average, 10); |
| assert.strictEqual(value.running.max, 10); |
| }); |
| }); |
| </script> |