libs/utils/energy: make energy meters API more generic

Currently available energy meters provide different formats for the results,
which makes the API not generic.

This makes the HWMon energy meters return results with similar format as the
ACME. A new attribute is introduced in the configuration dictionary called
"channel_map" that allows to map a user-defined label to the energy
meter-specific channel name. For example, in case of HWMon channel names are
the strings specified as "sites".

This way, when using the report() method, the user knows what is the label she
should use to measuree energy from a given channel and allows compatibility of
the code when using a different type of energy meter, by just changing the
channel mapping.

Signed-off-by: Michele Di Giorgio <michele.digiorgio@arm.com>
diff --git a/ipynb/sched_dvfs/smoke_test.ipynb b/ipynb/sched_dvfs/smoke_test.ipynb
index 9eab63f..f1699ec 100644
--- a/ipynb/sched_dvfs/smoke_test.ipynb
+++ b/ipynb/sched_dvfs/smoke_test.ipynb
@@ -324,7 +324,7 @@
     "    rtapp.run(out_dir=exp_dir)\n",
     "    \n",
     "    # Stop FTrace and sample Energy consumption\n",
-    "    nrg = te.emeter.sample()\n",
+    "    nrg = te.emeter.report(exp_dir).channels\n",
     "    te.ftrace.stop()\n",
     "    \n",
     "    logging.info('Energy: %s', nrg)\n",
@@ -392,8 +392,8 @@
     "    for governor in confs:\n",
     "        plot_title = \"{}\".format(governor.upper())\n",
     "        nrg = results[tid][governor]['energy']\n",
-    "        nrg_little = float(nrg['a53']['delta'])\n",
-    "        nrg_big = float(nrg['a57']['delta'])\n",
+    "        nrg_little = float(nrg['little'])\n",
+    "        nrg_big = float(nrg['big'])\n",
     "        nrg_sum = nrg_little + nrg_big\n",
     "        print \"{:15s} | {:9.3f} {:9.3f} {:9.3f}\"\\\n",
     "            .format(governor, nrg_little, nrg_big, nrg_sum)"
diff --git a/ipynb/tutorial/00_LisaInANutshell.ipynb b/ipynb/tutorial/00_LisaInANutshell.ipynb
index c4edc58..a0a9f78 100644
--- a/ipynb/tutorial/00_LisaInANutshell.ipynb
+++ b/ipynb/tutorial/00_LisaInANutshell.ipynb
@@ -881,7 +881,7 @@
     "    wload.run(out_dir=res_dir)\n",
     "\n",
     "    logging.info('## Read energy consumption: %s/energy.json', res_dir)\n",
-    "    nrg, nrg_file = te.emeter.report(out_dir=res_dir)\n",
+    "    nrg_report = te.emeter.report(out_dir=res_dir)\n",
     "\n",
     "    logging.info('# Stop FTrace')\n",
     "    te.ftrace.stop()\n",
@@ -897,7 +897,7 @@
     "    logging.info('   %s', res_dir)\n",
     "    !tree {res_dir}\n",
     "    \n",
