From 286c56e7b60fc61ed356080c108037b2b20ce8e6 Mon Sep 17 00:00:00 2001 From: Tim Rheinfels <tim.rheinfels@fau.de> Date: Wed, 24 May 2023 08:46:47 +0200 Subject: [PATCH] scripts: add benchmark class --- scripts/benchmark.py | 124 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 scripts/benchmark.py diff --git a/scripts/benchmark.py b/scripts/benchmark.py new file mode 100644 index 0000000..a187ed7 --- /dev/null +++ b/scripts/benchmark.py @@ -0,0 +1,124 @@ +## This file is part of the execution-time evaluation for the qronos observer abstractions. +## Copyright (C) 2022-2023 Tim Rheinfels <tim.rheinfels@fau.de> +## See https://gitlab.cs.fau.de/qronos-state-abstractions/execution-time +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see <https://www.gnu.org/licenses/>. + +### +### @file benchmark.py +### +### @brief Provides the @ref benchmark.Benchmark class used for all execution time benchmarks +### +### @author Tim Rheinfels <tim.rheinfels@fau.de> +### + +import re +import numpy as np + +### +### @brief Encapsulates an execution time benchmark, i.e., a collection of related campaigns parametrized by a key +### +class Benchmark(object): + + ### + ### @brief Validates the additional data supplied by a @p campaign + ### + ### @param campaign Dictionary associated with the campaign to validate + ### @param key Key describing the campaign + ### + ### @note This function must be overloaded by all child classes + ### + def _validate(self, campaign, key): + raise NotImplementedError('Benchmark may not be used directly!') + + ### + ### @brief Constructor + ### + ### @param data Dictionarized JSON data as per @ref data.load_json_data + ### @param name Name for the benchmark + ### @param regex Regex used to match all relevant campaigns + ### @param key_function Function transforming an re.match object into a string identifying the matched campaign + ### + def __init__(self, data, name, regex, key_function): + assert(isinstance(name, str)) + assert(isinstance(regex, str)) + + self._name = name + self._execution_times = {} + + # Gather and validate campaigns + regex = re.compile(regex) + for campaign in data['execution_time_measurements']: + + # Skip campaign's not matching the given regex + match = regex.match(campaign['name']) + if match is None: + continue + + # Determine key + key = key_function(match) + + # Delegate to child class for validation + self._validate(campaign, key) + + # Gather execution times over all runs into an array + execution_times = [] + for run in campaign['tests']: + execution_times.append(np.array(run['repetitions'], dtype=int)) + + # Don't overwrite data + assert(key not in self._execution_times) + + # Actually store execution times + self._execution_times[key] = np.array(execution_times) + + ### + ### @brief Getter for the benchmark's name + ### + ### @returns Benchmark's name + ### + @property + def name(self): + return self._name + + ### + ### @brief Getter for the benchmark's raw execution times in CPU cycles + ### + ### @returns Dictionary mapping the campaigns' keys to their execution time data. + ### The latter are two-dimensional np.ndarray instances with the first + ### dimension enumerating the runs and the second one the repetitions. + ### + @property + def execution_times(self): + return self._execution_times + + ### + ### @brief Computes some statistics from the linearized (i.e., treate runs and repetitions equally) execution time data in CPU cycles + ### + ### @returns Dictionary mapping the campaigns' keys to the statistics. + ### The latter are again dictionaries containing the keys + ### - mean: empirical mean over all samples, + ### - std: empirical standard deviation over all samples, + ### - min: minimum over all samples, + ### - max: maximum over all samples and + ### - cov: empirical coefficient of variation (standard deviation over mean) over all samples. + ### + def compute_statistics(self): + return {k: { + 'mean': np.mean(v), + 'std': np.std(v), + 'min': np.min(v), + 'max': np.max(v), + 'cov': np.std(v) / np.mean(v), + } for k, v in self.execution_times.items()} -- GitLab