blob: 335f907fdb5d8b1bb7497971af69b5a3e11427b3 [file] [log] [blame]
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<center>\n",
"<h1>Energy Model Building Flow - Example 2</h1>\n",
"<h2>for platforms supporting system-level energy meters</h2>\n",
"</center>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This notebook shows how to build an energy model of a HiKey platform running an Android Linux kernel.\n",
"\n",
"It can be used as a reference implementation of an energy model building flow for platforms<br>\n",
"where it's possible to measure the energy consumption at system level, that is either at battery<br>\n",
"level or as close as possible to the clusters.\n",
"\n",
"In this case, it is not enough to isolate the CPUs of the target cluster, but we also have to make<br>\n",
"sure that all tasks (except the essential ones) are **frozen** to avoid affecting battery power<br>\n",
"measurements. This will be achieved by exploiting the cgroup `freezer` controller."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Note: this requires `scipy`\n",
"\n",
"You can install it with `sudo -H pip install scipy` or similar."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Configuration"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true,
"run_control": {
"marked": false
}
},
"outputs": [],
"source": [
"import logging\n",
"from conf import LisaLogging\n",
"LisaLogging.setup()"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false,
"run_control": {
"marked": false
}
},
"outputs": [],
"source": [
"%matplotlib inline\n",
"\n",
"import devlib\n",
"import json\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"import os\n",
"import pandas as pd\n",
"import re\n",
"import trappy\n",
"\n",
"from collections import namedtuple, OrderedDict\n",
"from csv import DictWriter\n",
"from env import TestEnv\n",
"from matplotlib.ticker import FormatStrFormatter, MaxNLocator\n",
"from scipy.stats import linregress\n",
"from time import sleep\n",
"from trappy.plotter.ColorMap import ColorMap\n",
"\n",
"# Support for trace events analysis\n",
"from trace import Trace\n",
"# Import support for Android devices\n",
"from android import Screen, Workload, System"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": false,
"run_control": {
"marked": false
}
},
"outputs": [],
"source": [
"# Setup a target configuration\n",
"my_conf = {\n",
" \n",
" # Target platform and board\n",
" \"platform\" : 'android',\n",
" \"board\" : 'hikey',\n",
"\n",
" \"results_dir\" : \"EnergyModel_SystemEnergy\",\n",
"\n",
" # Energy Meters Configuration for BayLibre's ACME Cape\n",
" \"emeter\" : {\n",
" \"instrument\" : \"aep\",\n",
" \"conf\" : {\n",
" 'resistor_values' : [0.099],\n",
" 'device_entry' : '/dev/ttyACM0'\n",
" },\n",
" \"channel_map\" : {\n",
" \"Device0\" : \"BAT\"\n",
" }\n",
" },\n",
"\n",
" # Tools required by the experiments\n",
" \"tools\" : ['trace-cmd', 'sysbench'],\n",
" \"modules\" : ['cpufreq', 'cpuidle', 'hotplug', 'cgroups'],\n",
" \n",
" # FTrace events to collect for all the tests configuration which have\n",
" # the \"ftrace\" flag enabled\n",
" \"ftrace\" : {\n",
" \"events\" : [\n",
" \"cpu_frequency\",\n",
" \"cpu_idle\",\n",
" \"sched_switch\"\n",
" ],\n",
" \"buffsize\" : 10 * 1024,\n",
" },\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false,
"run_control": {
"marked": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"adbd is already running as root\r\n"
]
}
],
"source": [
"!adb root"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false,
"run_control": {
"marked": false
},
"scrolled": true
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"2016-09-09 14:03:28,185 INFO : Target - Using base path: /data/lisa\n",
"2016-09-09 14:03:28,186 INFO : Target - Loading custom (inline) target configuration\n",
"2016-09-09 14:03:28,189 INFO : Target - Devlib modules to load: ['cpuidle', 'cpufreq', 'cgroups', 'hotplug']\n",
"2016-09-09 14:03:28,190 INFO : Target - Connecting Android target [DEFAULT]\n",
"2016-09-09 14:03:28,191 INFO : Target - Connection settings:\n",
"2016-09-09 14:03:28,192 INFO : Target - None\n",
"2016-09-09 14:03:28,676 INFO : Target - Initializing target workdir:\n",
"2016-09-09 14:03:28,677 INFO : Target - /data/local/tmp/devlib-target\n",
"2016-09-09 14:03:32,960 INFO : Target - Topology:\n",
"2016-09-09 14:03:32,961 INFO : Target - [[0, 1, 2, 3, 4, 5, 6, 7]]\n",
"2016-09-09 14:03:33,356 INFO : FTrace - Enabled tracepoints:\n",
"2016-09-09 14:03:33,357 INFO : FTrace - cpu_frequency\n",
"2016-09-09 14:03:33,358 INFO : FTrace - cpu_idle\n",
"2016-09-09 14:03:33,359 INFO : FTrace - sched_switch\n",
"2016-09-09 14:03:33,361 WARNING : TestEnv - Wipe previous contents of the results folder:\n",
"2016-09-09 14:03:33,362 WARNING : TestEnv - /data/lisa/results/EnergyModel_SystemEnergy\n",
"2016-09-09 14:03:33,365 INFO : AEP - AEP configuration\n",
"2016-09-09 14:03:33,366 INFO : AEP - {'instrument': 'aep', 'channel_map': {'Device0': 'BAT'}, 'conf': {'resistor_values': [0.099], 'device_entry': '/dev/ttyACM0'}}\n",
"2016-09-09 14:03:33,379 INFO : AEP - Channels selected for energy sampling:\n",
"[CHAN(Device0_current), CHAN(Device0_power), CHAN(Device0_voltage)]\n",
"2016-09-09 14:03:33,382 INFO : TestEnv - Set results folder to:\n",
"2016-09-09 14:03:33,383 INFO : TestEnv - /data/lisa/results/EnergyModel_SystemEnergy\n",
"2016-09-09 14:03:33,384 INFO : TestEnv - Experiment results available also in:\n",
"2016-09-09 14:03:33,385 INFO : TestEnv - /data/lisa/results_latest\n"
]
}
],
"source": [
"# Initialize a test environment using:\n",
"# the provided target configuration (my_conf)\n",
"te = TestEnv(target_conf=my_conf, force_new=True)\n",
"target = te.target"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Critical tasks declaration"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Energy measured of a cluster at system-level is affected by noise due the other clusters running in the system. To limit effect of this noise we exploit the `freezer cpuset` controller to freeze the tasks already running in the system. However, we need to be careful not to freeze those tasks that allow us to communicate with the target.\n",
"\n",
"Hence, we define here-below a list of tasks called *CRITICAL* that must not be frozen."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false,
"run_control": {
"marked": false
}
},
"outputs": [],
"source": [
"# Lists of critical tasks for each platform\n",
"CRITICAL_TASKS = {\n",
" 'linux': [\"init\", \"sh\"],\n",
" 'android': [\"/system/bin/sh\", \"adbd\", \"/init\"]\n",
" }"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Energy Model Parameters (CPUs, OPPs and Idle States)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": true,
"run_control": {
"marked": false
}
},
"outputs": [],
"source": [
"# The EM reports capacity and energy consumption for each frequency domain.\n",
"# The frequency domains to be considered by the following EM building flow\n",
"# are described by the parameters of this named tuple\n",
"ClusterDescription = namedtuple('ClusterDescription',\n",
" ['name', 'emeter_ch', 'core_name',\n",
" 'cpus', 'freqs', 'idle_states'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Being Hikey a SMP platform we can limit the scope of the experiment to one cluster only and then replicate the code by hand."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false,
"run_control": {
"marked": false
}
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": []
}
],
"source": [
"clusters = [\n",
" ClusterDescription(\n",
" # Name of the cluster\n",
" name = \"PD_0\",\n",
" # Name of the energy meter channel as specified in the target configuration\n",
" emeter_ch = \"Device0\",\n",
" # Name of the cores in the cluster\n",
" core_name = \"A53_PD_0\",\n",
" # List of cores in the cluster\n",
" cpus = [0, 1, 2, 3],\n",
" # List of frequencies available in the cluster\n",
" freqs = [208000, 432000, 729000, 960000, 1200000],\n",
" # List of idle states available in the cluster\n",
" idle_states = range(len(target.cpuidle.get_states()))\n",
" ),\n",
"# ClusterDescription(\"PD_1\",\n",
"# \"Device0\",\n",
"# \"A53_PD_1\",\n",
"# [4, 5, 6, 7],\n",
"# [208000, 432000, 729000, 960000, 1200000],\n",
"# range(len(target.cpuidle.get_states()))\n",
"# )\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false,
"run_control": {
"marked": false
}
},
"outputs": [
{
"data": {
"text/plain": [
"[ClusterDescription(name='PD_0', emeter_ch='Device0', core_name='A53_PD_0', cpus=[0, 1, 2, 3], freqs=[208000, 432000, 729000, 960000, 1200000], idle_states=[0, 1, 2])]"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"clusters"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": false,
"run_control": {
"marked": false
}
},
"outputs": [],
"source": [
"# Mapping between cluster names and cluster IDs\n",
"cluster_ids = OrderedDict([\n",
" (0, 'PD_0'),\n",
"# (1, 'PD_1')\n",
" ])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Benchmark example"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": false,
"run_control": {
"marked": false
}
},
"outputs": [],
"source": [
"class Sysbench(object):\n",
" \"\"\"\n",
" Sysbench benchmark class.\n",
" \n",
" :param duration: maximum workload duration in seconds\n",
" :type duration: int\n",
" \"\"\"\n",
" sysbench_path = \"/data/local/tmp/bin/sysbench\"\n",
" \n",
" def __init__(self, target, duration):\n",
" self.target = target\n",
" self.duration = duration\n",
"\n",
" def run(self, cgroup, threads):\n",
" \"\"\"\n",
" Run benchmark using the specified number of 'threads'\n",
" to be executed under the specified 'cgroup'.\n",
" \n",
" :param cgroup: cgroup where to run the benchmark on\n",
" :type cgroup: str\n",
" \n",
" :param threads: number of threads to spawn\n",
" :type threads: int\n",
" \n",
" :returns: float - performance score\n",
" \"\"\"\n",
" bench_out = self.target.cgroups.run_into(\n",
" cgroup,\n",
" \"{} --test=cpu --num-threads={} --max-time={} run\"\n",
" .format(self.sysbench_path, threads, self.duration)\n",
" )\n",
" match = re.search(r'(total number of events:\\s*)([\\d.]*)', bench_out)\n",
" return float(match.group(2))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Utility Functions"
]
},
{
"cell_type": "code",
"execution_count": 135,
"metadata": {
"collapsed": false,
"run_control": {
"marked": false
}
},
"outputs": [],
"source": [
"def linfit(x, y):\n",
" slope, intercept, r, p, stderr = linregress(x, y)\n",
" return slope, intercept"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Energy Model Building"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Active States Profiling"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": false,
"scrolled": true
},
"outputs": [],
"source": [
"def compute_power_perf(clusters, loop_cnt, benchmark, bkp_file='pstates.csv'):\n",
" \"\"\"\n",
" Perform P-States profiling on each input cluster.\n",
" \n",
" This method requires a `benchmark` object with the following\n",
" characteristics:\n",
" \n",
" - duration, attribute that tells the workload duration in seconds\n",
" - run(cgroup, threads), run the benchmark into the specified 'cgroup',\n",
" spawning the specified number of 'threads',\n",
" and return a performance score of their execution.\n",
" \n",
" Data will be saved into a CSV file at each iteration such that, if something\n",
" goes wrong, the user can restart the experiment considering only idle_states\n",
" that had not yet been profiled.\n",
" \n",
" :param clusters: list of clusters to profile\n",
" :type clusters: list(namedtuple(ClusterDescription))\n",
" \n",
" :param loop_cnt: number of iterations for each experiment\n",
" :type loop_cnt: int\n",
" \n",
" :param benchmark: benchmark object\n",
" :type benchmark: int\n",
" \n",
" :param bkp_file: CSV file name\n",
" :type bkp_file: str\n",
" \"\"\"\n",
"\n",
" # Make sure all CPUs are online\n",
" target.hotplug.online_all()\n",
"\n",
" # Set cpufreq governor to userpace to allow manual frequency scaling\n",
" target.cpufreq.set_all_governors('userspace')\n",
" \n",
" with open(bkp_file, 'w') as csvfile:\n",
" writer = DictWriter(csvfile,\n",
" fieldnames=['cluster', 'cpus', 'freq',\n",
" 'perf', 'energy', 'power'])\n",
"\n",
" # Freeze all userspace tasks\n",
" target.cgroups.freeze(exclude=CRITICAL_TASKS['android'])\n",
"\n",
" # A) For each cluster (i.e. frequency domain) to profile...\n",
" power_perf = []\n",
" for cl in clusters:\n",
" target_cg, _ = target.cgroups.isolate(cl.cpus)\n",
"\n",
" # P-States profiling requires to plug in CPUs one at the time\n",
" for cpu in cl.cpus:\n",
" target.hotplug.offline(cpu)\n",
"\n",
" # B) For each additional cluster's plugged in CPU...\n",
" on_cpus = []\n",
" for cnt, cpu in enumerate(cl.cpus):\n",
" \n",
" # Hotplug ON one more CPU\n",
" target.hotplug.online(cpu)\n",
" on_cpus.append(cpu)\n",
" \n",
" # Ensure online CPUs are part of the target cgroup\n",
" # (in case hotplug OFF removes it)\n",
" target_cg.set(cpus=on_cpus)\n",
" cl_cpus = set(target.list_online_cpus()).intersection(set(cl.cpus))\n",
" logging.info('Cluster {:8} (Online CPUs : {})'\\\n",
" .format(cl.name, list(cl_cpus)))\n",
"\n",
" # C) For each OPP supported by the current cluster\n",
" for freq in cl.freqs:\n",
"\n",
" # Set frequency to freq for current CPU\n",
" target.cpufreq.set_frequency(cpu, freq)\n",
"\n",
" # Run the benchmark for the specified number of iterations each time\n",
" # collecting a sample of energy consumption and reported performance\n",
" energy = 0.0\n",
" perf = 0.0\n",
" for i in xrange(loop_cnt):\n",
" te.emeter.reset()\n",
" # Run benchmark into the LISA_EM_TARGET cgroup\n",
" perf += benchmark.run(target_cg.name, cnt + 1)\n",
" nrg = te.emeter.report(te.res_dir).channels\n",
" energy += float(nrg[cl.emeter_ch])\n",
" sleep(1)\n",
"\n",
" # Compute average energy and performance for the current number of\n",
" # active CPUs all running at the current OPP\n",
" perf = perf / loop_cnt\n",
" energy = energy / loop_cnt\n",
" power = energy / benchmark.duration\n",
"\n",
" # Keep track of this new P-State profiling point\n",
" new_row = {'cluster': cl.name,\n",
" 'cpus': cnt + 1,\n",
" 'freq': freq,\n",
" 'perf': perf,\n",
" 'energy' : energy,\n",
" 'power': power}\n",
" power_perf.append(new_row)\n",
"\n",
" # Save data in a CSV file\n",
" writer.writerow(new_row)\n",
" \n",
" # C) profile next P-State\n",
"\n",
" # B) add one more CPU (for the current frequency domain)\n",
"\n",
" # A) Profile next cluster (i.e. frequency domain)\n",
" \n",
" # Thaw all frozen tasks\n",
" target.cgroups.freeze(thaw=True)\n",
"\n",
" target.hotplug.online_all()\n",
"\n",
" power_perf_df = pd.DataFrame(power_perf)\n",
" return power_perf_df.set_index(['cluster', 'freq', 'cpus']).sort_index(level='cluster')"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": false,
"scrolled": true
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"2016-09-09 14:08:59,775 INFO : Cluster PD_0 - Online CPUs : set([0])\n",
"2016-09-09 14:14:05,620 INFO : Cluster PD_0 - Online CPUs : set([0, 1])\n",
"2016-09-09 14:19:10,296 INFO : Cluster PD_0 - Online CPUs : set([0, 1, 2])\n",
"2016-09-09 14:24:14,730 INFO : Cluster PD_0 - Online CPUs : set([0, 1, 2, 3])\n"
]
}
],
"source": [
"sysbench = Sysbench(target, 10)\n",
"loop_cnt = 5\n",
"\n",
"power_perf_df = compute_power_perf(clusters, loop_cnt, sysbench)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def plot_pstates(power_perf_df, cluster):\n",
" \"\"\"\n",
" Plot P-States profiling for the specified cluster.\n",
" \n",
" :param power_perf_df: DataFrame reporting power and performance values\n",
" :type power_perf_df: :mod:`pandas.DataFrame`\n",
" \n",
" :param cluster: cluster description\n",
" :type cluster: namedtuple(ClusterDescription)\n",
" \"\"\"\n",
" cmap = ColorMap(len(cluster.freqs))\n",
" color_map = map(cmap.cmap, range(len(cluster.freqs)))\n",
" color_map = dict(zip(cluster.freqs, color_map))\n",
" \n",
" fig, ax = plt.subplots(1, 1, figsize=(16, 10))\n",
" \n",
" grouped = power_perf_df.loc[cluster.name].groupby(level='freq')\n",
" for freq, df in grouped:\n",
" x = df.index.get_level_values('cpus').tolist()\n",
" y = df.power.tolist()\n",
" slope, intercept = linfit(x, y)\n",
" x.insert(0, 0)\n",
" y.insert(0, intercept)\n",
" # Plot linear fit of the points\n",
" ax.plot(x, [slope*i + intercept for i in x], color=color_map[freq])\n",
" # Plot measured points\n",
" ax.scatter(x, y, color=color_map[freq], label='{} kHz'.format(freq))\n",
"\n",
" ax.set_title('HiKey {} cluster P-States profiling'.format(cluster.name),\n",
" fontsize=16)\n",
" ax.legend()\n",
" ax.set_xlabel('Active cores')\n",
" ax.set_ylabel('Power [$\\mu$W]')\n",
" ax.set_xlim(-0.5, len(cluster.cpus)+1)\n",
" ax.xaxis.set_major_locator(MaxNLocator(integer=True))\n",
" ax.yaxis.set_major_formatter(FormatStrFormatter('%.2f'))\n",
" ax.grid(True)"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"image/png": "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\nAABJRU5ErkJggg==\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x7f64281acad0>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"pd0_cl = clusters[0]\n",
"\n",
"plot_pstates(power_perf_df, pd0_cl)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Statistics"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def power_perf_stats(power_perf_df):\n",
" \"\"\"\n",
" For each cluster compute per-OPP power and performance statistics.\n",
" \n",
" :param power_perf_df: dataframe containing power and performance numbers\n",
" :type power_perf_df: :mod:`pandas.DataFrame`\n",
" \"\"\"\n",
" clusters = power_perf_df.index.get_level_values('cluster')\\\n",
" .unique().tolist()\n",
"\n",
" stats = [] \n",
" for cl in clusters:\n",
" cl_power_df = power_perf_df.loc[cl].reset_index()\n",
"\n",
" grouped = cl_power_df.groupby('freq')\n",
" for freq, df in grouped:\n",
" perf = df['perf'] / df['cpus']\n",
" power = df['power'] / df['cpus']\n",
" energy = df['energy'] / df['cpus']\n",
"\n",
" avg_row = {'cluster': cl,\n",
" 'freq': freq,\n",
" 'stats': 'avg',\n",
" 'perf': perf.mean(),\n",
" 'power': power.mean(),\n",
" 'energy': energy.mean()\n",
" }\n",
" std_row = {'cluster': cl,\n",
" 'freq': freq,\n",
" 'stats': 'std',\n",
" 'perf': perf.std(),\n",
" 'power': power.std(),\n",
" 'energy': energy.std()\n",
" }\n",
" min_row = {'cluster': cl,\n",
" 'freq': freq,\n",
" 'stats': 'min',\n",
" 'perf': perf.min(),\n",
" 'power': power.min(),\n",
" 'energy': energy.min()\n",
" }\n",
" max_row = {'cluster' : cl,\n",
" 'freq' : freq,\n",
" 'stats' : 'max',\n",
" 'perf' : perf.max(),\n",
" 'power' : power.max(),\n",
" 'energy': energy.max()\n",
" }\n",
" c99_row = {'cluster' : cl,\n",
" 'freq' : freq,\n",
" 'stats' : 'c99',\n",
" 'perf' : perf.quantile(q=0.99),\n",
" 'power' : power.quantile(q=0.99),\n",
" 'energy': energy.quantile(q=0.99)\n",
" }\n",
"\n",
" stats.append(avg_row)\n",
" stats.append(std_row)\n",
" stats.append(min_row)\n",
" stats.append(max_row)\n",
" stats.append(c99_row)\n",
" \n",
" stats_df = pd.DataFrame(stats).set_index(['cluster', 'freq', 'stats'])\\\n",
" .sort_index(level='cluster')\n",
" return stats_df.unstack()"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"pp_stats = power_perf_stats(power_perf_df)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Plots"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def plot_power_perf(pp_stats, clusters):\n",
" cmap = ColorMap(len(clusters) + 1)\n",
" color_map = map(cmap.cmap, range(len(clusters) + 1))\n",
" \n",
" fig, ax = plt.subplots(1, 1, figsize=(16, 10))\n",
"\n",
" max_perf = pp_stats.perf['avg'].max()\n",
" max_power = pp_stats.power['avg'].max()\n",
"\n",
" for i, cl in enumerate(clusters):\n",
" cl_df = pp_stats.loc[cl.name]\n",
" norm_perf_df = cl_df.perf['avg'] * 100.0 / max_perf\n",
" norm_power_df = cl_df.power['avg'] * 100.0 / max_power\n",
"\n",
" x = norm_perf_df.values.tolist()\n",
" y = norm_power_df.values.tolist()\n",
" ax.plot(x, y, color=color_map[i], marker='o', label=cl.name)\n",
"\n",
" norm_perf_df = cl_df.perf['max'] * 100.0 / max_perf\n",
" norm_power_df = cl_df.power['max'] * 100.0 / max_power\n",
"\n",
" x = norm_perf_df.values.tolist()\n",
" y = norm_power_df.values.tolist()\n",
" ax.plot(x, y, '--', color=color_map[-1])\n",
"\n",
" norm_perf_df = cl_df.perf['min'] * 100.0 / max_perf\n",
" norm_power_df = cl_df.power['min'] * 100.0 / max_power\n",
"\n",
" x = norm_perf_df.values.tolist()\n",
" y = norm_power_df.values.tolist()\n",
" ax.plot(x, y, '--', color=color_map[-1])\n",
"\n",
" ax.set_title('HyKey Power VS Performance curves', fontsize=16)\n",
" ax.legend()\n",
" ax.set_xlabel('Performance [%]')\n",
" ax.set_ylabel('Power [%]')\n",
" ax.set_xlim(0, 120)\n",
" ax.set_ylim(0, 120)\n",
" ax.xaxis.set_major_locator(MaxNLocator(integer=True))\n",
" ax.yaxis.set_major_locator(MaxNLocator(integer=True))\n",
" ax.grid(True)"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x7f6420fdec10>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plot_power_perf(pp_stats, clusters)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Idle States Profiling"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"collapsed": false,
"run_control": {
"marked": false
},
"scrolled": true
},
"outputs": [],
"source": [
"def compute_idle_power(clusters, loop_cnt, sleep_duration, bkp_file='cstates.csv'):\n",
" \"\"\"\n",
" Perform C-States profiling on each input cluster.\n",
" \n",
" Data will be saved into a CSV file at each iteration such that if something\n",
" goes wrong the user can restart the experiment considering only idle_states\n",
" that had not been processed.\n",
" \n",
" :param clusters: list of clusters to profile\n",
" :type clusters: list(namedtuple(ClusterDescription))\n",
" \n",
" :param loop_cnt: number of loops for each experiment\n",
" :type loop_cnt: int\n",
" \n",
" :param sleep_duration: sleep time in seconds\n",
" :type sleep_duration: int\n",
" \n",
" :param bkp_file: CSV file name\n",
" :type bkp_file: str\n",
" \"\"\"\n",
"\n",
" # Make sure all CPUs are online\n",
" target.hotplug.online_all()\n",
"\n",
" with open(bkp_file, 'w') as csvfile:\n",
" writer = DictWriter(csvfile, fieldnames=['cluster', 'cpus',\n",
" 'idle_state', 'energy', 'power'])\n",
"\n",
" # Disable frequency scaling by setting cpufreq governor to userspace\n",
" target.cpufreq.set_all_governors('userspace')\n",
"\n",
" # Freeze all tasks but the ones to communicate with the target\n",
" target.cgroups.freeze(exclude=CRITICAL_TASKS['android'])\n",
"\n",
" all_cpus = set(range(target.number_of_cpus))\n",
" idle_power = []\n",
" for cl in clusters:\n",
"\n",
" # In current cluster, hotplug OFF all CPUs but the first one\n",
" # At least one CPU must be online\n",
" target.hotplug.online(cl.cpus[0])\n",
" for cpu in cl.cpus[1:]:\n",
" target.hotplug.offline(cpu)\n",
"\n",
" other_cpus = list(all_cpus - set(cl.cpus))\n",
" # CPUs in the other clusters will be kept hotplugged OFF\n",
" # to not affect measurements on the current cluster\n",
" for cpu in other_cpus:\n",
" target.hotplug.offline(cpu)\n",
"\n",
" # B) For each additional cluster's plugged in CPU...\n",
" for cnt, cpu in enumerate(cl.cpus):\n",
" \n",
" # Hotplug ON one more CPU\n",
" target.hotplug.online(cpu)\n",
" \n",
" cl_cpus = set(target.list_online_cpus()).intersection(set(cl.cpus))\n",
" logging.info('Cluster {:8} (Online CPUs : {})'\\\n",
" .format(cl.name, list(cl_cpus)))\n",
"\n",
" for idle in cl.idle_states:\n",
"\n",
" # Disable all idle states but the current one\n",
" for c in cl.cpus:\n",
" target.cpuidle.disable_all(cpu=c)\n",
" target.cpuidle.enable(idle, cpu=c)\n",
"\n",
" sleep(3)\n",
" # Sleep for the specified duration each time collecting a sample\n",
" # of energy consumption and reported performance\n",
" energy = 0.0\n",
" for i in xrange(loop_cnt):\n",
" te.emeter.reset()\n",
" sleep(sleep_duration)\n",
" nrg = te.emeter.report(te.res_dir).channels\n",
" energy += float(nrg[cl.emeter_ch])\n",
"\n",
" # Compute average energy and performance for the current number of\n",
" # active CPUs all idle at the current OPP\n",
" energy = energy / loop_cnt\n",
" power = energy / SLEEP_DURATION\n",
"\n",
" # Keep track of this new C-State profiling point\n",
" new_row = {'cluster': cl.name,\n",
" 'cpus': cnt + 1,\n",
" 'idle_state': idle,\n",
" 'energy': energy,\n",
" 'power': power}\n",
" idle_power.append(new_row)\n",
"\n",
" # Save data in a CSV file\n",
" writer.writerow(new_row)\n",
" \n",
" # C) profile next C-State\n",
"\n",
" # B) add one more CPU (for the current frequency domain)\n",
"\n",
" # A) profile next cluster (i.e. frequency domain)\n",
"\n",
" # Thaw all tasks in the freezer cgroup\n",
" target.cgroups.freeze(thaw=True)\n",
" target.hotplug.online_all()\n",
"\n",
" idle_df = pd.DataFrame(idle_power)\n",
" return idle_df.set_index(['cluster', 'idle_state', 'cpus']).sort_index(level='cluster')"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {
"collapsed": false,
"run_control": {
"marked": false
},
"scrolled": true
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"2016-09-09 14:52:14,747 INFO : Cluster PD_0 - Online CPUs : set([0])\n",
"2016-09-09 14:55:11,721 INFO : Cluster PD_0 - Online CPUs : set([0, 1])\n",
"2016-09-09 14:58:08,616 INFO : Cluster PD_0 - Online CPUs : set([0, 1, 2])\n",
"2016-09-09 15:01:05,259 INFO : Cluster PD_0 - Online CPUs : set([0, 1, 2, 3])\n"
]
}
],
"source": [
"SLEEP_DURATION = 10\n",
"loop_cnt = 5\n",
"\n",
"idle_df = compute_idle_power(clusters, loop_cnt, SLEEP_DURATION)"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th>energy</th>\n",
" <th>power</th>\n",
" </tr>\n",
" <tr>\n",
" <th>cluster</th>\n",
" <th>idle_state</th>\n",
" <th>cpus</th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th rowspan=\"12\" valign=\"top\">PD_0</th>\n",
" <th rowspan=\"4\" valign=\"top\">0</th>\n",
" <th>1</th>\n",
" <td>1.615466</td>\n",
" <td>0.161547</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>1.660321</td>\n",
" <td>0.166032</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>1.721711</td>\n",
" <td>0.172171</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>1.774200</td>\n",
" <td>0.177420</td>\n",
" </tr>\n",
" <tr>\n",
" <th rowspan=\"4\" valign=\"top\">1</th>\n",
" <th>1</th>\n",
" <td>1.551541</td>\n",
" <td>0.155154</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>1.549942</td>\n",
" <td>0.154994</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>1.557366</td>\n",
" <td>0.155737</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>1.561172</td>\n",
" <td>0.156117</td>\n",
" </tr>\n",
" <tr>\n",
" <th rowspan=\"4\" valign=\"top\">2</th>\n",
" <th>1</th>\n",
" <td>1.256227</td>\n",
" <td>0.125623</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>1.608698</td>\n",
" <td>0.160870</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>1.257657</td>\n",
" <td>0.125766</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>1.260770</td>\n",
" <td>0.126077</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" energy power\n",
"cluster idle_state cpus \n",
"PD_0 0 1 1.615466 0.161547\n",
" 2 1.660321 0.166032\n",
" 3 1.721711 0.172171\n",
" 4 1.774200 0.177420\n",
" 1 1 1.551541 0.155154\n",
" 2 1.549942 0.154994\n",
" 3 1.557366 0.155737\n",
" 4 1.561172 0.156117\n",
" 2 1 1.256227 0.125623\n",
" 2 1.608698 0.160870\n",
" 3 1.257657 0.125766\n",
" 4 1.260770 0.126077"
]
},
"execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"idle_df"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Idle Power Statistics"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"WFI = 0\n",
"CORE_OFF = 1\n",
"\n",
"def idle_power_stats(idle_df):\n",
" \"\"\"\n",
" For each cluster compute per idle state power statistics.\n",
" \n",
" :param idle_df: dataframe containing power numbers\n",
" :type idle_df: :mod:`pandas.DataFrame`\n",
" \"\"\"\n",
"\n",
" stats = []\n",
" for cl in clusters:\n",
" cl_df = idle_df.loc[cl.name].reset_index()\n",
" # Start from deepest idle state\n",
" cl_df = cl_df.sort_values('idle_state', ascending=False)\n",
" grouped = cl_df.groupby('idle_state', sort=False)\n",
" for state, df in grouped:\n",
" energy = df.energy\n",
" power = df.power\n",
" state_name = \"C{}_CLUSTER\".format(state)\n",
" if state == CORE_OFF:\n",
" core_off_nrg_avg = energy.mean()\n",
" core_off_pwr_avg = power.mean()\n",
" if state == WFI:\n",
" energy = df.energy.diff()\n",
" energy[0] = df.energy[0] - core_off_nrg_avg\n",
" power = df.power.diff()\n",
" power[0] = df.power[0] - core_off_pwr_avg\n",
" state_name = \"C0_CORE\"\n",
"\n",
" avg_row = {'cluster': cl.name,\n",
" 'idle_state': state_name,\n",
" 'stats': 'avg',\n",
" 'energy': energy.mean(),\n",
" 'power': power.mean()\n",
" }\n",
" std_row = {'cluster': cl.name,\n",
" 'idle_state': state_name,\n",
" 'stats': 'std',\n",
" 'energy': energy.std(),\n",
" 'power': power.std()\n",
" }\n",
" min_row = {'cluster' : cl.name,\n",
" 'idle_state' : state_name,\n",
" 'stats' : 'min',\n",
" 'energy' : energy.min(),\n",
" 'power' : power.min()\n",
" }\n",
" max_row = {'cluster' : cl.name,\n",
" 'idle_state' : state_name,\n",
" 'stats' : 'max',\n",
" 'energy' : energy.max(),\n",
" 'power' : power.max()\n",
" }\n",
" c99_row = {'cluster' : cl.name,\n",
" 'idle_state' : state_name,\n",
" 'stats' : 'c99',\n",
" 'energy' : energy.quantile(q=0.99),\n",
" 'power' : power.quantile(q=0.99)\n",
" }\n",
" stats.append(avg_row)\n",
" stats.append(std_row)\n",
" stats.append(min_row)\n",
" stats.append(max_row)\n",
" stats.append(c99_row)\n",
" \n",
" stats_df = pd.DataFrame(stats).set_index(\n",
" ['cluster', 'idle_state', 'stats']).sort_index(level='cluster')\n",
" return stats_df.unstack()"
]
},
{
"cell_type": "code",
"execution_count": 103,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"idle_stats = idle_power_stats(idle_df)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Plotting Idle power"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def plot_cstates(idle_power_df, cluster):\n",
" \"\"\"\n",
" Plot C-States profiling for the specified cluster.\n",
" \n",
" :param idle_power_df: dataframe reporting power values in each idle state\n",
" :type idle_power_df: :mod:`pandas.DataFrame`\n",
"\n",
" :param cluster: cluster description\n",
" :type cluster: namedtuple(ClusterDescription)\n",
" \"\"\"\n",
" n_cpus = len(cluster.cpus)\n",
" cmap = ColorMap(len(cluster.idle_states))\n",
" color_map = map(cmap.cmap, cluster.idle_states)\n",
" color_map = [c for c in color_map for i in xrange(n_cpus)]\n",
"\n",
" cl_df = idle_power_df.loc[cluster.name]\n",
" ax = cl_df.power.plot.bar(figsize=(16,8), color=color_map, alpha=0.5,\n",
" legend=False, table=True)\n",
"\n",
" idx = 0\n",
" grouped = cl_df.groupby(level=0)\n",
" for state, df in grouped:\n",
" x = df.index.get_level_values('cpus').tolist()\n",
" y = df.power.tolist()\n",
" slope, intercept = linfit(x, y)\n",
"\n",
" y = [slope * v + intercept for v in x]\n",
" x = range(n_cpus * idx, n_cpus * (idx + 1))\n",
" ax.plot(x, y, color=color_map[idx*n_cpus], linewidth=4)\n",
" idx += 1\n",
"\n",
" ax.grid(True)\n",
" ax.get_xaxis().set_visible(False)\n",
" ax.set_ylabel(\"Idle Power [$\\mu$W]\")\n",
" ax.set_title(\"{} cluster C-states profiling\"\\\n",
" .format(cluster.name), fontsize=16)"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"image/png": "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\nXCIiIiIiItIFNrhERERERESkC2xwiYiIiIiISBfY4BIREREREZEusMElIiIiIiIiXWCDS0RERERE\nRLrABpeIiIiIiIh0gQ0uERERERER6QIbXCIiIiIiItIFNrhERERERESkC2xwiYiIiIiISBfY4BIR\nEREREZEusMElIiIiIiIiXWCDS0RERERERLrABpeIiIiIiIh0gQ0uERERERER6QIbXCIiIiIiItIF\nNrhERERERESkC2xwiYiIiIiISBfY4BIREREREZEusMElIiIiIiIiXWCDS0RERERERLrABpeIiIiI\niIh0we0NrqIoQxRF+UVRlBxFUWbbWOZPiqIcVhRln6Iopuvz/BVF2awoyk+KomQrivKse/eciIiI\niIiIPJlbG1xFUbwALASQBMAAYLyiKN1rLZMMIFhEugF4HMCH12+qADBLRAwAegF4uva6RERERERE\n1HS5+x3cngAOi0iBiJQDWAZgeK1lhgP4DABEZCeA1oqi3CUiRSKy7/r8ywB+BuDnvl0nIiIiIiIi\nT+buBtcPwDGL6ULUbVJrL3O89jKKogQCMAHY6fQ9JCIiIiIioltSs8begRulKMqdAFYAeO76O7n1\nmjJlCgIDAwEAbdq0gclkQr9+/QAA6enpANDgdI10s7n69uvba/RpjfvvzmlzURHgKflcn67hCflY\nTXtIPjXT5qIipKene04+HjqePPXxd9JcBK90IKhf9f7lp1fvb2NOnzQXoUZj51O7nntCPpbTnpKP\n5fRJcxGC4Z7j1zpdwxPysZz2lHxqpk+aPa+eF500IzAUAABzXvXtgV37ecS0J+RjOV100gw0S/eY\nfMx51X+/Go2dT+167gn5WE57Sj6e/vircaPH895772Hfvn1qf2ePIiINLuQsiqIkAJgvIkOuT88B\nICLypsUyHwL4XkS+vD79C4C+IvKroijNAHwN4DsR+aOd+xFnHNf8KVMwX0OI7jTfbMb81NTG3o06\nmJU2zEkbT8wJ8Mysps6fguD5gY29G1aOzDfjk/mpjb0bVpiTdsxKG+akzZRp8xEYOr+xd6MOc858\npC6e39i7YcUTs2JO2nhiToC+s1IUBSKi1Hebuz+ivBtAiKIo9yiKchuAcQDSai2TBuBRQG2Iz4vI\nr9dvWwzgoL3mloiIiIiIiJomt35EWUQqFUV5BsB6VDfXH4vIz4qiPF59s/yfiHyrKMpQRVFyAZQA\nmAIAiqLcC2AigGxFUbIACIBXRWStO4+BiIiIiIiIPJPbv4N7vSENqzXvo1rTz9Sz3nYA3q7dOyIi\nIjVlj9AAACAASURBVCIiIrpVufsjykREREREREQuwQaXiIiIiIiIdIENLhEREREREekCG1wiIiIi\nIiLSBTa4REREREREpAtscImIiIiIiEgX2OASERERERGRLrDBJSIiIiIiIl1gg0tERERERES6wAaX\niIiIiIiIdIENLhEREREREekCG1wiIiIiIiLSBTa4REREREREpAtscImIiIiIiEgX2OASERERERGR\nLrDBJSIiIiIiIl1gg0tERERERES6wAaXiIiIiIiIdIENLhEREREREekCG1wiIiIiIiLSBTa4RERE\nREREpAtscImIiIiIiEgX2OASERERERGRLrDBJSIiIiIiIl1gg0tERERERES6wAaXiIiIiIiIdIEN\nLhEREREREekCG1wiIiIiIiLSBTa4REREREREpAtscImIiIiIiEgX2OASERERERGRLrDBJSIiIiIi\nIl1gg0tERERERES6wAaXiIiIiIiIdIENLhEREREREekCG1wiIiIiIiLSBTa4REREREREpAtscImI\niIiIiEgX2OASERERERGRLrDBJSIiIiIiIl1gg0tERERERES64PYGV1GUIYqi/KIoSo6iKLNtLPMn\nRVEOK4qyT1EU042sS0RERERERE2TWxtcRVG8ACwEkATAAGC8oijday2TDCBYRLoBeBzAh1rXJSIi\nIiIioqbL3e/g9gRwWEQKRKQcwDIAw2stMxzAZwAgIjsBtFYU5S6N6xIREREREVET5e4G1w/AMYvp\nwuvztCyjZV0iIiIiIiJqohQRcd+dKcooAEkiMuP69CMAeorIsxbLrAGQIiI/XJ/eCOBlAEENrWux\nDfcdFBEREREREbmViCj1zW/m5v04DqCLxbT/9Xm1lwmoZ5nbNKyrcmfjfqtSFIU5acCctGNW2jAn\n7ZiVNsxJG+akHbPShjlpx6y0YU7aKEq9vS0A939EeTeAEEVR7lEU5TYA4wCk1VomDcCjAKAoSgKA\n8yLyq8Z13aKsrAx9+/ZVB9+nn36K0NBQhIWF4bPPPmtw/YyMDMTFxaF58+ZYtWqVOv/UqVMYOnSo\ny/a7MTia1bvvvguDwQCTyYRBgwbh2LHqT6nrLStHc/roo48QHR2NmJgYJCYm4sCBAwD0lxPgeFY1\n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\nAAAAAElFTkSuQmCC\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x7feaa83b23d0>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"pd0 = clusters[0]\n",
"\n",
"plot_cstates(idle_df, pd0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Energy Model Generation"
]
},
{
"cell_type": "code",
"execution_count": 123,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def pstates_model_df(clusters, pp_stats, power_perf_df, metric='avg'):\n",
" \"\"\"\n",
" Build two data frames containing data to create the energy model for each\n",
" cluster given as input.\n",
" \n",
" :param clusters: list of clusters to profile\n",
" :type clusters: list(namedtuple(ClusterDescription))\n",
" \n",
" :param pp_stats: power and performance statistics\n",
" :type pp_stats: :mod:`pandas.DataFrame`\n",
" \n",
" :param power_perf_df: power and performance data\n",
" :type power_perf_df: :mod:`pandas.DataFrame`\n",
" \"\"\"\n",
" max_score = pp_stats.perf[metric].max()\n",
"\n",
" core_cap_energy = []\n",
" cluster_cap_energy = []\n",
" for cl in clusters:\n",
" # ACTIVE Energy\n",
" grouped = power_perf_df.loc[cl.name].groupby(level='freq')\n",
" for freq, df in grouped:\n",
" # Get average energy at OPP freq for 1 CPU\n",
" energy_freq_1 = pp_stats.loc[cl.name].loc[freq]['energy'][metric]\n",
" # Get cluster energy at OPP freq\n",
" x = df.index.get_level_values('cpus').tolist()\n",
" y = df.energy.tolist()\n",
" slope, intercept = linfit(x, y)\n",
" # Energy can't be negative but the regression line may intercept the\n",
" # y-axis at a negative value. Im this case cluster energy can be\n",
" # assumed to be 0.\n",
" cluster_energy = intercept if intercept >= 0.0 else 0.0\n",
" core_energy = energy_freq_1 - cluster_energy\n",
" #core_energy = cluster_energy\n",
"\n",
" # Get score at OPP freq\n",
" score_freq = pp_stats.loc[cl.name].loc[freq]['perf'][metric]\n",
" capacity = int(score_freq * 1024 / max_score)\n",
"\n",
" core_cap_energy.append({'cluster' : cl.name,\n",
" 'core': cl.core_name,\n",
" 'freq': freq,\n",
" 'cap': capacity,\n",
" 'energy': core_energy})\n",
" cluster_cap_energy.append({'cluster': cl.name,\n",
" 'freq': freq,\n",
" 'cap': capacity,\n",
" 'energy': cluster_energy})\n",
"\n",
" core_cap_nrg_df = pd.DataFrame(core_cap_energy)\n",
" cluster_cap_nrg_df = pd.DataFrame(cluster_cap_energy)\n",
" return core_cap_nrg_df, cluster_cap_nrg_df"
]
},
{
"cell_type": "code",
"execution_count": 125,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"core_cap_nrg_df, cluster_cap_nrg_df = pstates_model_df(clusters,\n",
" pp_stats,\n",
" power_perf_df,\n",
" metric='avg'\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": 126,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>cap</th>\n",
" <th>cluster</th>\n",
" <th>core</th>\n",
" <th>energy</th>\n",
" <th>freq</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>175</td>\n",
" <td>PD_0</td>\n",
" <td>A53_PD_0</td>\n",
" <td>-0.487181</td>\n",
" <td>208000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>369</td>\n",
" <td>PD_0</td>\n",
" <td>A53_PD_0</td>\n",
" <td>-0.364934</td>\n",
" <td>432000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>626</td>\n",
" <td>PD_0</td>\n",
" <td>A53_PD_0</td>\n",
" <td>-0.173280</td>\n",
" <td>729000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>823</td>\n",
" <td>PD_0</td>\n",
" <td>A53_PD_0</td>\n",
" <td>0.124791</td>\n",
" <td>960000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>1024</td>\n",
" <td>PD_0</td>\n",
" <td>A53_PD_0</td>\n",
" <td>0.575753</td>\n",
" <td>1200000</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" cap cluster core energy freq\n",
"0 175 PD_0 A53_PD_0 -0.487181 208000\n",
"1 369 PD_0 A53_PD_0 -0.364934 432000\n",
"2 626 PD_0 A53_PD_0 -0.173280 729000\n",
"3 823 PD_0 A53_PD_0 0.124791 960000\n",
"4 1024 PD_0 A53_PD_0 0.575753 1200000"
]
},
"execution_count": 126,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"core_cap_nrg_df"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this case, taking the average energy consumed by a core does not provide a nice result because the energy measured while running with $n$ CPUs **is not** $n \\times Energy\\_of\\_one\\_CPU$.\n",
"\n",
"For this reason, we will use a different metric, like for instance the 99th percentile."
]
},
{
"cell_type": "code",
"execution_count": 127,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"core_cap_nrg_df, cluster_cap_nrg_df = pstates_model_df(clusters,\n",
" pp_stats,\n",
" power_perf_df,\n",
" metric='c99'\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": 128,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>cap</th>\n",
" <th>cluster</th>\n",
" <th>core</th>\n",
" <th>energy</th>\n",
" <th>freq</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>175</td>\n",
" <td>PD_0</td>\n",
" <td>A53_PD_0</td>\n",
" <td>0.122582</td>\n",
" <td>208000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>369</td>\n",
" <td>PD_0</td>\n",
" <td>A53_PD_0</td>\n",
" <td>0.237698</td>\n",
" <td>432000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>625</td>\n",
" <td>PD_0</td>\n",
" <td>A53_PD_0</td>\n",
" <td>0.443248</td>\n",
" <td>729000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>822</td>\n",
" <td>PD_0</td>\n",
" <td>A53_PD_0</td>\n",
" <td>0.746307</td>\n",
" <td>960000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>1024</td>\n",
" <td>PD_0</td>\n",
" <td>A53_PD_0</td>\n",
" <td>1.250150</td>\n",
" <td>1200000</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" cap cluster core energy freq\n",
"0 175 PD_0 A53_PD_0 0.122582 208000\n",
"1 369 PD_0 A53_PD_0 0.237698 432000\n",
"2 625 PD_0 A53_PD_0 0.443248 729000\n",
"3 822 PD_0 A53_PD_0 0.746307 960000\n",
"4 1024 PD_0 A53_PD_0 1.250150 1200000"
]
},
"execution_count": 128,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"core_cap_nrg_df"
]
},
{
"cell_type": "code",
"execution_count": 129,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>cap</th>\n",
" <th>cluster</th>\n",
" <th>energy</th>\n",
" <th>freq</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>175</td>\n",
" <td>PD_0</td>\n",
" <td>1.336880</td>\n",
" <td>208000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>369</td>\n",
" <td>PD_0</td>\n",
" <td>1.319919</td>\n",
" <td>432000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>625</td>\n",
" <td>PD_0</td>\n",
" <td>1.357663</td>\n",
" <td>729000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>822</td>\n",
" <td>PD_0</td>\n",
" <td>1.370620</td>\n",
" <td>960000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>1024</td>\n",
" <td>PD_0</td>\n",
" <td>1.493721</td>\n",
" <td>1200000</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" cap cluster energy freq\n",
"0 175 PD_0 1.336880 208000\n",
"1 369 PD_0 1.319919 432000\n",
"2 625 PD_0 1.357663 729000\n",
"3 822 PD_0 1.370620 960000\n",
"4 1024 PD_0 1.493721 1200000"
]
},
"execution_count": 129,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"cluster_cap_nrg_df"
]
},
{
"cell_type": "code",
"execution_count": 130,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def energy_model_dict(clusters, core_cap_nrg_df, cluster_cap_nrg_df, metric='avg'):\n",
" n_states = len(clusters[0].idle_states)\n",
"\n",
" nrg_dict = {}\n",
"\n",
" grouped = core_cap_nrg_df.groupby('cluster')\n",
" for cl, df in grouped:\n",
" nrg_dict[cl] = {\n",
" \"opps\" : {},\n",
" \"core\": {\n",
" \"name\": df.core.iloc[0],\n",
" \"busy-cost\": OrderedDict(),\n",
" \"idle-cost\": OrderedDict()\n",
" },\n",
" \"cluster\": {\n",
" \"busy-cost\": OrderedDict(),\n",
" \"idle-cost\": OrderedDict()\n",
" }\n",
" }\n",
" # Core COSTS\n",
" # ACTIVE costs\n",
" for row in df.iterrows():\n",
" nrg_dict[cl][\"opps\"][row[1].cap] = row[1].freq\n",
" nrg_dict[cl][\"core\"][\"busy-cost\"][row[1].cap] = int(row[1].energy*100)\n",
"\n",
" # IDLE costs\n",
" wfi_nrg = idle_stats.loc[cl].energy[metric][0]\n",
" # WFI\n",
" nrg_dict[cl][\"core\"][\"idle-cost\"][0] = int(wfi_nrg*100)\n",
" # All remaining states are zeroes\n",
" for i in xrange(1, n_states):\n",
" nrg_dict[cl][\"core\"][\"idle-cost\"][i] = 0\n",
"\n",
" # Cluster COSTS\n",
" cl_data = cluster_cap_nrg_df[cluster_cap_nrg_df.cluster == cl]\n",
" # ACTIVE costs\n",
" for row in cl_data.iterrows():\n",
" nrg_dict[cl][\"cluster\"][\"busy-cost\"][row[1].cap] = int(row[1].energy*100)\n",
"\n",
" # IDLE costs\n",
" # Core OFF is the first valid idle cost for cluster\n",
" idle_data = idle_stats.loc[cl].energy[metric]\n",
" # WFI (same as Core OFF)\n",
" nrg_dict[cl][\"cluster\"][\"idle-cost\"][0] = int(idle_data[1]*100)\n",
" # All other idle states (from CORE OFF down)\n",
" for i in xrange(1, n_states):\n",
" nrg_dict[cl][\"cluster\"][\"idle-cost\"][i] = int(idle_data[i]*100)\n",
"\n",
" return nrg_dict"
]
},
{
"cell_type": "code",
"execution_count": 131,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"nrg_dict = energy_model_dict(clusters, core_cap_nrg_df, cluster_cap_nrg_df)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Device Tree EM Format"
]
},
{
"cell_type": "code",
"execution_count": 70,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def dump_device_tree(nrg_dict, outfile='sched-energy.dtsi'):\n",
" \"\"\"\n",
" Generate device tree energy model file.\n",
" \n",
" :param nrg_dict: dictionary describing the energy model\n",
" :type nrg_dict: dict\n",
" \n",
" :param outfile: output file name\n",
" :type outfile: str\n",
" \"\"\"\n",
" with open(os.path.join(te.res_dir, outfile), 'w') as out:\n",
" out.write(\"energy-costs {\\n\")\n",
" idx = 0\n",
" for cl_name in nrg_dict.keys():\n",
" core = nrg_dict[cl_name][\"core\"]\n",
" # Dump Core costs\n",
" out.write(\"\\tCPU_COST_{}: core_cost{} {}\\n\"\\\n",
" .format(core[\"name\"], idx, '{'))\n",
" # ACTIVE costs\n",
" out.write(\"\\t\\tbusy-cost-data = <\\n\")\n",
" for cap, nrg in core[\"busy-cost\"].iteritems():\n",
" out.write(\"\\t\\t\\t{} {}\\n\".format(cap, nrg))\n",
" out.write(\"\\t\\t>;\\n\")\n",
" # IDLE costs\n",
" out.write(\"\\t\\tidle-cost-data = <\\n\")\n",
" # arch idle\n",
" out.write(\"\\t\\t\\t{}\\n\".format(core[\"idle-cost\"][0]))\n",
" for nrg in core[\"idle-cost\"].values():\n",
" out.write(\"\\t\\t\\t{}\\n\".format(nrg)) \n",
" out.write(\"\\t\\t>;\\n\")\n",
" out.write(\"\\t};\\n\")\n",
"\n",
" # Dump Cluster costs\n",
" cl = nrg_dict[cl_name][\"cluster\"]\n",
" out.write(\"\\tCLUSTER_COST_{}: cluster_cost{} {}\\n\"\\\n",
" .format(cl_name, idx, '{'))\n",
" # ACTIVE costs\n",
" out.write(\"\\t\\tbusy-cost-data = <\\n\")\n",
" for cap, nrg in cl[\"busy-cost\"].iteritems():\n",
" out.write(\"\\t\\t\\t{} {}\\n\".format(cap, nrg))\n",
" out.write(\"\\t\\t>;\\n\")\n",
" # IDLE costs\n",
" out.write(\"\\t\\tidle-cost-data = <\\n\")\n",
" # arch idle\n",
" out.write(\"\\t\\t\\t{}\\n\".format(cl[\"idle-cost\"][0]))\n",
" for nrg in cl[\"idle-cost\"].values():\n",
" out.write(\"\\t\\t\\t{}\\n\".format(nrg))\n",
" out.write(\"\\t\\t>;\\n\")\n",
" out.write(\"\\t};\\n\")\n",
" idx += 1\n",
" out.write(\"};\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## C Code EM Format"
]
},
{
"cell_type": "code",
"execution_count": 71,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def dump_c_code(nrg_dict, cluster_ids, outfile='energy_model.c'):\n",
" \"\"\"\n",
" Generate C code energy model file.\n",
" \n",
" :param nrg_dict: dictionary describing the energy model\n",
" :type nrg_dict: dict\n",
" \n",
" :param cluster_ids: mapping between cluster names and cluster IDs\n",
" :type cluster_ids: dict\n",
" \n",
" :param outfile: output file name\n",
" :type outfile: str\n",
" \"\"\"\n",
" with open(os.path.join(te.res_dir, outfile), 'w') as o:\n",
"\n",
" core_names = []\n",
" for cl_name in nrg_dict.keys():\n",
" # Dump Core data\n",
" core = nrg_dict[cl_name][\"core\"]\n",
" core_names.append(core[\"name\"])\n",
" o.write(\"static struct capacity_state cap_states_core_{}[] = {}\\n\"\\\n",
" .format(core[\"name\"], '{'))\n",
" o.write(\"\\t/* Power per CPU */\\n\")\n",
" for cap, nrg in core[\"busy-cost\"].iteritems():\n",
" o.write(\"\\t {{ .cap = {:5d}, .power = {:5d}, }},\\n\"\\\n",
" .format(cap, nrg))\n",
" o.write(\"\\t};\\n\")\n",
"\n",
" o.write(\"\\n\")\n",
"\n",
" o.write(\"static struct idle_state idle_states_core_{}[] = {}\\n\"\\\n",
" .format(core[\"name\"], '{'))\n",
" # arch idle (same as WFI)\n",
" o.write(\"\\t {{ .power = {:5d}, }},\\n\".format(core[\"idle-cost\"][0]))\n",
" for nrg in core[\"idle-cost\"].values():\n",
" o.write(\"\\t {{ .power = {:5d}, }},\\n\".format(nrg))\n",
" o.write(\"\\t};\\n\")\n",
"\n",
" o.write(\"\\n\")\n",
"\n",
" # Dump Cluster data\n",
" cl = nrg_dict[cl_name][\"cluster\"]\n",
" o.write(\"static struct capacity_state cap_states_cluster_{}[] = {}\\n\"\\\n",
" .format(cl_name, '{'))\n",
" o.write(\"\\t/* Power per cluster */\\n\")\n",
" for cap, nrg in cl[\"busy-cost\"].iteritems():\n",
" o.write(\"\\t {{ .cap = {:5d}, .power = {:5d}, }},\\n\"\\\n",
" .format(cap, nrg))\n",
" o.write(\"\\t};\\n\")\n",
"\n",
" o.write(\"\\n\")\n",
"\n",
" o.write(\"static struct idle_state idle_states_cluster_{}[] = {}\\n\"\\\n",
" .format(cl_name, '{'))\n",
" # arch idle (same as Core OFF)\n",
" o.write(\"\\t {{ .power = {:5d}, }},\\n\".format(cl[\"idle-cost\"][0]))\n",
" for nrg in cl[\"idle-cost\"].values():\n",
" o.write(\"\\t {{ .power = {:5d}, }},\\n\".format(nrg))\n",
" o.write(\"\\t};\\n\")\n",
"\n",
" o.write(\"\\n\")\n",
"\n",
" o.write(\"static struct sched_group_energy energy_cluster_{} = {}\\n\"\\\n",
" .format(core[\"name\"], '{'))\n",
" o.write(\"\\t.nr_idle_states = ARRAY_SIZE(idle_states_cluster_{}),\\n\"\\\n",
" .format(core[\"name\"]))\n",
" o.write(\"\\t.idle_states = idle_states_cluster_{},\\n\"\\\n",
" .format(core[\"name\"]))\n",
" o.write(\"\\t.nr_cap_states = ARRAY_SIZE(cap_states_cluster_{}),\\n\"\\\n",
" .format(core[\"name\"]))\n",
" o.write(\"\\t.cap_states = cap_states_cluster_{},\\n\"\\\n",
" .format(core[\"name\"]))\n",
" o.write(\"};\\n\")\n",
"\n",
" o.write(\"\\n\")\n",
"\n",
" # Array of pointers to CORE sched_group_energy structs\n",
" o.write(\"static struct sched_group_energy *energy_cores[] = {\\n\")\n",
" for cl_name in cluster_ids.values():\n",
" o.write(\"\\t&energy_core_{},\\n\"\\\n",
" .format(nrg_dict[cl_name][\"core\"][\"name\"]))\n",
" o.write(\"};\\n\")\n",
"\n",
" o.write(\"\\n\")\n",
"\n",
" # Array of pointers to CLUSTER sched_group_energy structs\n",
" o.write(\"static struct sched_group_energy *energy_clusters[] = {\\n\")\n",
" for name in cluster_ids.values():\n",
" o.write(\"\\t&energy_cluster_{},\\n\".format(name))\n",
" o.write(\"};\\n\")\n",
"\n",
" o.write(\"\\n\")\n",
"\n",
" o.write(\"static inline\\n\")\n",
" o.write(\"const struct sched_group_energy * const cpu_core_energy(int cpu)\\n\")\n",
" o.write(\"{\\n\")\n",
" o.write(\"\\treturn energy_cores[cpu_topology[cpu].cluster_id];\\n\")\n",
" o.write(\"}\\n\")\n",
"\n",
" o.write(\"\\n\")\n",
"\n",
" o.write(\"static inline\\n\")\n",
" o.write(\"const struct sched_group_energy * const cpu_cluster_energy(int cpu)\\n\")\n",
" o.write(\"{\\n\")\n",
" o.write(\"\\treturn energy_clusters[cpu_topology[cpu].cluster_id];\\n\")\n",
" o.write(\"}\\n\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## JSON EM Format"
]
},
{
"cell_type": "code",
"execution_count": 72,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def dump_json(nrg_dict, outfile='energy_model.json'):\n",
" \"\"\"\n",
" Generate JSON energy model file.\n",
" \n",
" :param nrg_dict: dictionary describing the energy model\n",
" :type nrg_dict: dict\n",
" \n",
" :param outfile: output file name\n",
" :type outfile: str\n",
" \"\"\"\n",
" with open(os.path.join(te.res_dir, outfile), 'w') as ofile:\n",
" json.dump(nrg_dict, ofile, sort_keys=True, indent=4)"
]
},
{
"cell_type": "code",
"execution_count": 133,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"dump_device_tree(nrg_dict)"
]
},
{
"cell_type": "code",
"execution_count": 134,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"energy-costs {\r\n",
"\tCPU_COST_A53_PD_0: core_cost0 {\r\n",
"\t\tbusy-cost-data = <\r\n",
"\t\t\t175 12\r\n",
"\t\t\t369 23\r\n",
"\t\t\t625 44\r\n",
"\t\t\t822 74\r\n",
"\t\t\t1024 125\r\n",
"\t\t>;\r\n",
"\t\tidle-cost-data = <\r\n",
"\t\t\t5\r\n",
"\t\t\t5\r\n",
"\t\t\t0\r\n",
"\t\t\t0\r\n",
"\t\t>;\r\n",
"\t};\r\n",
"\tCLUSTER_COST_PD_0: cluster_cost0 {\r\n",
"\t\tbusy-cost-data = <\r\n",
"\t\t\t175 133\r\n",
"\t\t\t369 131\r\n",
"\t\t\t625 135\r\n",
"\t\t\t822 137\r\n",
"\t\t\t1024 149\r\n",
"\t\t>;\r\n",
"\t\tidle-cost-data = <\r\n",
"\t\t\t155\r\n",
"\t\t\t155\r\n",
"\t\t\t155\r\n",
"\t\t\t125\r\n",
"\t\t>;\r\n",
"\t};\r\n",
"};"
]
}
],
"source": [
"!cat ./sched-energy.dtsi"
]
}
],
"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.9"
},
"toc": {
"toc_cell": false,
"toc_number_sections": true,
"toc_threshold": 6,
"toc_window_display": true
}
},
"nbformat": 4,
"nbformat_minor": 0
}