-    "    return nrg, nrg_file, plt, plt_file, trace_file"
+    "    return nrg_report, plt, plt_file, trace_file"
    ]
   },
   {
@@ -963,7 +963,7 @@
     }
    ],
    "source": [
-    "nrg, nrg_file, plt, plt_file, trace_file = execute(te, rtapp, te.res_dir)"
+    "nrg_report, plt, plt_file, trace_file = execute(te, rtapp, te.res_dir)"
    ]
   },
   {
@@ -1023,7 +1023,7 @@
    "source": [
     "import pandas as pd\n",
     "\n",
-    "df = pd.DataFrame(list(nrg.iteritems()),\n",
+    "df = pd.DataFrame(list(nrg_report.channels.iteritems()),\n",
     "                  columns=['Cluster', 'Energy'])\n",
     "df = df.set_index('Cluster')\n",
     "df"
diff --git a/ipynb/tutorial/03_WlGenUsage.ipynb b/ipynb/tutorial/03_WlGenUsage.ipynb
index c01a95f..aed96f5 100644
--- a/ipynb/tutorial/03_WlGenUsage.ipynb
+++ b/ipynb/tutorial/03_WlGenUsage.ipynb
@@ -200,7 +200,7 @@
     "    wload.run(out_dir=res_dir)\n",
     "\n",
     "    logging.info('## Read energy consumption: %s/energy.json', res_dir)\n",
-    "    nrg, nrg_file = te.emeter.report(out_dir=res_dir)\n",
+    "    nrg_report = te.emeter.report(out_dir=res_dir)\n",
     "\n",
     "    logging.info('# Stop FTrace')\n",
     "    te.ftrace.stop()\n",
@@ -216,7 +216,7 @@
     "    logging.info('   %s', res_dir)\n",
     "    !ls -la {res_dir}\n",
     "    \n",
-    "    return nrg, nrg_file, plt, plt_file, trace_file"
+    "    return nrg_report, plt, plt_file, trace_file"
    ]
   },
   {
@@ -432,7 +432,7 @@
    ],
    "source": [
     "res_dir = os.path.join(te.res_dir, rtapp_name)\n",
-    "nrg, nrg_file, plt, plt_file, trace_file = execute(te, rtapp, res_dir)"
+    "nrg_report, plt, plt_file, trace_file = execute(te, rtapp, res_dir)"
    ]
   },
   {
@@ -469,8 +469,8 @@
    ],
    "source": [
     "# Dump the energy measured for the LITTLE and big clusters\n",
-    "logging.info('Energy: %s', nrg_file)\n",
-    "print json.dumps(nrg, indent=4, sort_keys=True)"
+    "logging.info('Energy: %s', nrg_report.report_file)\n",
+    "print json.dumps(nrg_report.channels, indent=4, sort_keys=True)"
    ]
   },
   {
@@ -983,7 +983,7 @@
    ],
    "source": [
     "res_dir = os.path.join(te.res_dir, rtapp_name)\n",
-    "nrg, nrg_file, plt, plt_file, trace_file = execute(te, rtapp, res_dir)"
+    "nrg_report, plt, plt_file, trace_file = execute(te, rtapp, res_dir)"
    ]
   },
   {
@@ -1108,7 +1108,7 @@
    ],
    "source": [
     "res_dir = os.path.join(te.res_dir, rtapp_name)\n",
-    "nrg, nrg_file, plt, plt_file, trace_file = execute(te, rtapp, res_dir)"
+    "nrg_report, plt, plt_file, trace_file = execute(te, rtapp, res_dir)"
    ]
   },
   {
@@ -1333,7 +1333,7 @@
    ],
    "source": [
     "res_dir = os.path.join(te.res_dir, perf_name)\n",
-    "nrg, nrg_file, plt, plt_file, trace_file = execute(te, perf, res_dir)"
+    "nrg_report, plt, plt_file, trace_file = execute(te, perf, res_dir)"
    ]
   },
   {
diff --git a/ipynb/tutorial/UseCaseExamples_SchedTuneAnalysis.ipynb b/ipynb/tutorial/UseCaseExamples_SchedTuneAnalysis.ipynb
index 45881f6..e92bd3f 100644
--- a/ipynb/tutorial/UseCaseExamples_SchedTuneAnalysis.ipynb
+++ b/ipynb/tutorial/UseCaseExamples_SchedTuneAnalysis.ipynb
@@ -2237,9 +2237,9 @@
     "\n",
     "    if te.emeter:\n",
     "        logging.info('## Read energy consumption: %s/energy.json', res_dir)\n",
-    "        nrg, nrg_file = te.emeter.report(out_dir=res_dir)\n",
+    "        nrg_report = te.emeter.report(out_dir=res_dir)\n",
     "    else:\n",
-    "        nrg, nrg_file = None, None\n",
+    "        nrg_report = None\n",
     "\n",
     "    logging.info('# Stop FTrace')\n",
     "    te.ftrace.stop()\n",
@@ -2255,7 +2255,7 @@
     "    logging.info('   %s', res_dir)\n",
     "    !tree {res_dir}\n",
     "    \n",
-    "    return nrg, nrg_file, plt, plt_file, trace_file"
+    "    return nrg_report, plt, plt_file, trace_file"
    ]
   },
   {
@@ -2267,7 +2267,7 @@
    },
    "outputs": [],
    "source": [
-    "nrg, nrg_file, plt, plt_file, trace_file = execute(te, rtapp, te.res_dir, cg=boostgroup.name)"
+    "nrg_report, plt, plt_file, trace_file = execute(te, rtapp, te.res_dir, cg=boostgroup.name)"
    ]
   },
   {
diff --git a/ipynb/wlgen/simple_rtapp.ipynb b/ipynb/wlgen/simple_rtapp.ipynb
index d274f2b..a14398b 100644
--- a/ipynb/wlgen/simple_rtapp.ipynb
+++ b/ipynb/wlgen/simple_rtapp.ipynb
@@ -298,7 +298,7 @@
     "rtapp.run(out_dir=te.res_dir, cgroup=\"\")\n",
     "\n",
     "logging.info('#### Read energy consumption: %s/energy.json', te.res_dir)\n",
-    "(nrg, nrg_file) = te.emeter.report(out_dir=te.res_dir)\n",
+    "nrg_report = te.emeter.report(out_dir=te.res_dir)\n",
     "\n",
     "logging.info('#### Stop FTrace')\n",
     "te.ftrace.stop()\n",
@@ -482,8 +482,8 @@
    ],
    "source": [
     "# Dump the energy measured for the LITTLE and big clusters\n",
-    "logging.info('Energy: %s', nrg_file)\n",
-    "print json.dumps(nrg, indent=4, sort_keys=True)"
+    "logging.info('Energy: %s', nrg_report.report_file)\n",
+    "print json.dumps(nrg_report.channels, indent=4, sort_keys=True)"
    ]
   },
   {
diff --git a/libs/utils/energy.py b/libs/utils/energy.py
index 4bf3e42..3518531 100644
--- a/libs/utils/energy.py
+++ b/libs/utils/energy.py
@@ -34,6 +34,10 @@
         'conf' : {
             'sites' : [ 'A7 Jcore', 'A15 Jcore' ],
             'kinds' : [ 'energy']
+        },
+        'channel_map' : {
+            'LITTLE' : 'A7 Jcore',
+            'big' : 'A15 Jcore',
         }
     },
 
