From f26af3fcfaaba9fc39e001a037a72c8028ec7e5f Mon Sep 17 00:00:00 2001 From: Brendan Jackman Date: Wed, 9 Nov 2016 18:34:31 +0000 Subject: [PATCH] tests/eas: Add test for frequency invariant load tracking This test runs the same workload on the most capable CPU on the system at a cross section of available frequencies. The trace is then examined to find the average activation length of the workload, which is combined with the known period and frequency to estimate an expected mean value for util_avg for each frequency. The util_avg value is extract from scheduler trace events and its mean is compared with the expected value (ignoring the first 300ms so that the signal can stabilize). The test fails if the observed mean is beyond a certain error margin from the expected one. load_avg is then similarly compared with the expected util_avg mean, under the assumption that load_avg should equal util_avg when system load is light. The test is many helper methods, so that in the case of test failures the logic used by the test can be re-used to examine the _cause_ of the failure. A canned notebook is provided with basic plots showing test results in a more useful format than the command-line test run. --- ipynb/tests/Frequency_Invariance_Test.ipynb | 677 ++++++++++++++++++++ tests/eas/load_tracking.py | 226 +++++++ 2 files changed, 903 insertions(+) create mode 100644 ipynb/tests/Frequency_Invariance_Test.ipynb create mode 100644 tests/eas/load_tracking.py diff --git a/ipynb/tests/Frequency_Invariance_Test.ipynb b/ipynb/tests/Frequency_Invariance_Test.ipynb new file mode 100644 index 000000000..f14232522 --- /dev/null +++ b/ipynb/tests/Frequency_Invariance_Test.ipynb @@ -0,0 +1,677 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Frequency Invariant Load Tracking Test\n", + "\n", + "FreqInvarianceTest is a LisaTest class for automated testing of frequency invariant load tracking. This notebook uses the methods it provides to perform the same analysis as the automated test and plot some results.\n", + "\n", + "The test class runs the same workload at a selection of frequencies, each entry in `t.experiments` represents a run at a different frequency." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setup" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import json\n", + "\n", + "from trace import Trace\n", + "from trappy.plotter import plot_trace\n", + "from trappy.stats.grammar import Parser\n", + "from trappy import ILinePlot" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2017-02-13 18:36:59,553 INFO : root : Using LISA logging configuration:\n", + "2017-02-13 18:36:59,554 INFO : root : /home/brendan/sources/lisa/logging.conf\n" + ] + } + ], + "source": [ + "import logging\n", + "from conf import LisaLogging\n", + "LisaLogging.setup()\n", + "logging.getLogger('Analysis').setLevel(logging.ERROR)\n", + "logging.getLogger('Trace').setLevel(logging.ERROR)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Run test workload\n", + "\n", + "There's currently no way to pass a `TestEnv` or configuration to automated test classes. Instead the target information comes from the `target.config` file (in the root of the LISA source tree), so you'll need to edit that to configure LISA to connect to your target." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + " Goal\n", + " ====\n", + " Basic check for frequency invariant load tracking\n", + "\n", + " Detailed Description\n", + " ====================\n", + " This test runs the same workload on the most capable CPU on the system at a\n", + " cross section of available frequencies. The trace is then examined to find\n", + " the average activation length of the workload, which is combined with the\n", + " known period to estimate an expected mean value for util_avg for each\n", + " frequency. The util_avg value is extracted from scheduler trace events and\n", + " its mean is compared with the expected value (ignoring the first 300ms so\n", + " that the signal can stabilize). The test fails if the observed mean is\n", + " beyond a certain error margin from the expected one. load_avg is then\n", + " similarly compared with the expected util_avg mean, under the assumption\n", + " that load_avg should equal util_avg when system load is light.\n", + "\n", + " Expected Behaviour\n", + " ==================\n", + " Load tracking signals are scaled so that the workload results in roughly the\n", + " same util & load values regardless of frequency.\n", + " \n" + ] + } + ], + "source": [ + "from tests.eas.load_tracking import FreqInvarianceTest\n", + "\n", + "t = FreqInvarianceTest()\n", + "print t.__doc__" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To run automated tests from within a notebook we instantiate the test class and call `runExperiments` on it." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false, + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2017-02-13 18:36:59,608 INFO : LisaTest : Setup tests execution engine...\n", + "2017-02-13 18:36:59,609 INFO : TestEnv : Using base path: /home/brejac01/sources/lisa\n", + "2017-02-13 18:36:59,610 INFO : TestEnv : Loading default (file) target configuration\n", + "2017-02-13 18:36:59,611 INFO : TestEnv : Loading target configuration [/home/brejac01/sources/lisa/target.config]...\n", + "2017-02-13 18:36:59,613 INFO : TestEnv : Loading custom (inline) test configuration\n", + "2017-02-13 18:36:59,614 INFO : TestEnv : Devlib modules to load: ['bl', u'cpuidle', 'cgroups', 'cpufreq']\n", + "2017-02-13 18:36:59,615 INFO : TestEnv : Connecting linux target:\n", + "2017-02-13 18:36:59,616 INFO : TestEnv : username : brendan\n", + "2017-02-13 18:36:59,617 INFO : TestEnv : host : 192.168.2.2\n", + "2017-02-13 18:36:59,618 INFO : TestEnv : password : password\n", + "2017-02-13 18:36:59,618 INFO : TestEnv : Connection settings:\n", + "2017-02-13 18:36:59,619 INFO : TestEnv : {'username': u'brendan', 'host': u'192.168.2.2', 'password': u'password'}\n", + "2017-02-13 18:37:07,367 INFO : TestEnv : Initializing target workdir:\n", + "2017-02-13 18:37:07,369 INFO : TestEnv : /home/brendan/devlib-target\n", + "2017-02-13 18:37:11,034 INFO : CGroups : Available controllers:\n", + "2017-02-13 18:37:12,775 INFO : CGroups : cpuset : /home/brendan/devlib-target/cgroups/devlib_cgh2\n", + "2017-02-13 18:37:14,512 INFO : CGroups : cpu : /home/brendan/devlib-target/cgroups/devlib_cgh3\n", + "2017-02-13 18:37:16,249 INFO : CGroups : cpuacct : /home/brendan/devlib-target/cgroups/devlib_cgh3\n", + "2017-02-13 18:37:17,988 INFO : CGroups : blkio : /home/brendan/devlib-target/cgroups/devlib_cgh4\n", + "2017-02-13 18:37:19,726 INFO : CGroups : memory : /home/brendan/devlib-target/cgroups/devlib_cgh5\n", + "2017-02-13 18:37:21,465 INFO : CGroups : devices : /home/brendan/devlib-target/cgroups/devlib_cgh6\n", + "2017-02-13 18:37:23,205 INFO : CGroups : perf_event : /home/brendan/devlib-target/cgroups/devlib_cgh7\n", + "2017-02-13 18:37:24,944 INFO : CGroups : hugetlb : /home/brendan/devlib-target/cgroups/devlib_cgh8\n", + "2017-02-13 18:37:26,682 INFO : CGroups : pids : /home/brendan/devlib-target/cgroups/devlib_cgh9\n", + "2017-02-13 18:37:29,594 INFO : TestEnv : Topology:\n", + "2017-02-13 18:37:29,596 INFO : TestEnv : [[0, 3, 4, 5], [1, 2]]\n", + "2017-02-13 18:37:32,227 INFO : TestEnv : Loading default EM:\n", + "2017-02-13 18:37:32,229 INFO : TestEnv : /home/brejac01/sources/lisa/libs/utils/platforms/juno.json\n", + "2017-02-13 18:37:33,996 WARNING : LinuxTarget : Event [sched_load_avg_task] not available for tracing\n", + "2017-02-13 18:37:33,999 WARNING : LinuxTarget : Event [sched_load_avg_cpu] not available for tracing\n", + "2017-02-13 18:37:34,001 INFO : TestEnv : Enabled tracepoints:\n", + "2017-02-13 18:37:34,002 INFO : TestEnv : sched_switch\n", + "2017-02-13 18:37:34,003 INFO : TestEnv : sched_load_avg_task\n", + "2017-02-13 18:37:34,004 INFO : TestEnv : sched_load_avg_cpu\n", + "2017-02-13 18:37:34,006 INFO : TestEnv : sched_pelt_se\n", + "2017-02-13 18:37:34,007 WARNING : TestEnv : Using configuration provided RTApp calibration\n", + "2017-02-13 18:37:34,008 INFO : TestEnv : Using RT-App calibration values:\n", + "2017-02-13 18:37:34,010 INFO : TestEnv : {\"0\": 354, \"1\": 138, \"2\": 138, \"3\": 363, \"4\": 355, \"5\": 357}\n", + "2017-02-13 18:37:34,011 INFO : EnergyMeter : HWMON module not enabled\n", + "2017-02-13 18:37:34,012 WARNING : EnergyMeter : Energy sampling disabled by configuration\n", + "2017-02-13 18:37:34,013 INFO : TestEnv : Set results folder to:\n", + "2017-02-13 18:37:34,015 INFO : TestEnv : /home/brejac01/sources/lisa/results/20170213_183734\n", + "2017-02-13 18:37:34,016 INFO : TestEnv : Experiment results available also in:\n", + "2017-02-13 18:37:34,017 INFO : TestEnv : /home/brejac01/sources/lisa/results_latest\n", + "2017-02-13 18:37:34,018 INFO : Executor : Loading custom (inline) test configuration\n", + "2017-02-13 18:37:34,019 INFO : Executor : \n", + "2017-02-13 18:37:34,020 INFO : Executor : ################################################################################\n", + "2017-02-13 18:37:34,022 INFO : Executor : Experiments configuration\n", + "2017-02-13 18:37:34,023 INFO : Executor : ################################################################################\n", + "2017-02-13 18:37:34,024 INFO : Executor : Configured to run:\n", + "2017-02-13 18:37:34,025 INFO : Executor : 1 target configurations:\n", + "2017-02-13 18:37:34,026 INFO : Executor : freq_450000\n", + "2017-02-13 18:37:34,027 INFO : Executor : 1 workloads (1 iterations each)\n", + "2017-02-13 18:37:34,028 INFO : Executor : fie_10pct\n", + "2017-02-13 18:37:34,029 INFO : Executor : Total: 1 experiments\n", + "2017-02-13 18:37:34,030 INFO : Executor : Results will be collected under:\n", + "2017-02-13 18:37:34,031 INFO : Executor : /home/brejac01/sources/lisa/results/20170213_183734\n", + "2017-02-13 18:37:34,032 INFO : Executor : rt-app workloads found, installing tool on target\n", + "2017-02-13 18:37:34,033 INFO : LisaTest : Experiments execution...\n", + "2017-02-13 18:37:34,034 INFO : Executor : \n", + "2017-02-13 18:37:34,035 INFO : Executor : ################################################################################\n", + "2017-02-13 18:37:34,036 INFO : Executor : Experiments execution\n", + "2017-02-13 18:37:34,037 INFO : Executor : ################################################################################\n", + "2017-02-13 18:37:34,038 INFO : Executor : \n", + "2017-02-13 18:37:34,039 INFO : Executor : ================================================================================\n", + "2017-02-13 18:37:34,040 INFO : Executor : configuring target for [freq_450000] experiments\n", + "2017-02-13 18:37:35,760 INFO : Executor : Configuring all CPUs to use [userspace] cpufreq governor\n", + "2017-02-13 18:37:36,666 INFO : Executor : CPUFreq - CPU frequencies: {1: 450000}\n", + "2017-02-13 18:37:38,683 INFO : Workload : Setup new workload fie_10pct\n", + "2017-02-13 18:37:38,685 INFO : Workload : Workload duration defined by longest task\n", + "2017-02-13 18:37:38,686 INFO : Workload : Default policy: SCHED_OTHER\n", + "2017-02-13 18:37:38,687 INFO : Workload : ------------------------\n", + "2017-02-13 18:37:38,688 INFO : Workload : task [fie_test0], sched: using default policy\n", + "2017-02-13 18:37:38,689 INFO : Workload : | calibration CPU: 1\n", + "2017-02-13 18:37:38,691 INFO : Workload : | loops count: 1\n", + "2017-02-13 18:37:38,692 INFO : Workload : + phase_000001: duration 1.000000 [s] (62 loops)\n", + "2017-02-13 18:37:38,693 INFO : Workload : | period 16000 [us], duty_cycle 10 %\n", + "2017-02-13 18:37:38,694 INFO : Workload : | run_time 1600 [us], sleep_time 14400 [us]\n", + "2017-02-13 18:37:39,836 INFO : Executor : ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "2017-02-13 18:37:39,838 INFO : Executor : Experiment 0/1, [freq_450000:fie_10pct] 1/1\n", + "2017-02-13 18:37:40,255 WARNING : Executor : No freezer cgroup controller on target. Not freezing userspace\n", + "2017-02-13 18:37:40,257 WARNING : Executor : FTrace events collection enabled\n", + "2017-02-13 18:37:46,898 INFO : Workload : Workload execution START:\n", + "2017-02-13 18:37:46,899 INFO : Workload : /home/brendan/devlib-target/bin/taskset 0x2 /home/brendan/devlib-target/bin/rt-app /home/brendan/devlib-target/run_dir/fie_10pct_00.json 2>&1\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2017-02-13 18:37:54,459 INFO : Executor : Collected FTrace binary trace:\n", + "2017-02-13 18:37:54,460 INFO : Executor : /rtapp:freq_450000:fie_10pct/1/trace.dat\n", + "2017-02-13 18:37:54,461 INFO : Executor : Collected FTrace function profiling:\n", + "2017-02-13 18:37:54,463 INFO : Executor : /rtapp:freq_450000:fie_10pct/1/trace_stat.json\n", + "2017-02-13 18:37:54,463 INFO : Executor : --------------------------------------------------------------------------------\n", + "2017-02-13 18:37:54,464 INFO : Executor : \n", + "2017-02-13 18:37:54,465 INFO : Executor : ################################################################################\n", + "2017-02-13 18:37:54,467 INFO : Executor : Experiments execution completed\n", + "2017-02-13 18:37:54,467 INFO : Executor : ################################################################################\n", + "2017-02-13 18:37:54,468 INFO : Executor : Results available in:\n", + "2017-02-13 18:37:54,469 INFO : Executor : /home/brejac01/sources/lisa/results/20170213_183734\n" + ] + } + ], + "source": [ + "t.runExperiments()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Show variance in util_avg and load_avg\n", + "We want to see the same util_avg and load_avg values regardless of frequencies - the bar charts below should have bars all with roughly the same height." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false, + "scrolled": true + }, + "outputs": [], + "source": [ + "# Get the frequency an experiment was run at\n", + "def experiment_freq(exp):\n", + " [cpu] = exp.wload.cpus\n", + " freq = exp.conf['cpufreq']['freqs'][cpu]\n", + " return freq\n", + "freqs = [experiment_freq(e) for e in t.experiments]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def plot_signal_against_freq(signal):\n", + " means = [t.get_signal_mean(e, signal) for e in t.experiments]\n", + " limits = (0 , max(means) * 1.15)\n", + " pd.DataFrame(means, index=freqs, columns=['Mean ' + signal]).plot(kind='bar', ylim=limits)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plot of variation of util_avg value with frequency:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['sched_switch', 'sched_pelt_se']" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t.get_trace(t.experiments[0]).available_events" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false, + "scrolled": false + }, + "outputs": [ + { + "data": { + "image/png": "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\nrkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_signal_against_freq('util_avg')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### And the same thing for load_avg:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXIAAAEWCAYAAAB7QRxFAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAFHVJREFUeJzt3XuQVNWBx/FvA44LysCMGF7DQzQmYh5iXDUWFh2NCrso\nJFZ4lUoemgqWiWjFDeyW7FhGo64uJqVYm41JoRVIGZdVMSGiYIOVZMFC44OHo5YgoCCB4SUIjJz9\n4zbNzDAwQ08304f5fqq6+t5zX8dx+jeHc889DZIkSZIkSZIkSZIkSZIkSUcldawvOGzYsLBo0aJj\nfVlJit0iIN3UhuaC/NfAPwMfAV/Mlv0HMBLYC7wLfAfYlt02Ffgu8CnwI2B+E+cMIYSWV106hqqr\nq6murm7rakiHSKVScJjM7tDMsb8Bhjcqmw+cDXwZqCEJb4DBwNjs+3BgRgvOL0lqpeaC9iWgtlHZ\n88D+7PISoCq7PAqYDewDVgPvAOcXpJaSpMNqbYv5u8Afs8t9gHX1tq0D+rby/NIxlU6n27oK0lHr\n1Ipj/42kn3zWEfZpsjO8fh9kOp32w6OS4e+iSkUmkyGTybRo35aMWhkIzOXgzU6AbwM3AJcCn2TL\npmTf78m+/wn4d5Lul/q82SnVU1lZSW1t4x5MtVcVFRVs2bLlkPIj3ezMp0U+HLgNGMbBEAd4hqR1\n/p8kXSqfBZbmcX6pXamtrcXGjQ7IBvZRaS7IZ5MEdg9gLUkLeypQRnLTE+CvwI3ACuCJ7Htdtszf\nTkkqsmP+QBB2rUgNpFIpW+TKOdzvQ2vGkUuSSpxBLikamUyGfv36FeXcAwcOZMGCBUU5d7EZ5FKJ\nKS+vJJVKFe1VXl7Z4roMHDiQE088kc2bNzcoHzJkCB06dOD9998v9H9+mznw84mRQS6VmB07aknG\nCRTnlZy/ZVKpFIMGDWL27Nm5sjfeeIPdu3dHG3rHI4Nc0hFdc801PPbYY7n1mTNnct111zW4Ibdn\nzx5+/OMfM2DAAHr16sWkSZP45JNkdPLWrVsZOXIkn/nMZ6isrOTKK69k/fr1uWPT6TTTpk1j6NCh\nlJeXc8UVVxzyL4DDWblyJel0moqKCr7whS8wd+7c3LY//OEPDBkyhG7dutG/f3/uuOOOBsc+/vjj\nDBgwgB49enD33Xe36HpLly7lq1/9KhUVFfTp04cf/vCH7Nu3D4BJkyZx2223Ndh/1KhRTJ8+HYBX\nXnmFIUOGUF5ezpgxYxg7diy33357i65bioKkgxp/JoAAoYivln8GBw4cGF544YXwuc99LqxcuTLU\n1dWFqqqqsGbNmpBKpcKaNWtCCCFMnjw5jBo1KtTW1oYdO3aEK6+8MkydOjWEEMLmzZvDnDlzwu7d\nu8OOHTvCt771rTB69OjcNYYNGxbOOOOM8Pbbb4fdu3eHdDodpkyZ0mR9XnzxxVBVVRVCCGHv3r3h\n9NNPDz/72c/Cvn37wsKFC0PXrl3DW2+9FUIIIZPJhDfffDOEEMLrr78eevbsGZ566qkQQgjLly8P\nJ598cnjppZfCnj17wq233ho6deoUFixYcMSfx7Jly8KSJUvCp59+GlavXh3OOuus8OCDD4YQQli8\neHHo169fbt8tW7aEzp07hw8//DDs2bMn9O/fP/ziF78IdXV1Yc6cOaGsrCzcfvvth1zjcP9/KLHh\n3Ef8QUntTePPBCUY5D/96U/D1KlTw7x588Lll18e6urqckG+f//+cNJJJ4V33303d9xf/vKXcNpp\npzV5zldffTVUVFTk1tPpdLjrrrty6zNmzAjDhw9v8tj6Qb548eLQq1evBtvHjx8fqqurmzz25ptv\nDrfccksIIYQ77rgjjB8/Prft448/DmVlZc0GeWPTp08P3/jGN0IIIezfvz/0798/LF68OIQQwi9/\n+ctw6aWXhhBCWLRoUejbt2+DY4cOHVqwIG/NXCuS2oFUKsW1117LxRdfzHvvvXdIt8qmTZvYtWsX\nX/nKV3JlIQT2708mSd21axe33HILzz33XG4qgp07dxJCyPWz9+rVK3ds586d2blzZ7P1+uCDDw4Z\nwTJgwIBct82SJUuYMmUKy5cvZ+/evezZs4cxY8bkjq2qqsod16VLF0455ZRmr1lTU8Ott97KsmXL\n2LVrF3V1dZx33nm5n9O4ceOYPXs2F198MbNmzeK6667LXa9v34ZzCPbr169gzw/YRy6pWf3792fQ\noEHMmzePb37zmw229ejRg86dO7NixQpqa2upra1l69atbN++HYAHHniAmpoali5dyrZt21i0aBEh\nhFaHWJ8+fVi7dm2D86xZsyYX0BMmTGD06NGsW7eOrVu38oMf/CC374FjD9i1a1eL+uUnTZrE4MGD\neeedd9i2bRt33XVX7g8WwPjx43nyySdZs2YNS5cu5eqrrwagd+/eDe4LALz//vsFu2FskEtqkUcf\n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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_signal_against_freq('load_avg')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Examine trace from workload execution" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot task residency and `sched_util` and `sched_load` for the workload task, along with the expected mean value for util_avg. Note that assuming the system was under little load, so that the task was RUNNING whenever it was RUNNABLE, `load_avg` and `util_avg` should be the same. \n", + "\n", + "Call `examine_experiment` with different experiment indexes to get plots for runs at different frequencies." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "signals = ['util_avg', 'load_avg']\n", + "def examine_experiment(idx):\n", + " experiment = t.experiments[idx]\n", + " \n", + " [freq] = experiment.conf['cpufreq']['freqs'].values()\n", + " print \"Experiment ran at frequency {}\".format(freq)\n", + " events = t.te.test_conf[\"ftrace\"][\"events\"]\n", + " \n", + " # todo add get_trace method\n", + " tasks = experiment.wload.tasks.keys()\n", + " #trace = Trace(t.te.platform, experiment.out_dir, events, tasks)\n", + " print 'Trace plot:'\n", + " plot_trace(t.get_trace(experiment).ftrace)\n", + " \n", + " # Get observed signal\n", + " signal_df = t.get_sched_task_signals(experiment, signals)\n", + " # Get expected average value for util_avg signal\n", + " expected_util_avg_mean = t.get_expected_util_avg(experiment)\n", + " \n", + " # Plot task util_avg signal with expected mean value\n", + " util_avg_mean = pd.Series([expected_util_avg_mean], name='expected_util_avg', index=[signal_df.index[0]])\n", + " df = pd.concat([signal_df, util_avg_mean], axis=1).ffill()\n", + " ILinePlot(df, column=signals + ['expected_util_avg'], drawstyle='steps-post',\n", + " title='Scheduler task signals').view()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Experiment 0: 450000Hz\n" + ] + } + ], + "source": [ + "for i , f in enumerate(freqs):\n", + " print \"Experiment {}:{:10d}Hz\".format(i, f)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false, + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Experiment ran at frequency 450000\n", + "Trace plot:\n" + ] + }, + { + "data": { + "text/html": [ + "\n", + "
\n", + "\n", + "\n", + "\n", + " \n", + "
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
Scheduler task signals
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "examine_experiment(0)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/tests/eas/load_tracking.py b/tests/eas/load_tracking.py new file mode 100644 index 000000000..c4f71475d --- /dev/null +++ b/tests/eas/load_tracking.py @@ -0,0 +1,226 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (C) 2016, ARM Limited and contributors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from bart.common.Utils import select_window, area_under_curve +from devlib.utils.misc import memoized +from trappy.stats.grammar import Parser +import pandas as pd + +from test import LisaTest, experiment_test + +UTIL_SCALE = 1024 +# Time in seconds to allow for util_avg to converge (i.e. ignored time) +UTIL_AVG_CONVERGENCE_TIME = 0.3 +# Allowed margin between expected and observed util_avg value +ERROR_MARGIN_PCT = 15 + +class FreqInvarianceTest(LisaTest): + """ + Goal + ==== + Basic check for frequency invariant load tracking + + Detailed Description + ==================== + This test runs the same workload on the most capable CPU on the system at a + cross section of available frequencies. The trace is then examined to find + the average activation length of the workload, which is combined with the + known period to estimate an expected mean value for util_avg for each + frequency. The util_avg value is extracted from scheduler trace events and + its mean is compared with the expected value (ignoring the first 300ms so + that the signal can stabilize). The test fails if the observed mean is + beyond a certain error margin from the expected one. load_avg is then + similarly compared with the expected util_avg mean, under the assumption + that load_avg should equal util_avg when system load is light. + + Expected Behaviour + ================== + Load tracking signals are scaled so that the workload results in roughly the + same util & load values regardless of frequency. + """ + + test_conf = { + 'tools' : [ 'rt-app' ], + 'ftrace' : { + 'events' : [ + 'sched_switch', + 'sched_load_avg_task', + 'sched_load_avg_cpu', + 'sched_pelt_se', + ], + }, + # cgroups required by freeze_userspace flag + 'modules': ['cpufreq', 'cgroups'], + } + + @classmethod + def setUpClass(cls, *args, **kwargs): + super(FreqInvarianceTest, cls).runExperiments(*args, **kwargs) + + @memoized + @classmethod + def _get_cpu(cls, target): + # Run on a 'big' CPU, or any CPU if not big.LITTLE + if hasattr(target, 'bl'): + return target.bl.bigs[0] + else: + return 0 + + @classmethod + def _getExperimentsConf(cls, test_env): + cpu = cls._get_cpu(test_env.target) + + # 10% periodic RTApp workload: + wloads = { + 'fie_10pct' : { + 'type' : 'rt-app', + 'conf' : { + 'class' : 'periodic', + 'params' : { + 'duty_cycle_pct': 10, + 'duration_s': 1, + 'period_ms': 16, + }, + 'tasks' : 1, + 'prefix' : 'fie_test', + 'cpus' : [cpu] + }, + }, + } + + # Create a set of confs with different frequencies + # We'll run the 10% workload under each conf (i.e. at each frequency) + confs = [] + + all_freqs = test_env.target.cpufreq.list_frequencies(cpu) + # If we have loads of frequencies just test a cross-section so it + # doesn't take all day + cls.freqs = all_freqs[::len(all_freqs)/8 + 1] + for freq in cls.freqs: + confs.append({ + 'tag' : 'freq_{}'.format(freq), + 'flags' : ['ftrace', 'freeze_userspace'], + 'cpufreq' : { + 'freqs' : {cpu: freq}, + 'governor' : 'userspace', + }, + }) + + return { + 'wloads': wloads, + 'confs': confs, + } + + def get_expected_util_avg(self, experiment): + """ + Examine trace to figure out an expected mean for util_avg + + Assumes an RT-App workload with a single task with a single phase, + running on a CPU with the highest max capacity in the system + + This takes into account the frequency the workload was run at, but + doesn't use the kernel's data for compute capacities at each frequency, + instead it assumes that these values scale linearly. + """ + [task] = experiment.wload.tasks.keys() + sched_assert = self.get_sched_assert(experiment, task) + + [freq] = experiment.conf['cpufreq']['freqs'].values() + freq_scaling_factor = float(freq) / max(self.freqs) + duty_cycle_pct = sched_assert.getDutyCycle(self.get_window(experiment)) + + return UTIL_SCALE * (duty_cycle_pct / 100.) * freq_scaling_factor + + def get_sched_task_signals(self, experiment, signals): + """ + Get a pandas.DataFrame with the sched signals for the workload task + + This examines scheduler load tracking trace events, supporting either + sched_load_avg_task or sched_pelt_se. You will need a target kernel that + includes these events. + + :param experiment: Experiment to get trace for + :param signals: List of load tracking signals to extract. Probably a + subset of ``['util_avg', 'load_avg']`` + :returns: :class:`pandas.DataFrame` with a column for each signal for + the experiment's workload task + """ + [task] = experiment.wload.tasks.keys() + trace = self.get_trace(experiment) + + # There are two different scheduler trace events that expose the load + # tracking signals. Neither of them is in mainline. Eventually they + # should be unified but for now we'll just check for both types of + # event. + # TODO: Add support for this parsing in Trappy and/or tasks_analysis + if 'sched_load_avg_task' in trace.available_events: + event = 'sched_load_avg_task' + elif 'sched_pelt_se' in trace.available_events: + event = 'sched_pelt_se' + else: + raise ValueError('No sched_load_avg_task or sched_pelt_se events. ' + 'Does the kernel support them?') + + df = getattr(trace.ftrace, event).data_frame + signals = df[df['comm'] == task][signals] + return select_window(signals, self.get_window(experiment)) + + def get_signal_mean(self, experiment, signal, + ignore_first_s=UTIL_AVG_CONVERGENCE_TIME): + """ + Get the mean of a scheduler signal for the experiment's task + + Ignore the first `ignore_first_s` seconds of the signal. + """ + (wload_start, wload_end) = self.get_window(experiment) + window = (wload_start + ignore_first_s, wload_end) + + signal = self.get_sched_task_signals(experiment, [signal])[signal] + signal = select_window(signal, window) + return area_under_curve(signal) / (window[1] - window[0]) + + def _test_signal(self, experiment, tasks, signal_name): + [task] = tasks + exp_util = self.get_expected_util_avg(experiment) + signal_mean = self.get_signal_mean(experiment, signal_name) + + error_margin = exp_util * (ERROR_MARGIN_PCT / 100.) + [freq] = experiment.conf['cpufreq']['freqs'].values() + + msg = 'Saw {} around {}, expected {} at freq {}'.format( + signal_name, signal_mean, exp_util, freq) + self.assertAlmostEqual(signal_mean, exp_util, delta=error_margin, + msg=msg) + + @experiment_test + def test_task_util_avg(self, experiment, tasks): + """ + Test that the mean of the util_avg signal matched the expected value + """ + return self._test_signal(experiment, tasks, 'util_avg') + + @experiment_test + def test_task_load_avg(self, experiment, tasks): + """ + Test that the mean of the load_avg signal matched the expected value + + Assuming that the system was under little stress (so the task was + RUNNING whenever it was RUNNABLE) and that the task was run with a + 'nice' value of 0, the load_avg should be similar to the util_avg. So, + this test does the same as test_task_util_avg but for load_avg. + """ + return self._test_signal(experiment, tasks, 'load_avg') -- GitLab