From fedc67539592f130df3a605041c14b83de906121 Mon Sep 17 00:00:00 2001 From: Gratian Crisan Date: Wed, 13 Dec 2023 15:25:01 -0600 Subject: [PATCH] kernel-*-performance-tests: re-factor common files Refactor cyclictest files common between containerized and non-containerized tests to single location. Signed-off-by: Gratian Crisan --- .../common.cfg | 0 .../fio.cfg | 0 .../run-cyclictest | 0 .../upload_cyclictest_results.py | 0 .../common.cfg | 9 - .../kernel-performance-tests-files/fio.cfg | 15 -- .../run-cyclictest | 83 ------- .../upload_cyclictest_results.py | 217 ------------------ 8 files changed, 324 deletions(-) rename recipes-kernel/kernel-tests/{kernel-performance-tests-files => files}/common.cfg (100%) rename recipes-kernel/kernel-tests/{kernel-containerized-performance-tests-files => files}/fio.cfg (100%) rename recipes-kernel/kernel-tests/{kernel-containerized-performance-tests-files => files}/run-cyclictest (100%) rename recipes-kernel/kernel-tests/{kernel-containerized-performance-tests-files => files}/upload_cyclictest_results.py (100%) delete mode 100644 recipes-kernel/kernel-tests/kernel-containerized-performance-tests-files/common.cfg delete mode 100644 recipes-kernel/kernel-tests/kernel-performance-tests-files/fio.cfg delete mode 100644 recipes-kernel/kernel-tests/kernel-performance-tests-files/run-cyclictest delete mode 100755 recipes-kernel/kernel-tests/kernel-performance-tests-files/upload_cyclictest_results.py diff --git a/recipes-kernel/kernel-tests/kernel-performance-tests-files/common.cfg b/recipes-kernel/kernel-tests/files/common.cfg similarity index 100% rename from recipes-kernel/kernel-tests/kernel-performance-tests-files/common.cfg rename to recipes-kernel/kernel-tests/files/common.cfg diff --git a/recipes-kernel/kernel-tests/kernel-containerized-performance-tests-files/fio.cfg b/recipes-kernel/kernel-tests/files/fio.cfg similarity index 100% rename from recipes-kernel/kernel-tests/kernel-containerized-performance-tests-files/fio.cfg rename to recipes-kernel/kernel-tests/files/fio.cfg diff --git a/recipes-kernel/kernel-tests/kernel-containerized-performance-tests-files/run-cyclictest b/recipes-kernel/kernel-tests/files/run-cyclictest similarity index 100% rename from recipes-kernel/kernel-tests/kernel-containerized-performance-tests-files/run-cyclictest rename to recipes-kernel/kernel-tests/files/run-cyclictest diff --git a/recipes-kernel/kernel-tests/kernel-containerized-performance-tests-files/upload_cyclictest_results.py b/recipes-kernel/kernel-tests/files/upload_cyclictest_results.py similarity index 100% rename from recipes-kernel/kernel-tests/kernel-containerized-performance-tests-files/upload_cyclictest_results.py rename to recipes-kernel/kernel-tests/files/upload_cyclictest_results.py diff --git a/recipes-kernel/kernel-tests/kernel-containerized-performance-tests-files/common.cfg b/recipes-kernel/kernel-tests/kernel-containerized-performance-tests-files/common.cfg deleted file mode 100644 index 70136bf76..000000000 --- a/recipes-kernel/kernel-tests/kernel-containerized-performance-tests-files/common.cfg +++ /dev/null @@ -1,9 +0,0 @@ -# Common configuration for all kernel performance tests -TEST_DURATION=8h - -# Maximum expected latency in useconds. -# The test will fail if cyclictest latency goes beyond this value. -MAX_LATENCY=300 - -# Location for benchmark logs and test results -LOG_DIR="/var/local/ptest-results/kernel-containerized-performance-tests" diff --git a/recipes-kernel/kernel-tests/kernel-performance-tests-files/fio.cfg b/recipes-kernel/kernel-tests/kernel-performance-tests-files/fio.cfg deleted file mode 100644 index 78ff99b68..000000000 --- a/recipes-kernel/kernel-tests/kernel-performance-tests-files/fio.cfg +++ /dev/null @@ -1,15 +0,0 @@ -[global] -directory=/var/cache/fio -numjobs=1 -size=100M -nrfiles=20 -openfiles=10 -direct=0 -verify=sha256 -do_verify=1 -time_based -clocksource=clock_gettime -bs=5k - -[random_rw] -rw=randrw diff --git a/recipes-kernel/kernel-tests/kernel-performance-tests-files/run-cyclictest b/recipes-kernel/kernel-tests/kernel-performance-tests-files/run-cyclictest deleted file mode 100644 index 4d11def15..000000000 --- a/recipes-kernel/kernel-tests/kernel-performance-tests-files/run-cyclictest +++ /dev/null @@ -1,83 +0,0 @@ -#!/bin/bash -source ./common.cfg - -function add_system_info() -{ - { - DESC=$(fw_printenv DeviceDesc) - DEVICE=${DESC#*=} - echo "# Device: $DEVICE" - - echo -n "# Kernel: " - uname -a - - echo -n "# Kernel parameters: " - cat /proc/cmdline - - # save info on the current security mitigations - echo "# Security vulnerabilities settings: " - if [ -d "/sys/devices/system/cpu/vulnerabilities" ]; then - for f in /sys/devices/system/cpu/vulnerabilities/*; do - VULN=$(basename "$f") - if [ -f "$f" ]; then - echo -n -e "# $VULN:\t" - cat "$f" - fi - done - else - echo "# vulnerability information not published" - fi - - # save info on the current C state settings - echo "# C-states settings: " - for CPU in /sys/devices/system/cpu/cpu[0-9]; do - NCPU=$(basename "$CPU") - echo "# [$NCPU]" - for CSTATE in $CPU/cpuidle/state[0-9]; do - NSTATE=$(basename "$CSTATE") - if [ -f "$CSTATE/name" ] && [ -f "$CSTATE/disable" ]; then - NAME=$(cat "$CSTATE/name" 2>/dev/null) - STATUS=$(cat "$CSTATE/disable" 2>/dev/null) - - echo -n "# $NSTATE: $NAME: " - if [ "$STATUS" = "0" ]; then - echo "enabled" - else - echo "disabled" - fi - else - echo "# information not available" - fi - done - done - } >> "$1" -} - -function run_cyclictest() -{ - LOG="$LOG_DIR/cyclictest-$1-`date +'%Y_%m_%d-%H_%M_%S'`.log" - INFLUXDB_INFO="/home/admin/.influxdb.info" - cyclictest --smp --priority=98 --mlockall --interval=997 --quiet --duration="$TEST_DURATION" --histofall=1000 --histfile="$LOG" > /dev/null - add_system_info "$LOG" - if [[ -f "$INFLUXDB_INFO" ]]; then - source "$INFLUXDB_INFO" - python3 upload_cyclictest_results.py "-i $LOG" "-s $INFLUXDB_SERVER" "-p $INFLUXDB_PORT" - else - echo "INFO: No InfluxDB Connection Info. Results will not be published." - fi - - LATENCY=$(grep -sw "# Max Latencies:" "$LOG" | awk '{max=$4; for(i=4; i<=NF; i++) if ($i>max) max=$i; gsub("^0*", "", max); print max}') - if [ "$LATENCY" -le "$MAX_LATENCY" ]; then - echo "cyclictest with $1 load latency: $LATENCY (usec) is less than max latency: $MAX_LATENCY (usec)" - echo "histogram log file: $LOG" - echo "PASS: test_kernel_cyclictest_$1" - CYCLICTEST_RESULT=0 - else - echo "cyclictest with $1 load latency: $LATENCY (usec) is above the expected max latency: $MAX_LATENCY (usec)" - echo "histogram log file: $LOG" - echo "FAIL: test_kernel_cyclictest_$1" - CYCLICTEST_RESULT=1 - fi -} - -mkdir -p "$LOG_DIR" diff --git a/recipes-kernel/kernel-tests/kernel-performance-tests-files/upload_cyclictest_results.py b/recipes-kernel/kernel-tests/kernel-performance-tests-files/upload_cyclictest_results.py deleted file mode 100755 index f46d83563..000000000 --- a/recipes-kernel/kernel-tests/kernel-performance-tests-files/upload_cyclictest_results.py +++ /dev/null @@ -1,217 +0,0 @@ -#!/usr/bin/env python3 -"""Script for uploading a cyclictest log to influxdb""" - -import argparse -import logging -import mmap -import re -import subprocess -import sys -from pathlib import Path -from datetime import datetime -from influxdb import InfluxDBClient, exceptions -import requests.exceptions - - -def get_current_kernel_version(): - """Get the kernel version currently running on the system""" - try: - process = subprocess.run(['uname', '-r'], - check=True, - stdout=subprocess.PIPE) - kver_full = process.stdout.strip().decode("utf-8") - rgx = re.search(r'([0-9]+\.[0-9]+)\.([0-9]+)', kver_full) - kver = rgx.group(1) - except (FileNotFoundError, AttributeError): - logging.warning("failed to read the current kernel version") - raise - - return kver, kver_full - - -def get_kernel_version(path): - """Get the kernel version used in cyclictest test - - Read 'major.minor' and 'major.minor.patch-rt' kernel version strings from - cyclictest log if found or current running system otherwise. - - """ - try: - with open(path, 'rb', 0) as file, \ - mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ) as mfile: - kernel = re.search(br'# Kernel: Linux ([^ ]+) ([0-9]+)\.([0-9]+)\.' - br'([0-9]+-rc[0-9]+-rt[0-9]+|[0-9]+-rt[0-9]+)', - mfile) - # ignore build machine name, i.e. group(1) - major = kernel.group(2).decode() - minor = kernel.group(3).decode() - patch = kernel.group(4).decode() - version = major + '.' + minor - full_version = version + '.' + patch - except (ValueError, AttributeError): - logging.warning('kernel version information missing from \'%s\' ' - 'retriving from current system.', path) - version, full_version = get_current_kernel_version() - return version, full_version - - -def get_current_device(): - """Get the device description for the current system (e.g. cRIO-90xx)""" - try: - process = subprocess.run(['fw_printenv', 'DeviceDesc'], - check=True, - stdout=subprocess.PIPE) - dev_str = process.stdout.strip().decode("utf-8") - dev = dev_str.split('=')[-1] - except FileNotFoundError: - logging.warning("failed to read the current device type") - raise - - return dev - - -def get_device(path): - """Get the device name used in cyclictest test - - Read the device name stored in the cyclictest log file or if not available - retrieve the current device name. - - """ - try: - with open(path, 'rb', 0) as file, \ - mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ) as mfile: - rgx = re.search(br'# Device: ([a-zA-z]+-[0-9]+)', mfile) - device = rgx.group(1).decode() - except (ValueError, AttributeError): - logging.warning('device information missing from \'%s\' ' - 'retriving from current system.', path) - device = get_current_device() - return device - - -def get_test_params(path): - """Get the test name and datetime - - Extract the test name and date/time from cyclictest log name. - - """ - try: - rgx = re.search(r'[^_]*cyclictest-([^-]+)-([^-]+)-([^\.]+).log', - path.name) - test = rgx.group(1) - date = rgx.group(2).replace('_', '-') - time = rgx.group(3).replace('_', ':') - date_time = datetime.fromisoformat(date + ' ' + time) - except AttributeError: - logging.warning('failed to parse test parameters ' - '(i.e. test name, date, time)') - raise - - return test, date_time - - -def get_test_results(path): - """Extract min, avg, max latency from cyclictest log""" - try: - with open(path, 'rb', 0) as file, \ - mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ) as mfile: - rgx = re.search(br'# Max Latencies: ([^\n]+)', mfile) - max_list = list(map(int, rgx.group(1).decode().split())) - max_latency = max_list[-1] - - rgx = re.search(br'# Min Latencies: ([^\n]+)', mfile) - min_list = list(map(int, rgx.group(1).decode().split())) - min_latency = min(min_list) - - rgx = re.search(br'# Avg Latencies: ([^\n]+)', mfile) - avg_list = list(map(int, rgx.group(1).decode().split())) - avg_latency = sum(avg_list) / len(avg_list) - except (ValueError, AttributeError): - logging.warning("failed to parse test results") - raise - - return min_latency, avg_latency, max_latency - -def get_distro_info(): - """Extract distro version and codename from os-release and return them as a tuple - - Returns 'unknown' for either in case of file read exception or missing fields. - - """ - os_release_stmts = [] - try: - with open('/etc/os-release') as os_release_file: - os_release_stmts = os_release_file.readlines() - except: - return ('unknown', 'unknown') - pairs = dict(map(lambda e: e.split('='), os_release_stmts)) - version = pairs.get('VERSION_ID', 'unknown').strip() - name = pairs.get('DISTRO_CODENAME', 'unknown').strip()[1:-1] - return (version, name) - -def read_data(path): - """Read test data and metadata from a cyclictest log file""" - version, full_version = get_kernel_version(path) - controller = get_device(path) - test, time = get_test_params(path) - min_latency, avg_latency, max_latency = get_test_results(path) - distro_version, distro_name = get_distro_info() - - data = { - "measurement": "latency", - "tags": { - "controller": controller, - "test": test, - "kernel_version": version, - "kernel_full_version": full_version, - "distro_version": distro_version, - "distro_name": distro_name - }, - "fields": { - "min_latency": float(min_latency), - "avg_latency": float(avg_latency), - "max_latency": float(max_latency), - }, - "time": time - } - return data - - -def upload_results(data, server, server_port): - """Upload results to influxdb instance""" - try: - influxdb = InfluxDBClient(host=server, port=server_port) - influxdb.switch_database("rtos_kernel_performance") - if not influxdb.write_points(data): - logging.warning("failed to write data points to influxdb") - influxdb.close() - except (exceptions.InfluxDBClientError, - requests.exceptions.ConnectionError) as err: - logging.warning('influxdb error: %s', err) - - -parser = argparse.ArgumentParser( - description="Parse and upload cyclictest results.") -parser.add_argument("-i", "--input", required=True, - help="cyclictest log input file") -parser.add_argument("-s", "--server", required=True, - help="influxdb server") -parser.add_argument("-p", "--port", type=int, default=8086, - help="influxdb server port") -args = parser.parse_args() - -log_file = Path(args.input.strip()) -if not log_file.is_file(): - logging.error('input file %s does not exist!', log_file) - sys.exit(1) - -try: - result = read_data(log_file) -except (FileNotFoundError, AttributeError, ValueError): - logging.error('skipping malformed or incomplete test results at: %s', - log_file) - sys.exit(1) - -results = [] -results.append(result) -upload_results(results, args.server.strip(), args.port)