ipynb: add thermal section for thermal-related notebooks

Signed-off-by: Michele Di Giorgio <michele.digiorgio@arm.com>
diff --git a/ipynb/thermal/ThermalSensorCharacterisation.ipynb b/ipynb/thermal/ThermalSensorCharacterisation.ipynb
new file mode 100644
index 0000000..30e2a0f
--- /dev/null
+++ b/ipynb/thermal/ThermalSensorCharacterisation.ipynb
@@ -0,0 +1,377 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Thermal Sensor Measurements"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The goal of this experiment is to measure temperature on Juno R2 board using the available sensors. In order to do that we will run a busy-loop workload of about 5 minutes and collect traces for the `thermal_temperature` event.\n",
+    "\n",
+    "Measurements must be done **with** and **without** fan."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "import logging\n",
+    "reload(logging)\n",
+    "log_fmt = '%(asctime)-9s %(levelname)-8s: %(message)s'\n",
+    "logging.basicConfig(format=log_fmt)\n",
+    "\n",
+    "# Change to info once the notebook runs ok\n",
+    "logging.getLogger().setLevel(logging.DEBUG)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "%pylab inline\n",
+    "\n",
+    "import os\n",
+    "\n",
+    "# Support to access the remote target\n",
+    "import devlib\n",
+    "from env import TestEnv\n",
+    "\n",
+    "# Support to configure and run RTApp based workloads\n",
+    "from wlgen import RTA, Periodic\n",
+    "\n",
+    "# Support for trace events analysis\n",
+    "from trace import Trace\n",
+    "from trace_analysis import TraceAnalysis\n",
+    "\n",
+    "# Suport for FTrace events parsing and visualization\n",
+    "import trappy"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Target Configuration"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Our target is a Juno R2 development board running Linux."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# Setup a target configuration\n",
+    "my_target_conf = {\n",
+    "    \n",
+    "    # Target platform and board\n",
+    "    \"platform\"    : 'linux',\n",
+    "    \"board\"       : 'juno',\n",
+    "    \n",
+    "    # Target board IP/MAC address\n",
+    "    \"host\"        : '10.1.205.135',\n",
+    "    \n",
+    "    # Login credentials\n",
+    "    \"username\"    : 'root',\n",
+    "    \"password\"    : '',\n",
+    "    \n",
+    "    # RTApp calibration values (comment to let LISA do a calibration run)\n",
+    "    \"rtapp-calib\" :  {\n",
+    "        \"0\": 318, \"1\": 125, \"2\": 124, \"3\": 318, \"4\": 318, \"5\": 319\n",
+    "    },\n",
+    "    \n",
+    "    # Tools required by the experiments\n",
+    "    \"tools\"   : [ 'rt-app', 'trace-cmd' ],    \n",
+    "    \"exclude_modules\" : ['hwmon'],\n",
+    "    \n",
+    "    # FTrace events to collect for all the tests configuration which have\n",
+    "    # the \"ftrace\" flag enabled\n",
+    "    \"ftrace\"  : {\n",
+    "         \"events\" : [\n",
+    "            \"thermal_temperature\",\n",
+    "            # Use sched_switch event to recognize tasks on kernelshark\n",
+    "            \"sched_switch\",\n",
+    "            # cdev_update has been used to show that \"step_wise\" thermal governor introduces noise\n",
+    "            # because it keeps changing the state of the cooling devices and therefore\n",
+    "            # the available OPPs\n",
+    "            #\"cdev_update\",\n",
+    "         ],\n",
+    "         \"buffsize\" : 80 * 1024,\n",
+    "    },\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Tests execution"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "# Initialize a test environment using:\n",
+    "# the provided target configuration (my_target_conf)\n",
+    "te = TestEnv(target_conf=my_target_conf)\n",
+    "target = te.target"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Workloads configuration"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "# Create a new RTApp workload generator using the calibration values\n",
+    "# reported by the TestEnv module\n",
+    "rtapp_big = RTA(target, 'big', calibration=te.calibration())\n",
+    "\n",
+    "big_tasks = dict()\n",
+    "for cpu in target.bl.bigs:\n",
+    "    big_tasks['busy_big'+str(cpu)] = Periodic(duty_cycle_pct=100,\n",
+    "                                              duration_s=360,     # 6 minutes\n",
+    "                                              cpus=str(cpu)       # pinned to a given cpu\n",
+    "                                             ).get()\n",
+    "\n",
+    "# Configure this RTApp instance to:\n",
+    "rtapp_big.conf(\n",
+    "    # 1. generate a \"profile based\" set of tasks\n",
+    "    kind='profile',\n",
+    "    \n",
+    "    # 2. define the \"profile\" of each task\n",
+    "    params=big_tasks,\n",
+    "    \n",
+    "    # 3. Set load reference for task calibration\n",
+    "    loadref='big',\n",
+    "    \n",
+    "    # 4. use this folder for task logfiles\n",
+    "    run_dir=target.working_directory\n",
+    ");"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "rtapp_little = RTA(target, 'little', calibration=te.calibration())\n",
+    "\n",
+    "little_tasks = dict()\n",
+    "for cpu in target.bl.littles:\n",
+    "    little_tasks['busy_little'+str(cpu)] = Periodic(duty_cycle_pct=100,\n",
+    "                                                    duration_s=360,\n",
+    "                                                    cpus=str(cpu)).get()\n",
+    "\n",
+    "rtapp_little.conf(\n",
+    "    kind='profile',\n",
+    "    params=little_tasks,\n",
+    "    # Allow the task duration to be calibrated for the littles (default is for big)\n",
+    "    loadref='little',\n",
+    "    run_dir=target.working_directory\n",
+    ");"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Workload execution"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "logging.info('#### Setup FTrace')\n",
+    "te.ftrace.start()\n",
+    "\n",
+    "logging.info('#### Start RTApp execution')\n",
+    "# Run tasks on the bigs in background to allow execution of following instruction\n",
+    "rtapp_big.run(out_dir=te.res_dir, background=True)\n",
+    "# Run tasks on the littles and then wait 2 minutes for device to cool down\n",
+    "rtapp_little.run(out_dir=te.res_dir, end_pause_s=120.0)\n",
+    "\n",
+    "logging.info('#### Stop FTrace')\n",
+    "te.ftrace.stop()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "collapsed": false
+   },
+   "source": [
+    "# Trace Analysis"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "collapsed": false
+   },
+   "source": [
+    "In order to analyze the trace we will plot it using `TRAPpy`."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# Collect the trace\n",
+    "trace_file = os.path.join(te.res_dir, 'trace.dat')\n",
+    "logging.info('#### Save FTrace: %s', trace_file)\n",
+    "te.ftrace.get_trace(trace_file)\n",
+    "# Parse trace\n",
+    "therm_trace = trappy.FTrace(trace_file)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "therm_trace.thermal.data_frame.tail(10)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# Plot the data\n",
+    "therm_plot = trappy.ILinePlot(therm_trace,\n",
+    "                              signals=['thermal:temp'],\n",
+    "                              filters={'thermal_zone': [\"soc\"]},\n",
+    "                              title='Juno R2 SoC Temperature w/o fans')\n",
+    "therm_plot.view()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "collapsed": false
+   },
+   "source": [
+    "The `pmic` sensor if off-chip and therefore it is not useful to get its temperature."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "# Extract a data frame for each zone\n",
+    "df = therm_trace.thermal.data_frame\n",
+    "soc_df = df[df.thermal_zone == \"soc\"]\n",
+    "big_df = df[df.thermal_zone == \"big_cluster\"]\n",
+    "little_df = df[df.thermal_zone == \"little_cluster\"]\n",
+    "gpu0_df = df[df.thermal_zone == \"gpu0\"]\n",
+    "gpu1_df = df[df.thermal_zone == \"gpu1\"]\n",
+    "# Build new trace\n",
+    "juno_trace = trappy.BareTrace(name = \"Juno_R2\")\n",
+    "juno_trace.add_parsed_event(\"SoC\", soc_df)\n",
+    "juno_trace.add_parsed_event(\"big_Cluster\", big_df)\n",
+    "juno_trace.add_parsed_event(\"LITTLE_Cluster\", little_df)\n",
+    "juno_trace.add_parsed_event(\"gpu0\", gpu0_df)\n",
+    "juno_trace.add_parsed_event(\"gpu1\", gpu1_df)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# Plot the data for all sensors\n",
+    "juno_signals = ['SoC:temp', 'big_Cluster:temp', 'LITTLE_Cluster:temp', 'gpu0:temp', 'gpu1:temp']\n",
+    "therm_plot = trappy.ILinePlot([juno_trace],\n",
+    "                              signals=juno_signals,\n",
+    "                              title='Juno R2 Temperature all traces')\n",
+    "therm_plot.view()"
+   ]
+  }
+ ],
+ "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
+}