@@ -43,6 +47,10 @@
         'conf' : {
             'sites' : [ 'a53', 'a57' ],
             'kinds' : [ 'energy' ],
+        },
+        'channel_map' : {
+            'LITTLE' : 'a53',
+            'big' : 'a57',
         }
     },
     'juno2' : {
@@ -55,7 +63,7 @@
         # little/big cores on the board, use a channel_map section to
         # indicate which channel is which
         'channel_map' : {
-            'little' : 'BOARDLITTLE',
+            'LITTLE' : 'BOARDLITTLE',
             'big' : 'BOARDBIG',
         }
     },
@@ -73,6 +81,8 @@
 }
 
 EnergyCounter = namedtuple('EnergyCounter', ['site', 'pwr_total' , 'pwr_samples', 'pwr_avg', 'time', 'nrg'])
+EnergyReport = namedtuple('EnergyReport', ['channels', 'report_file'])
+
 class EnergyMeter(object):
 
     _meter = None
@@ -125,7 +135,7 @@
 
 class HWMon(EnergyMeter):
 
-    def __init__(self, target, hwmon_conf=None, res_dir=None):
+    def __init__(self, target, conf=None, res_dir=None):
         super(HWMon, self).__init__(target, res_dir)
 
         # The HWMon energy meter
@@ -145,29 +155,23 @@
         self._hwmon = devlib.HwmonInstrument(self._target)
 
         # Configure channels for energy measurements
-        logging.debug('%14s - Enabling channels %s', 'HWMon', hwmon_conf['conf'])
-        self._hwmon.reset(**hwmon_conf['conf'])
+        logging.debug('%14s - Enabling channels %s', 'HWMon', conf['conf'])
+        self._hwmon.reset(**conf['conf'])
 
         # Logging enabled channels
         logging.info('%14s - Channels selected for energy sampling:', 'HWMon')
         for channel in self._hwmon.active_channels:
             logging.info('%14s -    %s', 'HWMon', channel.label)
 
-        # record the hwmon channel mapping
-        self.little_channel = self._target.little_core.upper()
-        self.big_channel = self._target.big_core.upper()
-        if hwmon_conf and 'channel_map' in hwmon_conf:
-            self.little_channel = hwmon_conf['channel_map']['little']
-            self.big_channel = hwmon_conf['channel_map']['big']
-        logging.info('%14s - Using channel %s as little channel',
-                     'HWMon', self.little_channel)
-        logging.info('%14s - Using channel %s as big channel',
-                     'HWMon', self.big_channel)
-
+        # record the HWMon channels
+        self._channels = conf.get('channel_map', {
+            'LITTLE': self._target.little_core.upper(),
+            'big': self._target.big_core.upper()
+        })
 
     def sample(self):
         if self._hwmon is None:
-            return
+            return None
         samples = self._hwmon.take_measurement()
         for s in samples:
             label = s.channel.label\
@@ -199,41 +203,25 @@
             self.readings[label]['total'] = 0
         logging.debug('RESET: %s', self.readings)
 
-
     def report(self, out_dir, out_file='energy.json'):
         if self._hwmon is None:
-            return
+            return (None, None)
         # Retrive energy consumption data
         nrg = self.sample()
         # Reformat data for output generation
         clusters_nrg = {}
-        for ch in nrg:
-            nrg_total = nrg[ch]['total']
-            logging.info('%14s - Energy [%16s]: %.6f',
-                         'HWMon', ch, nrg_total)
-            if ch.upper() == self.little_channel:
-                clusters_nrg['LITTLE'] = '{:.6f}'.format(nrg_total)
-            elif ch.upper() == self.big_channel:
-                clusters_nrg['big'] = '{:.6f}'.format(nrg_total)
-            else:
-                logging.warning('%14s - Unable to bind hwmon channel [%s]'\
-                        ' to a big.LITTLE cluster',
-                        'HWMon', ch)
-                clusters_nrg[ch] = '{:.6f}'.format(nrg_total)
-        if 'LITTLE' not in clusters_nrg:
-                logging.warning('%14s - No energy data for LITTLE cluster',
-                                'HWMon')
-        if 'big' not in clusters_nrg:
-                logging.warning('%14s - No energy data for big cluster',
-                                'HWMon')
+        for channel in self._channels:
+            label = self._channels[channel]
+            nrg_total = nrg[label]['total']
+            logging.info('%14s - Energy [%16s]: %.6f', 'HWMon', label, nrg_total)
+            clusters_nrg[channel] = nrg_total
 
         # Dump data as JSON file
         nrg_file = '{}/{}'.format(out_dir, out_file)
         with open(nrg_file, 'w') as ofile:
             json.dump(clusters_nrg, ofile, sort_keys=True, indent=4)
 
-        return (clusters_nrg, nrg_file)
-
+        return EnergyReport(clusters_nrg, nrg_file)
 
 class AEP(EnergyMeter):