ipynb/examples/Idle: Add extra idle state analysis
- Use cpuidle devlib module to poke CPUs to make sure cpu_idle events
are present in the trace
- Set performance cpufreq governor to make sure there are idle periods
during workload execution
- Pin workload to CPU 1
- Make workload period shorter and extent duty cycle range to extend
over full idle state target residency range.
- Add an ILinePlot of the cpuidle state showing how the idle state used
gets deeper as the workload duty cycle decreases in length.
- Add a histogram and scatter plot of idle period lengths
diff --git a/ipynb/examples/trace_analysis/TraceAnalysis_IdleStates.ipynb b/ipynb/examples/trace_analysis/TraceAnalysis_IdleStates.ipynb
index eaf5af3..3fd5f05 100644
--- a/ipynb/examples/trace_analysis/TraceAnalysis_IdleStates.ipynb
+++ b/ipynb/examples/trace_analysis/TraceAnalysis_IdleStates.ipynb
@@ -76,7 +76,12 @@
"from trace import Trace\n",
"\n",
"# DataFrame support\n",
- "from pandas import DataFrame"
+ "import pandas as pd\n",
+ "from pandas import DataFrame\n",
+ "\n",
+ "# Trappy (plots) support\n",
+ "from trappy import ILinePlot\n",
+ "from trappy.stats.grammar import Parser"
]
},
{
@@ -147,7 +152,7 @@
"run_control": {
"marked": false
},
- "scrolled": true
+ "scrolled": false
},
"outputs": [
{
@@ -191,6 +196,21 @@
]
},
{
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "# We're going to run quite a heavy workload to try and create short idle periods.\n",
+ "# Let's set the CPU frequency to max to make sure those idle periods exist\n",
+ "# (otherwise at a lower frequency the workload might overload the CPU\n",
+ "# so it never went idle at all)\n",
+ "te.target.cpufreq.set_all_governors('performance')"
+ ]
+ },
+ {
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -200,14 +220,25 @@
]
},
{
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This experiment:\n",
+ "- Runs a periodic RT-App workload, pinned to CPU 1, that ramps down from 80% to 10% over 7.5 seconds\n",
+ "- Uses `perturb_cpus` to ensure 'cpu_idle' events are present in the trace for all CPUs\n",
+ "- Triggers and collects ftrace output"
+ ]
+ },
+ {
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": null,
"metadata": {
"collapsed": false,
"scrolled": true
},
"outputs": [],
"source": [
+ "cpu = 1\n",
"def experiment(te):\n",
"\n",
" # Create RTApp RAMP task\n",
@@ -215,14 +246,18 @@
" rtapp.conf(kind='profile',\n",
" params={\n",
" 'ramp' : Ramp(\n",
- " start_pct = 60,\n",
- " end_pct = 20,\n",
- " delta_pct = 5,\n",
- " time_s = 0.5).get()\n",
+ " start_pct = 80,\n",
+ " end_pct = 10,\n",
+ " delta_pct = 5,\n",
+ " time_s = 0.5,\n",
+ " period_ms = 5,\n",
+ " cpus = [cpu]).get()\n",
" })\n",
"\n",
" # FTrace the execution of this workload\n",
" te.ftrace.start()\n",
+ " # Momentarily wake all CPUs to ensure cpu_idle trace events are present from the beginning\n",
+ " te.target.cpuidle.perturb_cpus()\n",
" rtapp.run(out_dir=te.res_dir)\n",
" te.ftrace.stop()\n",
"\n",
@@ -590,6 +625,125 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "## CPU idle state over time"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Take a look at the target's idle states:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "te.target.cpuidle.get_states()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now use trappy to plot the idle state of a single CPU over time. Higher is deeper: the plot is at -1 when the CPU is active, 0 for WFI, 1 for CPU sleep, etc.\n",
+ "\n",
+ "We should see that as the workload ramps down and the idle periods become longer, the idle states used become deeper."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "p = Parser(trace.ftrace, filters = {'cpu_id': cpu})\n",
+ "idle_df = p.solve('cpu_idle:state')\n",
+ "ILinePlot(idle_df, column=cpu, drawstyle='steps-post').view()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Examine idle period lengths\n",
+ "Let's get a DataFrame showing the length of each idle period on the CPU and the index of the cpuidle state that was entered."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "def get_idle_periods(df):\n",
+ " series = df[cpu]\n",
+ " series = series[series.shift() != series].dropna()\n",
+ " if series.iloc[0] == -1:\n",
+ " series = series.iloc[1:]\n",
+ "\n",
+ " idles = series.iloc[0::2] \n",
+ " wakeups = series.iloc[1::2]\n",
+ " if len(idles) > len(wakeups):\n",
+ " idles = idles.iloc[:-1]\n",
+ " else:\n",
+ " wakeups = wakeups.iloc[:-1]\n",
+ "\n",
+ " lengths = pd.Series((wakeups.index - idles.index), index=idles.index)\n",
+ " return pd.DataFrame({\"length\": lengths, \"state\": idles})"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Make a scatter plot of the length of idle periods against the state that was entered. We should see that for long idle periods, deeper states were entered (i.e. we should see a positive corellation between the X and Y axes)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "lengths = get_idle_periods(idle_df)\n",
+ "lengths.plot(kind='scatter', x='length', y='state')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "One more example: Draw a histogram of the length of idle periods shorter than 100ms in which the CPU entered cpuidle state 2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "df = lengths[(lengths['state'] == 2) & (lengths['length'] < 0.010)]\n",
+ "df.hist(column='length', bins=50)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
"## Per-cluster Idle State Residency"
]
},