{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font size=\"9\">Kernel Functions Profiling</font><br>\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "%load_ext autoreload\n",
    "%autoreload 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import logging\n",
    "from conf import LisaLogging\n",
    "LisaLogging.setup()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Populating the interactive namespace from numpy and matplotlib\n"
     ]
    }
   ],
   "source": [
    "# Generate plots inline\n",
    "%pylab inline\n",
    "\n",
    "import json\n",
    "import os\n",
    "\n",
    "import re\n",
    "import collections\n",
    "import pandas\n",
    "\n",
    "# Support to tests execution\n",
    "from executor import Executor\n",
    "from env import TestEnv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tests configuration"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "01:43:51  INFO    :         Target - Using base path: /home/bjackman/sources/lisa\n",
      "01:43:51  INFO    :         Target - Loading custom (inline) target configuration\n",
      "01:43:51  INFO    :         Target - Loading custom (inline) test configuration\n",
      "01:43:51  INFO    :         Target - Devlib modules to load: ['bl', 'cpufreq']\n",
      "01:43:51  INFO    :         Target - Connecting linux target:\n",
      "01:43:51  INFO    :         Target -   username : brendan\n",
      "01:43:51  INFO    :         Target -       host : 192.168.0.1\n",
      "01:43:51  INFO    :         Target -   password : \n",
      "01:43:51  INFO    :         Target - Connection settings:\n",
      "01:43:51  INFO    :         Target -    {'username': 'brendan', 'host': '192.168.0.1', 'password': ''}\n",
      "01:43:58  INFO    :         Target - Initializing target workdir:\n",
      "01:43:58  INFO    :         Target -    /home/brendan/devlib-target\n",
      "01:44:04  INFO    :         Target - Topology:\n",
      "01:44:04  INFO    :         Target -    [[0, 3, 4, 5], [1, 2]]\n",
      "01:44:07  INFO    :       Platform - Loading default EM:\n",
      "01:44:07  INFO    :       Platform -    /home/bjackman/sources/lisa/libs/utils/platforms/juno.json\n",
      "01:44:11  INFO    :         FTrace - Enabled tracepoints:\n",
      "01:44:11  INFO    :         FTrace -   sched:*\n",
      "01:44:11  INFO    :         FTrace - Kernel functions profiled:\n",
      "01:44:11  INFO    :         FTrace -   select_task_rq_fair\n",
      "01:44:11  INFO    :         FTrace -   enqueue_task_fair\n",
      "01:44:11  INFO    :         FTrace -   dequeue_task_fair\n",
      "01:44:11  WARNING :         Target - Using configuration provided RTApp calibration\n",
      "01:44:11  INFO    :         Target - Using RT-App calibration values:\n",
      "01:44:11  INFO    :         Target -    {\"0\": 358, \"1\": 138, \"2\": 138, \"3\": 357, \"4\": 359, \"5\": 355}\n",
      "01:44:11  WARNING :        TestEnv - Wipe previous contents of the results folder:\n",
      "01:44:11  WARNING :        TestEnv -    /home/bjackman/sources/lisa/results/KernelFunctionsProfilingExample\n",
      "01:44:11  INFO    :          HWMon - HWMON module not enabled\n",
      "01:44:11  WARNING :          HWMon - Energy sampling disabled by configuration\n",
      "01:44:11  INFO    :        TestEnv - Set results folder to:\n",
      "01:44:11  INFO    :        TestEnv -    /home/bjackman/sources/lisa/results/KernelFunctionsProfilingExample\n",
      "01:44:11  INFO    :        TestEnv - Experiment results available also in:\n",
      "01:44:11  INFO    :        TestEnv -    /home/bjackman/sources/lisa/results_latest\n"
     ]
    }
   ],
   "source": [
    "# Setup a target configuration\n",
    "target_conf = {\n",
    "\n",
    "    # Platform and board to target\n",
    "    \"platform\"    : \"linux\",\n",
    "    \"board\"       : \"juno\",\n",
    "\n",
    "    # Login credentials\n",
    "    \"host\"        : \"192.168.0.1\",\n",
    "    \"username\"    : \"brendan\",\n",
    "    \"password\"    : \"\",\n",
    "\n",
    "    # Local installation path\n",
    "    \"tftp\"  : {\n",
    "        \"folder\"    : \"/var/lib/tftpboot\",\n",
    "        \"kernel\"    : \"kern.bin\",\n",
    "        \"dtb\"       : \"dtb.bin\",\n",
    "    },\n",
    "\n",
    "    # RTApp calibration values (comment to let LISA do a calibration run)\n",
    "    \"rtapp-calib\" :  {\n",
    "        \"0\": 358, \"1\": 138, \"2\": 138, \"3\": 357, \"4\": 359, \"5\": 355\n",
    "    },\n",
    "\n",
    "}\n",
    "\n",
    "test_conf = {\n",
    "    # Tools to deploy\n",
    "    \"tools\" : [ \"rt-app\", 'trace-cmd' ],\n",
    "    \n",
    "    # Where results are collected\n",
    "    # NOTE: this folder will be wiped before running the experiments\n",
    "    \"results_dir\" : \"KernelFunctionsProfilingExample\",\n",
    "\n",
    "    # Modules required by these experiments\n",
    "    \"exclude_modules\" : [ \"hwmon\" ],\n",
    "    \n",
    "    # Kernel functions to profile for all the test\n",
    "    # configurations which have the \"ftrace\" flag enabled\n",
    "    \"ftrace\"  : {\n",
    "         \"functions\" : [\n",
    "            \"select_task_rq_fair\",\n",
    "            \"enqueue_task_fair\",\n",
    "            \"dequeue_task_fair\",\n",
    "         ],\n",
    "         \"buffsize\" : 80 * 1024,\n",
    "    },\n",
    "}\n",
    "\n",
    "env = TestEnv(target_conf, test_conf)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "01:50:59  INFO    :         Target - Loading custom (inline) test configuration\n",
      "01:50:59  INFO    : \n",
      "01:50:59  INFO    : ################################################################################\n",
      "01:50:59  INFO    :       Executor - Experiments configuration\n",
      "01:50:59  INFO    : ################################################################################\n",
      "01:50:59  INFO    :       Executor - Configured to run:\n",
      "01:50:59  INFO    :       Executor -     2 target configurations:\n",
      "01:50:59  INFO    :       Executor -       base, eas\n",
      "01:50:59  INFO    :       Executor -     1 workloads (3 iterations each)\n",
      "01:50:59  INFO    :       Executor -       rta\n",
      "01:50:59  INFO    :       Executor - Total: 6 experiments\n",
      "01:50:59  INFO    :       Executor - Results will be collected under:\n",
      "01:50:59  INFO    :       Executor -       /home/bjackman/sources/lisa/results/KernelFunctionsProfilingExample\n"
     ]
    }
   ],
   "source": [
    "# Setup tests executions based on our configuration\n",
    "    \n",
    "tests_conf = {\n",
    "    # Platform configurations to test\n",
    "    \"confs\" : [\n",
    "        {\n",
    "            \"tag\"            : \"base\",\n",
    "            \"flags\"          : \"ftrace\",\n",
    "            \"sched_features\" : \"NO_ENERGY_AWARE\",\n",
    "            \"cpufreq\"        : {\n",
    "                \"governor\" : \"performance\",\n",
    "            },\n",
    "            # provide a set of files and values to write into them\n",
    "            \"files\"          : {\n",
    "                # if filenames start with !/ then we verify that the content\n",
    "                # matches what we wrote and raise an exception if it does not.\n",
    "                # All filenames without an initial decorator are not verified,\n",
    "                # and we do not assert that the write was allowed\n",
    "                # (i,e, the file existed, we have write permission, etc.)\n",
    "                # this means we can use this for sysctls or other files whose\n",
    "                # presence or permissions might depend upon kernel config or\n",
    "                # OS support and we reasonably can proceed for either case.\n",
    "                '/this_file_doesnt_exist_and_we_dont_care'     : '1',\n",
    "                '/proc/sys/kernel/sched_is_big_little'          : '0',\n",
    "                '/proc/sys/kernel/sched_initial_task_util'      : '1023',\n",
    "                '/proc/sys/kernel/sched_use_walt_cpu_util'     : '0',\n",
    "                '/proc/sys/kernel/sched_use_walt_task_util'    : '0',\n",
    "                '/proc/sys/kernel/sched_cstate_aware'           : '1',\n",
    "                '/proc/sys/kernel/sched_walt_cpu_high_irqload' : '10000000',\n",
    "                '/proc/sys/kernel/sched_init_task_load_pct'    : '15',\n",
    "                '!/proc/sys/kernel/sched_latency_ns'             : '10000000',\n",
    "                '!/proc/sys/kernel/sched_migration_cost_ns'      : '500000',\n",
    "            },\n",
    "        },\n",
    "        {\n",
    "            \"tag\"            : \"eas\",\n",
    "            \"flags\"          : \"ftrace\",\n",
    "            \"sched_features\" : \"ENERGY_AWARE\",\n",
    "            \"cpufreq\"        : {\n",
    "                  \"governor\" : \"performance\",\n",
    "            },\n",
    "            \"files\"          : {\n",
    "                '/proc/sys/kernel/sched_is_big_little'          : '1',\n",
    "                '/proc/sys/kernel/sched_initial_task_util'      : '1023',\n",
    "                '/proc/sys/kernel/sched_use_walt_cpu_util'     : '0',\n",
    "                '/proc/sys/kernel/sched_use_walt_task_util'    : '0',\n",
    "                '/proc/sys/kernel/sched_cstate_aware'           : '1',\n",
    "                '/proc/sys/kernel/sched_walt_cpu_high_irqload' : '10000000',\n",
    "                '/proc/sys/kernel/sched_init_task_load_pct'    : '15',\n",
    "                '!/proc/sys/kernel/sched_latency_ns'             : '10000000',\n",
    "                '!/proc/sys/kernel/sched_migration_cost_ns'      : '500000',\n",
    "            },\n",
    "        },\n",
    "    ],\n",
    "    \n",
    "    # Workloads to run (on each platform configuration)\n",
    "    \"wloads\" : {\n",
    "        \"rta\" : {\n",
    "            \"type\" : \"rt-app\",\n",
    "            \"conf\" : {\n",
    "                \"class\"  : \"profile\",\n",
    "                \"params\"  : {\n",
    "                    \"p20\" : {\n",
    "                        \"kind\"   : \"Periodic\",\n",
    "                        \"params\" : {\n",
    "                            \"duty_cycle_pct\" : 20,\n",
    "                         },\n",
    "                        \"tasks\" : \"cpus\",\n",
    "                    },\n",
    "                },\n",
    "            },\n",
    "        },\n",
    "    },\n",
    "    \n",
    "    # Number of iterations for each configuration/workload pair\n",
    "    \"iterations\" : 3,\n",
    "}\n",
    "\n",
    "executor = Executor(env, tests_conf)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tests execution"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "01:51:01  INFO    : \n",
      "01:51:01  INFO    : ################################################################################\n",
      "01:51:01  INFO    :       Executor - Experiments execution\n",
      "01:51:01  INFO    : ################################################################################\n",
      "01:51:01  INFO    : \n",
      "01:51:01  INFO    : ================================================================================\n",
      "01:51:01  INFO    :   TargetConfig - configuring target for [base] experiments\n",
      "01:51:03  INFO    :  SchedFeatures - Set scheduler feature: NO_ENERGY_AWARE\n",
      "01:51:04  INFO    :        CPUFreq - Configuring all CPUs to use [performance] governor\n",
      "01:51:05  INFO    :          WlGen - Setup new workload rta\n",
      "01:51:05  INFO    :          RTApp - Workload duration defined by longest task\n",
      "01:51:05  INFO    :          RTApp - Default policy: SCHED_OTHER\n",
      "01:51:05  INFO    :          RTApp - ------------------------\n",
      "01:51:05  INFO    :          RTApp - task [task_p200], sched: using default policy\n",
      "01:51:05  INFO    :          RTApp -  | calibration CPU: 1\n",
      "01:51:05  INFO    :          RTApp -  | loops count: 1\n",
      "01:51:05  INFO    :          RTApp - + phase_000001: duration 1.000000 [s] (10 loops)\n",
      "01:51:05  INFO    :          RTApp - |  period   100000 [us], duty_cycle  20 %\n",
      "01:51:05  INFO    :          RTApp - |  run_time  20000 [us], sleep_time  80000 [us]\n",
      "01:51:05  INFO    :          RTApp - ------------------------\n",
      "01:51:05  INFO    :          RTApp - task [task_p201], sched: using default policy\n",
      "01:51:05  INFO    :          RTApp -  | calibration CPU: 1\n",
      "01:51:05  INFO    :          RTApp -  | loops count: 1\n",
      "01:51:05  INFO    :          RTApp - + phase_000001: duration 1.000000 [s] (10 loops)\n",
      "01:51:05  INFO    :          RTApp - |  period   100000 [us], duty_cycle  20 %\n",
      "01:51:05  INFO    :          RTApp - |  run_time  20000 [us], sleep_time  80000 [us]\n",
      "01:51:05  INFO    :          RTApp - ------------------------\n",
      "01:51:05  INFO    :          RTApp - task [task_p202], sched: using default policy\n",
      "01:51:05  INFO    :          RTApp -  | calibration CPU: 1\n",
      "01:51:05  INFO    :          RTApp -  | loops count: 1\n",
      "01:51:05  INFO    :          RTApp - + phase_000001: duration 1.000000 [s] (10 loops)\n",
      "01:51:05  INFO    :          RTApp - |  period   100000 [us], duty_cycle  20 %\n",
      "01:51:05  INFO    :          RTApp - |  run_time  20000 [us], sleep_time  80000 [us]\n",
      "01:51:05  INFO    :          RTApp - ------------------------\n",
      "01:51:05  INFO    :          RTApp - task [task_p203], sched: using default policy\n",
      "01:51:05  INFO    :          RTApp -  | calibration CPU: 1\n",
      "01:51:05  INFO    :          RTApp -  | loops count: 1\n",
      "01:51:05  INFO    :          RTApp - + phase_000001: duration 1.000000 [s] (10 loops)\n",
      "01:51:05  INFO    :          RTApp - |  period   100000 [us], duty_cycle  20 %\n",
      "01:51:05  INFO    :          RTApp - |  run_time  20000 [us], sleep_time  80000 [us]\n",
      "01:51:05  INFO    :          RTApp - ------------------------\n",
      "01:51:05  INFO    :          RTApp - task [task_p204], sched: using default policy\n",
      "01:51:05  INFO    :          RTApp -  | calibration CPU: 1\n",
      "01:51:05  INFO    :          RTApp -  | loops count: 1\n",
      "01:51:05  INFO    :          RTApp - + phase_000001: duration 1.000000 [s] (10 loops)\n",
      "01:51:05  INFO    :          RTApp - |  period   100000 [us], duty_cycle  20 %\n",
      "01:51:05  INFO    :          RTApp - |  run_time  20000 [us], sleep_time  80000 [us]\n",
      "01:51:05  INFO    :          RTApp - ------------------------\n",
      "01:51:05  INFO    :          RTApp - task [task_p205], sched: using default policy\n",
      "01:51:05  INFO    :          RTApp -  | calibration CPU: 1\n",
      "01:51:05  INFO    :          RTApp -  | loops count: 1\n",
      "01:51:05  INFO    :          RTApp - + phase_000001: duration 1.000000 [s] (10 loops)\n",
      "01:51:05  INFO    :          RTApp - |  period   100000 [us], duty_cycle  20 %\n",
      "01:51:05  INFO    :          RTApp - |  run_time  20000 [us], sleep_time  80000 [us]\n",
      "01:51:06  INFO    : ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
      "01:51:06  INFO    :       Executor - Experiment 0/6, [base:rta] 1/3\n",
      "01:51:06  WARNING :       Executor - FTrace events collection enabled\n",
      "01:51:17  INFO    :          WlGen - Workload execution START:\n",
      "01:51:17  INFO    :          WlGen -    /home/brendan/devlib-target/bin/rt-app /home/brendan/devlib-target/run_dir/rta_00.json 2>&1\n",
      "01:51:30  INFO    :       Executor - Collected FTrace binary trace:\n",
      "01:51:30  INFO    :       Executor -    <res_dir>/rtapp:base:rta/1/trace.dat\n",
      "01:51:31  INFO    :       Executor - Collected FTrace function profiling:\n",
      "01:51:31  INFO    :       Executor -    <res_dir>/rtapp:base:rta/1/trace_stat.json\n",
      "01:51:31  INFO    : --------------------------------------------------------------------------------\n",
      "01:51:31  INFO    : ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
      "01:51:31  INFO    :       Executor - Experiment 1/6, [base:rta] 2/3\n",
      "01:51:31  WARNING :       Executor - FTrace events collection enabled\n",
      "01:51:43  INFO    :          WlGen - Workload execution START:\n",
      "01:51:43  INFO    :          WlGen -    /home/brendan/devlib-target/bin/rt-app /home/brendan/devlib-target/run_dir/rta_00.json 2>&1\n",
      "01:51:52  INFO    :       Executor - Collected FTrace binary trace:\n",
      "01:51:52  INFO    :       Executor -    <res_dir>/rtapp:base:rta/2/trace.dat\n",
      "01:51:53  INFO    :       Executor - Collected FTrace function profiling:\n",
      "01:51:53  INFO    :       Executor -    <res_dir>/rtapp:base:rta/2/trace_stat.json\n",
      "01:51:53  INFO    : --------------------------------------------------------------------------------\n",
      "01:51:53  INFO    : ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
      "01:51:53  INFO    :       Executor - Experiment 2/6, [base:rta] 3/3\n",
      "01:51:53  WARNING :       Executor - FTrace events collection enabled\n",
      "01:52:05  INFO    :          WlGen - Workload execution START:\n",
      "01:52:05  INFO    :          WlGen -    /home/brendan/devlib-target/bin/rt-app /home/brendan/devlib-target/run_dir/rta_00.json 2>&1\n",
      "01:52:19  INFO    :       Executor - Collected FTrace binary trace:\n",
      "01:52:19  INFO    :       Executor -    <res_dir>/rtapp:base:rta/3/trace.dat\n",
      "01:52:20  INFO    :       Executor - Collected FTrace function profiling:\n",
      "01:52:20  INFO    :       Executor -    <res_dir>/rtapp:base:rta/3/trace_stat.json\n",
      "01:52:20  INFO    : --------------------------------------------------------------------------------\n",
      "01:52:20  INFO    : \n",
      "01:52:20  INFO    : ================================================================================\n",
      "01:52:20  INFO    :   TargetConfig - configuring target for [eas] experiments\n",
      "01:52:22  INFO    :  SchedFeatures - Set scheduler feature: ENERGY_AWARE\n",
      "01:52:23  INFO    :        CPUFreq - Configuring all CPUs to use [performance] governor\n",
      "01:52:24  INFO    :          WlGen - Setup new workload rta\n",
      "01:52:24  INFO    :          RTApp - Workload duration defined by longest task\n",
      "01:52:24  INFO    :          RTApp - Default policy: SCHED_OTHER\n",
      "01:52:24  INFO    :          RTApp - ------------------------\n",
      "01:52:24  INFO    :          RTApp - task [task_p200], sched: using default policy\n",
      "01:52:24  INFO    :          RTApp -  | calibration CPU: 1\n",
      "01:52:24  INFO    :          RTApp -  | loops count: 1\n",
      "01:52:24  INFO    :          RTApp - + phase_000001: duration 1.000000 [s] (10 loops)\n",
      "01:52:24  INFO    :          RTApp - |  period   100000 [us], duty_cycle  20 %\n",
      "01:52:24  INFO    :          RTApp - |  run_time  20000 [us], sleep_time  80000 [us]\n",
      "01:52:24  INFO    :          RTApp - ------------------------\n",
      "01:52:24  INFO    :          RTApp - task [task_p201], sched: using default policy\n",
      "01:52:24  INFO    :          RTApp -  | calibration CPU: 1\n",
      "01:52:24  INFO    :          RTApp -  | loops count: 1\n",
      "01:52:24  INFO    :          RTApp - + phase_000001: duration 1.000000 [s] (10 loops)\n",
      "01:52:24  INFO    :          RTApp - |  period   100000 [us], duty_cycle  20 %\n",
      "01:52:24  INFO    :          RTApp - |  run_time  20000 [us], sleep_time  80000 [us]\n",
      "01:52:24  INFO    :          RTApp - ------------------------\n",
      "01:52:24  INFO    :          RTApp - task [task_p202], sched: using default policy\n",
      "01:52:24  INFO    :          RTApp -  | calibration CPU: 1\n",
      "01:52:24  INFO    :          RTApp -  | loops count: 1\n",
      "01:52:24  INFO    :          RTApp - + phase_000001: duration 1.000000 [s] (10 loops)\n",
      "01:52:24  INFO    :          RTApp - |  period   100000 [us], duty_cycle  20 %\n",
      "01:52:24  INFO    :          RTApp - |  run_time  20000 [us], sleep_time  80000 [us]\n",
      "01:52:24  INFO    :          RTApp - ------------------------\n",
      "01:52:24  INFO    :          RTApp - task [task_p203], sched: using default policy\n",
      "01:52:24  INFO    :          RTApp -  | calibration CPU: 1\n",
      "01:52:24  INFO    :          RTApp -  | loops count: 1\n",
      "01:52:24  INFO    :          RTApp - + phase_000001: duration 1.000000 [s] (10 loops)\n",
      "01:52:24  INFO    :          RTApp - |  period   100000 [us], duty_cycle  20 %\n",
      "01:52:24  INFO    :          RTApp - |  run_time  20000 [us], sleep_time  80000 [us]\n",
      "01:52:24  INFO    :          RTApp - ------------------------\n",
      "01:52:24  INFO    :          RTApp - task [task_p204], sched: using default policy\n",
      "01:52:24  INFO    :          RTApp -  | calibration CPU: 1\n",
      "01:52:24  INFO    :          RTApp -  | loops count: 1\n",
      "01:52:24  INFO    :          RTApp - + phase_000001: duration 1.000000 [s] (10 loops)\n",
      "01:52:24  INFO    :          RTApp - |  period   100000 [us], duty_cycle  20 %\n",
      "01:52:24  INFO    :          RTApp - |  run_time  20000 [us], sleep_time  80000 [us]\n",
      "01:52:24  INFO    :          RTApp - ------------------------\n",
      "01:52:24  INFO    :          RTApp - task [task_p205], sched: using default policy\n",
      "01:52:24  INFO    :          RTApp -  | calibration CPU: 1\n",
      "01:52:24  INFO    :          RTApp -  | loops count: 1\n",
      "01:52:24  INFO    :          RTApp - + phase_000001: duration 1.000000 [s] (10 loops)\n",
      "01:52:24  INFO    :          RTApp - |  period   100000 [us], duty_cycle  20 %\n",
      "01:52:24  INFO    :          RTApp - |  run_time  20000 [us], sleep_time  80000 [us]\n",
      "01:52:24  INFO    : ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
      "01:52:24  INFO    :       Executor - Experiment 0/6, [base:rta] 1/3\n",
      "01:52:24  WARNING :       Executor - FTrace events collection enabled\n",
      "01:52:37  INFO    :          WlGen - Workload execution START:\n",
      "01:52:37  INFO    :          WlGen -    /home/brendan/devlib-target/bin/rt-app /home/brendan/devlib-target/run_dir/rta_00.json 2>&1\n",
      "01:52:47  INFO    :       Executor - Collected FTrace binary trace:\n",
      "01:52:47  INFO    :       Executor -    <res_dir>/rtapp:base:rta/1/trace.dat\n",
      "01:52:48  INFO    :       Executor - Collected FTrace function profiling:\n",
      "01:52:48  INFO    :       Executor -    <res_dir>/rtapp:base:rta/1/trace_stat.json\n",
      "01:52:48  INFO    : --------------------------------------------------------------------------------\n",
      "01:52:48  INFO    : ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
      "01:52:48  INFO    :       Executor - Experiment 1/6, [base:rta] 2/3\n",
      "01:52:48  WARNING :       Executor - FTrace events collection enabled\n",
      "01:53:00  INFO    :          WlGen - Workload execution START:\n",
      "01:53:00  INFO    :          WlGen -    /home/brendan/devlib-target/bin/rt-app /home/brendan/devlib-target/run_dir/rta_00.json 2>&1\n",
      "01:53:12  INFO    :       Executor - Collected FTrace binary trace:\n",
      "01:53:12  INFO    :       Executor -    <res_dir>/rtapp:base:rta/2/trace.dat\n",
      "01:53:13  INFO    :       Executor - Collected FTrace function profiling:\n",
      "01:53:13  INFO    :       Executor -    <res_dir>/rtapp:base:rta/2/trace_stat.json\n",
      "01:53:13  INFO    : --------------------------------------------------------------------------------\n",
      "01:53:13  INFO    : ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
      "01:53:13  INFO    :       Executor - Experiment 2/6, [base:rta] 3/3\n",
      "01:53:13  WARNING :       Executor - FTrace events collection enabled\n",
      "01:53:25  INFO    :          WlGen - Workload execution START:\n",
      "01:53:25  INFO    :          WlGen -    /home/brendan/devlib-target/bin/rt-app /home/brendan/devlib-target/run_dir/rta_00.json 2>&1\n",
      "01:53:35  INFO    :       Executor - Collected FTrace binary trace:\n",
      "01:53:35  INFO    :       Executor -    <res_dir>/rtapp:base:rta/3/trace.dat\n",
      "01:53:36  INFO    :       Executor - Collected FTrace function profiling:\n",
      "01:53:36  INFO    :       Executor -    <res_dir>/rtapp:base:rta/3/trace_stat.json\n",
      "01:53:36  INFO    : --------------------------------------------------------------------------------\n",
      "01:53:36  INFO    : ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
      "01:53:36  INFO    :       Executor - Experiment 3/6, [eas:rta] 1/3\n",
      "01:53:36  WARNING :       Executor - FTrace events collection enabled\n",
      "01:53:48  INFO    :          WlGen - Workload execution START:\n",
      "01:53:48  INFO    :          WlGen -    /home/brendan/devlib-target/bin/rt-app /home/brendan/devlib-target/run_dir/rta_00.json 2>&1\n",
      "01:53:57  INFO    :       Executor - Collected FTrace binary trace:\n",
      "01:53:57  INFO    :       Executor -    <res_dir>/rtapp:eas:rta/1/trace.dat\n",
      "01:53:58  INFO    :       Executor - Collected FTrace function profiling:\n",
      "01:53:58  INFO    :       Executor -    <res_dir>/rtapp:eas:rta/1/trace_stat.json\n",
      "01:53:58  INFO    : --------------------------------------------------------------------------------\n",
      "01:53:58  INFO    : ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
      "01:53:58  INFO    :       Executor - Experiment 4/6, [eas:rta] 2/3\n",
      "01:53:58  WARNING :       Executor - FTrace events collection enabled\n",
      "01:54:10  INFO    :          WlGen - Workload execution START:\n",
      "01:54:10  INFO    :          WlGen -    /home/brendan/devlib-target/bin/rt-app /home/brendan/devlib-target/run_dir/rta_00.json 2>&1\n",
      "01:54:22  INFO    :       Executor - Collected FTrace binary trace:\n",
      "01:54:22  INFO    :       Executor -    <res_dir>/rtapp:eas:rta/2/trace.dat\n",
      "01:54:23  INFO    :       Executor - Collected FTrace function profiling:\n",
      "01:54:23  INFO    :       Executor -    <res_dir>/rtapp:eas:rta/2/trace_stat.json\n",
      "01:54:23  INFO    : --------------------------------------------------------------------------------\n",
      "01:54:23  INFO    : ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
      "01:54:23  INFO    :       Executor - Experiment 5/6, [eas:rta] 3/3\n",
      "01:54:23  WARNING :       Executor - FTrace events collection enabled\n",
      "01:54:35  INFO    :          WlGen - Workload execution START:\n",
      "01:54:35  INFO    :          WlGen -    /home/brendan/devlib-target/bin/rt-app /home/brendan/devlib-target/run_dir/rta_00.json 2>&1\n",
      "01:54:45  INFO    :       Executor - Collected FTrace binary trace:\n",
      "01:54:45  INFO    :       Executor -    <res_dir>/rtapp:eas:rta/3/trace.dat\n",
      "01:54:46  INFO    :       Executor - Collected FTrace function profiling:\n",
      "01:54:46  INFO    :       Executor -    <res_dir>/rtapp:eas:rta/3/trace_stat.json\n",
      "01:54:46  INFO    : --------------------------------------------------------------------------------\n",
      "01:54:46  INFO    : \n",
      "01:54:46  INFO    : ################################################################################\n",
      "01:54:46  INFO    :       Executor - Experiments execution completed\n",
      "01:54:46  INFO    : ################################################################################\n",
      "01:54:46  INFO    :       Executor - Results available in:\n",
      "01:54:46  INFO    :       Executor -       /home/bjackman/sources/lisa/results/KernelFunctionsProfilingExample\n"
     ]
    }
   ],
   "source": [
    "# Execute all the configured test\n",
    "executor.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "res_dir = \"/home/derkling/Code/lisa/results/KernelFunctionsProfilingExample\"\n",
    "out_dir = \"/home/derkling/Code/lisa/results/KernelFunctionsProfilingExample/rtapp:eas:rta/2/trace.dat\"\n",
    "out_dir.replace(res_dir, \"<res_dir>\")\n",
    "print executor.te.res_dir"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false,
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "01:56:21  INFO    : Content of the output folder /home/bjackman/sources/lisa/results/KernelFunctionsProfilingExample\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[01;34m/home/bjackman/sources/lisa/results/KernelFunctionsProfilingExample\u001b[00m\r\n",
      "├── \u001b[01;34mrtapp:base:rta\u001b[00m\r\n",
      "│   ├── \u001b[01;34m1\u001b[00m\r\n",
      "│   │   ├── output.log\r\n",
      "│   │   ├── rta_00.json\r\n",
      "│   │   ├── rt-app-task_p200-0.log\r\n",
      "│   │   ├── rt-app-task_p201-1.log\r\n",
      "│   │   ├── rt-app-task_p202-2.log\r\n",
      "│   │   ├── rt-app-task_p203-3.log\r\n",
      "│   │   ├── rt-app-task_p204-4.log\r\n",
      "│   │   ├── rt-app-task_p205-5.log\r\n",
      "│   │   ├── trace.dat\r\n",
      "│   │   └── trace_stat.json\r\n",
      "│   ├── \u001b[01;34m2\u001b[00m\r\n",
      "│   │   ├── output.log\r\n",
      "│   │   ├── rta_00.json\r\n",
      "│   │   ├── rt-app-task_p200-0.log\r\n",
      "│   │   ├── rt-app-task_p201-1.log\r\n",
      "│   │   ├── rt-app-task_p202-2.log\r\n",
      "│   │   ├── rt-app-task_p203-3.log\r\n",
      "│   │   ├── rt-app-task_p204-4.log\r\n",
      "│   │   ├── rt-app-task_p205-5.log\r\n",
      "│   │   ├── trace.dat\r\n",
      "│   │   └── trace_stat.json\r\n",
      "│   ├── \u001b[01;34m3\u001b[00m\r\n",
      "│   │   ├── output.log\r\n",
      "│   │   ├── rta_00.json\r\n",
      "│   │   ├── rt-app-task_p200-0.log\r\n",
      "│   │   ├── rt-app-task_p201-1.log\r\n",
      "│   │   ├── rt-app-task_p202-2.log\r\n",
      "│   │   ├── rt-app-task_p203-3.log\r\n",
      "│   │   ├── rt-app-task_p204-4.log\r\n",
      "│   │   ├── rt-app-task_p205-5.log\r\n",
      "│   │   ├── trace.dat\r\n",
      "│   │   └── trace_stat.json\r\n",
      "│   ├── kernel.config\r\n",
      "│   ├── kernel.version\r\n",
      "│   └── platform.json\r\n",
      "└── \u001b[01;34mrtapp:eas:rta\u001b[00m\r\n",
      "    ├── \u001b[01;34m1\u001b[00m\r\n",
      "    │   ├── output.log\r\n",
      "    │   ├── rta_00.json\r\n",
      "    │   ├── rt-app-task_p200-0.log\r\n",
      "    │   ├── rt-app-task_p201-1.log\r\n",
      "    │   ├── rt-app-task_p202-2.log\r\n",
      "    │   ├── rt-app-task_p203-3.log\r\n",
      "    │   ├── rt-app-task_p204-4.log\r\n",
      "    │   ├── rt-app-task_p205-5.log\r\n",
      "    │   ├── trace.dat\r\n",
      "    │   └── trace_stat.json\r\n",
      "    ├── \u001b[01;34m2\u001b[00m\r\n",
      "    │   ├── output.log\r\n",
      "    │   ├── rta_00.json\r\n",
      "    │   ├── rt-app-task_p200-0.log\r\n",
      "    │   ├── rt-app-task_p201-1.log\r\n",
      "    │   ├── rt-app-task_p202-2.log\r\n",
      "    │   ├── rt-app-task_p203-3.log\r\n",
      "    │   ├── rt-app-task_p204-4.log\r\n",
      "    │   ├── rt-app-task_p205-5.log\r\n",
      "    │   ├── trace.dat\r\n",
      "    │   └── trace_stat.json\r\n",
      "    ├── \u001b[01;34m3\u001b[00m\r\n",
      "    │   ├── output.log\r\n",
      "    │   ├── rta_00.json\r\n",
      "    │   ├── rt-app-task_p200-0.log\r\n",
      "    │   ├── rt-app-task_p201-1.log\r\n",
      "    │   ├── rt-app-task_p202-2.log\r\n",
      "    │   ├── rt-app-task_p203-3.log\r\n",
      "    │   ├── rt-app-task_p204-4.log\r\n",
      "    │   ├── rt-app-task_p205-5.log\r\n",
      "    │   ├── trace.dat\r\n",
      "    │   └── trace_stat.json\r\n",
      "    ├── kernel.config\r\n",
      "    ├── kernel.version\r\n",
      "    └── platform.json\r\n",
      "\r\n",
      "8 directories, 66 files\r\n"
     ]
    }
   ],
   "source": [
    "# Check content of the output folder\n",
    "res_dir = executor.te.res_dir\n",
    "logging.info('Content of the output folder %s', res_dir)\n",
    "!tree {res_dir}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Load function profiling data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false,
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "def autodict():\n",
    "    return collections.defaultdict(autodict)\n",
    "\n",
    "def parse_perf_stat(res_dir):\n",
    "    TEST_DIR_RE = re.compile(r'.*/([^:]*):([^:]*):([^:]*)')\n",
    "    profiling_data = autodict()\n",
    "\n",
    "    for test_idx in sorted(os.listdir(res_dir)):\n",
    "        test_dir = os.path.join(res_dir, test_idx)\n",
    "        if not os.path.isdir(test_dir):\n",
    "            continue\n",
    "        match = TEST_DIR_RE.search(test_dir)\n",
    "        if not match:\n",
    "            continue\n",
    "        wtype = match.group(1)\n",
    "        tconf = match.group(2)\n",
    "        wload = match.group(3)\n",
    "\n",
    "        #logging.info('Processing %s:%s:%s', wtype, tconf, wload)\n",
    "        trace_stat_file = os.path.join(test_dir, '1', 'trace_stat.json')\n",
    "        if not os.path.isfile(trace_stat_file):\n",
    "            continue\n",
    "        with open(trace_stat_file, 'r') as fh:\n",
    "            data = json.load(fh)\n",
    "        for cpu_id, cpu_stats in sorted(data.items()):\n",
    "            for fname in cpu_stats:\n",
    "                profiling_data[cpu_id][tconf][fname] = cpu_stats[fname]\n",
    "\n",
    "    return profiling_data\n",
    "  \n",
    "profiling_data = parse_perf_stat(res_dir)\n",
    "#logging.info(\"Profiling data:\\n%s\", json.dumps(profiling_data, indent=4))\n",
    "#profiling_data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Build Pandas DataFrame from profiling data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def get_df(profiling_data):\n",
    "    cpu_ids = []\n",
    "    cpu_frames = []\n",
    "    for cpu_id, cpu_data in sorted(profiling_data.items()):\n",
    "        cpu_ids.append(cpu_id)\n",
    "        conf_ids = []\n",
    "        conf_frames = []\n",
    "        for conf_id, conf_data in cpu_data.iteritems():\n",
    "            conf_ids.append(conf_id)\n",
    "            function_data = pandas.DataFrame.from_dict(conf_data, orient='index')\n",
    "            conf_frames.append(function_data)\n",
    "        df = pandas.concat(conf_frames, keys=conf_ids)\n",
    "        cpu_frames.append(df)\n",
    "    df = pandas.concat(cpu_frames, keys=cpu_ids)\n",
    "    #df.head()\n",
    "    return df\n",
    "\n",
    "stats_df = get_df(profiling_data)\n",
    "#stats_df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Plot profiling data per function and CPU"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def plot_stats(df, fname, axes=None):\n",
    "    func_data = df.xs(fname, level=2)\n",
    "    func_stats = func_data.xs(['avg', 's_2'], axis=1)\n",
    "    #func_stats\n",
    "    func_avg = func_stats.unstack(level=1)['avg']\n",
    "    func_std = func_stats.unstack(level=1)['s_2'].apply(numpy.sqrt)\n",
    "    func_avg.plot(kind='bar', title=fname, yerr=func_std, ax=axes);\n",
    "\n",
    "#plot_stats(stats_df, 'select_task_rq_fair')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false,
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "01:56:33  INFO    : Plotting stats for [dequeue_task_fair] function\n",
      "01:56:33  INFO    : Plotting stats for [enqueue_task_fair] function\n",
      "01:56:33  INFO    : Plotting stats for [select_task_rq_fair] function\n",
      "/usr/lib/pymodules/python2.7/matplotlib/collections.py:548: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison\n",
      "  if self._edgecolors == 'face':\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n5I477siaNWvyyU9+Mknyta99LbfffnseeeSRjIyM5JZbbslhhx027fUKmwAAAD3gzjvvzJNPPplL\nL7008+bNy+LFi/POd74zn/nMZ3LKKafktNNOy5w5c3LcccdlxYoVWbt2bZLkgAMOyOjoaL7zne9k\n+/btOeGEE3LUUUdNe73zpv0KAAAAtG3Dhg3ZtGlTBgYGxvY9//zzOf300/PII4/koosuyt13351n\nnnkmP/vZz3LqqacmSc4888ysXLky73nPe7Jhw4a8/vWvz1VXXZW+vr5prVfPJgAAQA849thjs3jx\n4gwPD489tmzZkttuuy3nn39+li5dmu9973sZGRnJ5Zdfnu3bt4+de8EFF+Suu+7KQw89lPXr1+fK\nK6+c9nqFTQAAgB5w2mmnpa+vLx/96Eezbdu2PP/883nggQdy55135umnn05fX1/mz5+fhx9+ONdd\nd92OWWJz11135dvf/naee+65zJ8/PwceeGDmzp077fUKmwAAALvR1zeQamWP6XlU7e/ZnDlzcttt\nt+Xee+/NkiVL8tKXvjQrVqzI6OhorrrqqqxatSr9/f1ZsWJFli9fPnbeli1bsmLFigwODmbRokU5\n/PDDc/HFF7f9fdkT62wCALvVaDTSaDTGtuv1epKkXq+PbQPMFpOtJcner7MpbAIAU+aPMGC283tu\ncnsbNg2jBQAAoDhhEwAAgOKETQAAAIoTNgEAAChO2AQAAKA4YRMAAIDihE0AAACKEzYBAAB6wKJF\ni7JmzZpOlzFlwiYAAMBu9B/an1qtNm2P/kP7p1THjuN7xbxOFwAAANDNRkdGk6FpbH9odPoa7yA9\nmwAAAD1i3bp1ecUrXpHBwcG8/e1vz7PPPpvh4eGcffbZOeKIIzI4OJhzzjknjz/++Ng5N910U44/\n/vj09/dnyZIlWbVq1dhzN954Y5YuXZrBwcGcddZZ2bhxY7FahU0AAIAe0Gw2s2rVqqxevTrf//73\ns379+nz4wx9Os9nMO97xjmzcuDEbN27MQQcdlJUrVyZJtm7dmgsvvDBf/epXs2XLltxxxx151ate\nlSS59dZb85GPfCRf/OIX8+STT+a1r31tzjvvvGL1CpsAAAA9oFarZeXKlTn66KMzMDCQD33oQ7n5\n5pszODiY173udTnwwANzyCGH5IMf/GDWrl07dt6cOXNy//33Z9u2bTnyyCOzdOnSJMn111+fSy65\n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\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAABCtpXKAAAgAElEQVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMB1uSvJf9/Kc\ng5J8JclTST47heMfSHL6Xl4DAHZpXqcLAIBZrJ7kfyY5pkBbzdZjb/xmkiOSDCbZPoXjf35viwKA\nyczpdAEAwJTV9vL445Ksz9SC5p7MLdAGAADAtFuY5PNJfpTk75Jc0No/lOTPk/yPJFtSDe38F+PO\nOznJ37Se+0zrsWN46VuT3D7hOtuTLGlt/5MkVyXZkOSJJNclObDAubtycJJtSZ5PMtqq96gkpyW5\nI8lwkk1Jrk1ywLjzrk7ywyQjSf42ydLW/k+Ne519Sb6V5JrdXP+yJM8m+Wnr+m9rvZZvJnkyyY+T\n/GmSBePOeTTJma3toSSfS9UzO5Lk7bu5FgDsRM8mAJ0wJ9W9hPekCp2/kuR9SZa1nj8nyc2pgtCX\nk/xRa/9LknwpVRAdSHJLktdn6sNL/+8k/yzJSa1/j07yB9N07tYkZ6UKlH1J+lOF1J8luTDJYUle\nk+q1/4fWOf8myWuT/PNUr/2NSTaPa7PZOm9NqmD8vt1c/z8nuSJVGO9LFVZrSS5P8nNJXp5qeO/Q\nhPbH+41U3+MFSVbt5loAAABd4ZdS9RCOd0mSG1OFpNXj9i9N8kxr+/Qkj08476+S/JfW9lszee9k\nLcnTeaGnMqnC3t8VOHcy9SSP7eGY9yX5Qmv7zCTfTfX9mfgfwp9K8idJ7k/yH/fQ5g5DqXomJ3Nu\nql7iHX6QF/dsNqZ4HQDYiQmCAOiE41L1aA6P2zc3yf+XKoT+cNz+Z1INV53TOmdi2JwYWifz0iTz\nk9w9bl8tUxvl0865E70syR+mGho8P9Vn8V2t576Zqhf3E6m+R19I8vuphsHWkvx6a/u/7cN1k+TI\nJB9P8supejvn5MU9pxP9/T5eBwAMowWgIzam6kUbGPfoT3L2Hs77h1TDV8c7btz21lQBboejxm0/\nmeoeyqXjrnlo67rtnjuZXQ3vvS7JQ6mG4i5I8qG8+PP42iSntq71siQXj2vrj5N8LclfTqh1qte/\nItU9pD/fuvbvZvd/C+zt7LcAMEbYBKAT1qXqofs/U60FOTdVADp1D+fdkeqex/emmlTn9Ul+cdzz\n9yV5Rar7Kg/Mi+9H3J4qrF2TqqcyqYLrsgLnTuaHqe6xHB9KD0n12p9JcmKS38sLoe7UVENoD2g9\n/4+pwmHywky0K1MNtf1Kdj9B0fhzxl97a6rJio7OC0EWAIoTNgHohO2pejFfleq+xx8nuSEvzIw6\nsUdtx9c/TRUw35rkJ0l+K9VQ0x2han2q+ze/kSqQ3T6hrQ8k+V6S/5VqhtWvp+o9bPfcyTycaqKj\nv0s1XPWoVMNi35Qq8N2QagKfHfpb+zanmhn2ySRXjvse7KhnRaohrl9KNUvuZCauzXlZklNa9X8l\n1WzAk/Ve7su6ngBQ1IWpJit4oLUNADNp/JIgAECXaLdn8+eTvDPVEKaTUv0v9fHtFgUAe2HiUFEA\noAu0GzZPTPLtvHBPydpUw5sAYKZ0erjnB1Pdgznx8RczdP0HJ7n+eTN0fQCYFiemuq9lMNWseHek\nmlIdAACA/Vi762w+nOT/SbX49tYk96Sa9GHMSSed1LzvvvvavAwAAABd6r5Uk/69SOn7XK5ItXba\n9eP2NZtNk9ntydDQUIaGhjpdBrOI9xSleU9RmvcUpXlPUZL309TVarVkF9my3Z7NJDkiyY+SHJvk\ndanWBwMAAGA/ViJsfi7VgtXPJfkPqdYNAwAAYD9WImyeXqCN/V69Xu90Ccwy3lOU5j1Fad5TlOY9\nRUneT+2bibXJ3LMJAAAwS03nPZsAAACzwuDgYIaHhztdRlcaGBjI5s2bp3y8nk0AAICWWq0W+WXX\nJvveTNazOWcGagIAAGA/I2wCAABQnLAJAABAccImAAAAxQmbAAAAu9HfP5harTZtj/7+wU6/xGlh\nNloAAICWXc24Ws22Op2ZpjdmwDUbLQAAAB0nbAIAAPSITZs25Q1veEOOOOKILFmyJNdee22SZN26\ndXnNa16TgYGBLFy4MBdccEGee+65sfMuuuiiHHnkkVmwYEFe+cpX5sEHH5z2WoVNAACAHrB9+/ac\nc845Ofnkk7Np06asWbMm11xzTVavXp158+bl4x//eH7yk5/kjjvuyJo1a/LJT34ySfK1r30tt99+\nex555JGMjIzklltuyWGHHTbt9QqbAAAAPeDOO+/Mk08+mUsvvTTz5s3L4sWL8853vjOf+cxncsop\np+S0007LnDlzctxxx2XFihVZu3ZtkuSAAw7I6OhovvOd72T79u054YQTctRRR017vfOm/QoAAAC0\nbcOGDdm0aVMGBgbG9j3//PM5/fTT88gjj+Siiy7K3XffnWeeeSY/+9nPcuqppyZJzjzzzKxcuTLv\nec97smHDhrz+9a/PVVddlb6+vmmtV88mAABADzj22GOzePHiDA8Pjz22bNmS2267Leeff36WLl2a\n733vexkZGcnll1+e7du3j517wQUX5K677spDDz2U9evX58orr5z2eoVNAACAHnDaaaelr68vH/3o\nR7Nt27Y8//zzeeCBB3LnnXfm6aefTl9fX+bPn5+HH34411133Y4lSXLXXXfl29/+dp577rnMnz8/\nBx54YObOnTvt9QqbAAAAu9HXN5BqGcnpeVTt79mcOXNy22235d57782SJUvy0pe+NCtWrMjo6Giu\nuuqqrFq1Kv39/VmxYkWWL18+dt6WLVuyYsWKDA4OZtGiRTn88MNz8cUXt/192ZOdFt6cBs1eWKB0\nbzQajTQajbHter2eJKnX62PbAABA76nVaplt+aWUyb43rR7UnbKlsNkmb0YAAJg9/H0/ub0Nm2aj\nnSX0tgIAAN1Ez2abuvF/PrqxJgAA6AX+lp7c3vZsmiAIAACA4oRNAAAAihM2AQAAKE7YBAAAoDhh\nEwAAgOKETQAAgN3oP7Q/tVpt2h79h/ZPqY5FixZlzZo10/xqy7HOJgAAwG6MjowmQ9PY/tDolI7b\nEU57hZ5NAAAAihM2AQAAesS6devyile8IoODg3n729+eZ599NsPDwzn77LNzxBFHZHBwMOecc04e\nf/zxsXNuuummHH/88env78+SJUuyatWqseduvPHGLF26NIODgznrrLOycePGYrUKmwAAAD2g2Wxm\n1apVWb16db7//e9n/fr1+fCHP5xms5l3vOMd2bhxYzZu3JiDDjooK1euTJJs3bo1F154Yb761a9m\ny5YtueOOO/KqV70qSXLrrbfmIx/5SL74xS/mySefzGtf+9qcd955xeoVNgEAAHpArVbLypUrc/TR\nR2dgYCAf+tCHcvPNN2dwcDCve93rcuCBB+aQQw7JBz/4waxdu3bsvDlz5uT+++/Ptm3bcuSRR2bp\n0qVJkuuvvz6XXHJJTjjhhMyZMyeXXHJJ7r333jz22GNF6hU2AQAAesQxxxwztn3sscdm06ZN2bZt\n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\nHJz7bAIAADB1wiYAAADlhE0AAADKCZsAAACUEzYBAAAoJ2wCAABQTtgEAACgnLAJAABAOWETAABg\nBmzfvj3XXHPNtNsYm7AJAABwCPMnzKfX663aY/6E+bH62Lf+rNg87QYAAAC6bLhnmAxWsf5guHrF\np8iZTQAAgBlxww035OlPf3q2bduWn//5n893v/vd7N69OxdccEGe8IQnZNu2bXn+85+fr33ta0vv\n+b3f+708+clPzvz8fM4444xcddVVS//33ve+N2eeeWa2bduW888/P3fffXdZr8ImAADADFhcXMxV\nV12Vq6++Ol/5yldy22235Zd/+ZezuLiYV7ziFbn77rtz991357GPfWwuvfTSJMn999+fyy+/PB//\n+MezsLCQT33qUznrrLOSJB/+8Ifz5je/OR/84AfzrW99K895znPyohe9qKxfYRMAAGAG9Hq9XHrp\npTnllFOydevW/NIv/VLe9773Zdu2bXnBC16QY445Jscff3ze8IY35Lrrrlt636ZNm3LzzTfngQce\nyEknnZQzzzwzSfKud70rV1xxRZ7ylKdk06ZNueKKK3LTTTflnnvuKelX2AQAAJgRp5566tLyaaed\nlnvvvTcPPPBAfvEXfzHbt2/Pli1bcu6552bPnj1ZXFzMcccdlz/+4z/Ou971rpx88sm54IIL8qUv\nfSlJctddd+Xyyy/P1q1bs3Xr1jzucY9LkkcMwZ2EsAkAADAjll9Teffdd+fkk0/OW9/61tx22225\n4YYbsmfPnlx33XVZXFzM4uJikuS8887L1VdfnW984xt56lOfmosvvjhJG1bf/e53Z/fu3UuP+++/\nP8961rNKehU2AQAAZsDi4mJ+67d+K1/72teya9euvOlNb8pFF12U4XCYxz72sdmyZUt27dqVnTt3\nLr3nr//6r/PhD384999/f44++ugcd9xxOeqoo5Ikr3zlK/Mrv/IrueWWW5Ike/bsyQc+8IGyft36\nBAAA4BDmtsyt6u1J5rbMjbVer9fLS17ykpx33nm59957c+GFF+aNb3xjdu/enRe/+MU58cQTc8op\np+Q1r3lNPvKRjyRJ9u7dm7e97W152ctell6vl7PPPjvvfOc7kyQXXnhhvv3tb+eiiy7KXXfdlS1b\ntuS8887Lz/zMz5R8XWtxR9DFfadvAYDZ1uv10rXP9S72BMwuP1MO7mDfm16vl6yQLQ2jBQAAoJyw\n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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f086d8887d0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def plot_all_functions(df):\n",
    "    functions = df.index.get_level_values(2).unique()\n",
    "    fcount = len(functions)\n",
    "\n",
    "    fig, pltaxes = plt.subplots(fcount, 1, figsize=(16, 8*fcount))\n",
    "\n",
    "    fig_id = 0\n",
    "    for fname in functions:\n",
    "        logging.info(\"Plotting stats for [%s] function\", fname)\n",
    "        if fcount > 1:\n",
    "            axes = pltaxes[fig_id]\n",
    "        else:\n",
    "            axes = pltaxes\n",
    "        plot_stats(df, fname, axes)\n",
    "        fig_id = fig_id + 1\n",
    "        \n",
    "plot_all_functions(stats_df)"
   ]
  }
 ],
 "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
}