From a9858d9e6889f5044a8dc440427da175281178ff Mon Sep 17 00:00:00 2001 From: William Hesse Date: Thu, 8 Feb 2024 19:26:07 +0100 Subject: [PATCH] Create perf stat subprocess and attach it to the current benchmark --- lib/src/benchmark_base.dart | 7 ------ lib/src/perf_benchmark_base.dart | 38 ++++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/lib/src/benchmark_base.dart b/lib/src/benchmark_base.dart index 300d70b..bc874f5 100644 --- a/lib/src/benchmark_base.dart +++ b/lib/src/benchmark_base.dart @@ -38,13 +38,6 @@ class BenchmarkBase { /// Not measured teardown code executed after the benchmark runs. void teardown() {} - /// Not measured code run just before starting the timed runs - void beforeTimedRuns() {} - - /// Not measured code run just after the timed runs finish. - /// Receives the total number of iterations run. - void afterTimedRuns(int totalIterations) {} - /// Measures the score for this benchmark by executing it enough times /// to reach [minimumMillis]. diff --git a/lib/src/perf_benchmark_base.dart b/lib/src/perf_benchmark_base.dart index 897e72f..37a903b 100644 --- a/lib/src/perf_benchmark_base.dart +++ b/lib/src/perf_benchmark_base.dart @@ -2,6 +2,7 @@ // 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. +import 'dart:convert'; import 'dart:io'; import 'benchmark_base.dart'; @@ -20,10 +21,22 @@ class PerfBenchmarkBase extends BenchmarkBase { late Process perfProcess; Future _startPerfStat() async { + // TODO: Create these fifos here instead of getting them through env variables. perfControlFifo = Platform.environment[perfControlFifoVariable]; perfControlAck = Platform.environment[perfControlAckVariable]; - print(perfControlFifo); if (perfControlFifo != null) { + perfProcess = await Process.start('perf', [ + 'stat', + '--delay', + '-1', + '--control', + 'fifo:$perfControlFifo,$perfControlAck', + '-j', + '-p', + '$pid' + ]); + await Future.delayed(const Duration(seconds: 2)); + openedFifo = File(perfControlFifo!).openSync(mode: FileMode.writeOnly); if (perfControlAck != null) { openedAck = File(perfControlAck!).openSync(); @@ -43,7 +56,15 @@ class PerfBenchmarkBase extends BenchmarkBase { _waitForAck(); openedAck.closeSync(); } - emitter.emit('$name.totalIterations', totalIterations.toDouble()); + perfProcess.kill(ProcessSignal.sigint); + final lines = + utf8.decoder.bind(perfProcess.stderr).transform(const LineSplitter()); + final events = [ + await for (final line in lines) + if (line.startsWith('{"counter-value" : ')) + jsonDecode(line) as Map + ]; + _reportPerfStats(events, totalIterations); } } @@ -73,4 +94,17 @@ class PerfBenchmarkBase extends BenchmarkBase { print('Ack was $ack'); } } + + void _reportPerfStats(List> events, int iterations) { + for (final {'event': String event, 'counter-value': String counterString} + in events) { + final metric = + {'cycles:u': 'CpuCycles', 'page-faults:u': 'MajorPageFaults'}[event]; + if (metric != null) { + emitter.emit( + '$name($metric)', double.parse(counterString) / iterations); + } + } + emitter.emit('$name.totalIterations', iterations.toDouble()); + } }