=== added file 'doc/arm_energy_probe.rst'
--- doc/arm_energy_probe.rst	1970-01-01 00:00:00 +0000
+++ doc/arm_energy_probe.rst	2012-12-19 04:23:01 +0000
@@ -0,0 +1,102 @@
+Using the ARM Energy Probe
+==========================
+
+The dispatcher includes a `signal handler`_ that allows tests in LAVA
+to include power measurement data per test case. Since the functionality
+is built into the dispatcher there are really two main things required to
+enable this.
+
+ * deployment of a device with the AEP
+ * creating jobs to use it
+
+.. _`signal handler`: external_measurement.html
+
+Deployment
+----------
+
+Hooking up probes to a specific board are beyond the scope of this document.
+However, once a board has a probe hooked up and plugged into the host PC,
+the dispatcher can be configured as follows::
+
+  # These options should be added to the device.conf ie:
+  # /srv/lava/instances/<INST>/etc/lava-dispatcher/devices/panda01.conf
+  # if the defaults are what's needed, then this can be skipped
+
+  # The location of the binary (default=/usr/local/bin/arm-probe)
+  arm_probe_binary = /home/doanac/linaro/arm-probe/arm-probe/arm-probe
+
+  # The location of the config file (default=/usr/local/etc/arm-probe-config)
+  arm_probe_config = /home/doanac/linaro/arm-probe/config
+
+  # The channels configured for this probe (can be an array default=VDD_VCORE1)
+  arm_probe_channels = VDD_VCORE1
+
+Since there may be a mix of device that have AEPs and different configs for
+the ones that do, its also recommended to use the LAVA admin interface for
+the lava-scheduler to define some tagging scheme that can be used to identify
+devices with certain AEP configs. This allows job files to then specify a
+tag if it needs AEP or some special AEP config.
+
+Creating a Job File
+-------------------
+
+The job is pretty standard and can be read about our `jobfile`_ documentation.
+The specific thing needed for an AEP job would be the lava-test-shell action
+which would look something like::
+
+   {
+        "command": "lava_test_shell",
+        "parameters": {
+            "testdef_repos": [
+              {"bzr-repo": "lp:~doanac/+junk/arm-probe-demo",
+               "testdef": "arm-probe.yaml"
+              }
+            ],
+            "timeout": 1800
+        }
+    }
+
+.. _`jobfile`: jobfile.html
+
+Specifying the Test Definition
+------------------------------
+
+The test definintion should live in a bzr/git repository. The `above example's`_
+test definintion would look like::
+
+  metadata:
+      format: Lava-Test Test Definition 1.0
+      name: arm-probe-demo
+
+  handler:
+      handler-name: arm-probe
+      params:
+          # The post_process_script is run for each test case. Its called like:
+          # <script> <testcase_id> <aep stdout> <aep stderr> <aep channel_1>...
+          # This value can be either a relative path in the repo it lives in, or
+          # can be URL that will be downloaded
+          post_process_script: plot.sh
+          # probe_args allow you to add additional parameters when invoking the
+          # arm-probe binary
+          probe_args:
+            - -a
+            - '0.01'
+
+  install:
+      deps:
+          - cpuburn
+
+  run:
+      steps:
+          # These steps run on the target. lava-test-shell will call your script
+          # and ensure the host starts/stops the arm-probe for each test case
+          - 'lava-test-case aep-idle --shell ./aep-idle.sh'
+          - 'lava-test-case aep-burn --shell ./aep-burn.sh'
+
+
+Upon completion of the test run, the dispatcher will invoke the provided
+`postprocess_test_result`_ script so that it can generate things like graphs as it sees
+fit to compliment the data normally captured by LAVA.
+
+.. _`above example's`: http://bazaar.launchpad.net/~doanac/+junk/arm-probe-demo/files
+.. _`postprocess_test_result`: http://bazaar.launchpad.net/~doanac/+junk/arm-probe-demo/view/head:/plot.sh

=== modified file 'doc/index.rst'
--- doc/index.rst	2012-11-22 02:03:49 +0000
+++ doc/index.rst	2012-12-16 22:24:10 +0000
@@ -35,6 +35,7 @@
    usage.rst
    lava_test_shell.rst
    external_measurement.rst
+   arm_energy_probe.rst
    proxy.rst
 
 * :ref:`search`

=== modified file 'lava_dispatcher/config.py'
--- lava_dispatcher/config.py	2012-12-13 21:23:55 +0000
+++ lava_dispatcher/config.py	2012-12-16 22:20:53 +0000
@@ -82,6 +82,10 @@
     android_orig_block_device = schema.StringOption(default="mmcblk0")
     android_lava_block_device = schema.StringOption(default="mmcblk0")
 
+    arm_probe_binary = schema.StringOption(default='/usr/local/bin/arm-probe')
+    arm_probe_config = schema.StringOption(default='/usr/local/etc/arm-probe-config')
+    arm_probe_channels = schema.ListOption(default=['VDD_VCORE1'])
+
 
 class OptionDescriptor(object):
     def __init__(self, name):

=== modified file 'lava_dispatcher/signals/__init__.py'
--- lava_dispatcher/signals/__init__.py	2012-11-23 00:39:23 +0000
+++ lava_dispatcher/signals/__init__.py	2012-12-19 04:27:40 +0000
@@ -18,7 +18,16 @@
 # along
 # with this program; if not, see <http://www.gnu.org/licenses>.
 
+import contextlib
 import logging
+import tempfile
+
+from lava_dispatcher.utils import rmtree
+
+from lava_dispatcher.lava_test_shell import (
+    _result_to_dir,
+    _result_from_dir,
+)
 
 
 class BaseSignalHandler(object):
@@ -91,6 +100,18 @@
             except:
                 logging.exception("postprocess_test_result failed for %s", tc_id)
 
+    @contextlib.contextmanager
+    def _result_as_dir(self, test_result):
+        scratch_dir = self.testdef_obj.context.client.target_device.scratch_dir
+        rdir = tempfile.mkdtemp(dir=scratch_dir)
+        try:
+            _result_to_dir(test_result, rdir)
+            yield rdir
+            test_result.clear()
+            test_result.update(_result_from_dir(rdir))
+        finally:
+            rmtree(rdir)
+
     def start_testcase(self, test_case_id):
         return {}
 

=== added file 'lava_dispatcher/signals/armprobe.py'
--- lava_dispatcher/signals/armprobe.py	1970-01-01 00:00:00 +0000
+++ lava_dispatcher/signals/armprobe.py	2012-12-18 23:58:02 +0000
@@ -0,0 +1,77 @@
+import logging
+import os
+import subprocess
+import urlparse
+
+from lava_dispatcher.downloader import download_image
+from lava_dispatcher.signals import SignalHandler
+
+
+class ArmProbe(SignalHandler):
+
+    def __init__(self, testdef_obj, post_process_script, probe_args=None):
+        SignalHandler.__init__(self, testdef_obj)
+
+        self.scratch_dir = testdef_obj.context.client.target_device.scratch_dir
+
+        # post_process_script can be local to the repo or a URL
+        if not urlparse.urlparse(post_process_script).scheme:
+            self.post_process_script = os.path.join(
+                testdef_obj.repo, post_process_script)
+        else:
+            self.post_process_script = download_image(
+                post_process_script, testdef_obj.context, self.scratch_dir)
+        os.chmod(self.post_process_script, 755)  # make sure we can execute it
+
+        # build up the command we'll use for running the probe
+        config = testdef_obj.context.client.config
+        self.aep_channels = config.arm_probe_channels
+        self.aep_args = [
+            config.arm_probe_binary, '-C', config.arm_probe_config]
+        for c in self.aep_channels:
+            self.aep_args.append('-c')
+            self.aep_args.append(c)
+
+        for arg in probe_args:
+            self.aep_args.append(arg)
+
+    def start_testcase(self, test_case_id):
+        ofile = os.path.join(self.scratch_dir, '%s.out' % test_case_id)
+        efile = os.path.join(self.scratch_dir, '%s.err' % test_case_id)
+        ofile = open(ofile, 'w')
+        efile = open(efile, 'w')
+
+        proc = subprocess.Popen(
+            self.aep_args, stdout=ofile, stderr=efile, stdin=subprocess.PIPE)
+        # The arm-probe-binary allows you to write to stdin via a pipe and
+        # includes the content as comments in the header of its output
+        proc.stdin.write(
+            '# run from lava-test-shell with args: %r' % self.aep_args)
+        proc.stdin.close()
+
+        return {
+            'process': proc,
+            'logfile': ofile,
+            'errfile': efile,
+        }
+
+    def end_testcase(self, test_case_id, data):
+        proc = data['process']
+        proc.terminate()
+
+    def postprocess_test_result(self, test_result, data):
+        tcid = test_result['test_case_id']
+        logging.info('analyzing aep data for %s ...', tcid)
+
+        lfile = data['logfile']
+        efile = data['errfile']
+
+        lfile.close()
+        efile.close()
+
+        with self._result_as_dir(test_result) as result_dir:
+            args = [self.post_process_script, tcid, lfile.name, efile.name]
+            args.extend(self.aep_channels)
+
+            if subprocess.call(args, cwd=result_dir) != 0:
+                logging.warn('error calling post_process_script')

=== modified file 'lava_dispatcher/signals/shellhooks.py'
--- lava_dispatcher/signals/shellhooks.py	2012-12-18 19:50:48 +0000
+++ lava_dispatcher/signals/shellhooks.py	2012-12-19 04:27:40 +0000
@@ -5,13 +5,11 @@
 import os
 import tempfile
 
-from lava_dispatcher.lava_test_shell import (
-    _read_content,
-    _result_to_dir,
-    _result_from_dir)
+from lava_dispatcher.lava_test_shell import _read_content
 from lava_dispatcher.signals import SignalHandler
 from lava_dispatcher.test_data import create_attachment
-from lava_dispatcher.utils import mkdtemp, rmtree
+from lava_dispatcher.utils import mkdtemp
+
 
 class ShellHooks(SignalHandler):
 
@@ -64,24 +62,16 @@
             'end_testcase', case_data['case_dir'])
 
     def postprocess_test_result(self, test_result, case_data):
-        test_case_id = test_result['test_case_id']
-        scratch_dir = tempfile.mkdtemp()
-        try:
-            result_dir = os.path.join(scratch_dir, test_case_id)
-            os.mkdir(result_dir)
-            _result_to_dir(test_result, result_dir)
+        with self._result_as_dir(test_result) as result_dir:
             case_data['postprocess_test_result_output'] = self._invoke_hook(
                 'postprocess_test_result', case_data['case_dir'], [result_dir])
-            test_result.clear()
-            test_result.update(_result_from_dir(result_dir))
-        finally:
-            rmtree(scratch_dir)
+
         for key in 'start_testcase_output', 'end_testcase_output', \
-          'postprocess_test_result_output':
-          path = case_data.get(key)
-          if path is None:
-              continue
-          content = _read_content(path, ignore_missing=True)
-          if content:
-              test_result['attachments'].append(
-                  create_attachment(key + '.txt', _read_content(path)))
+                'postprocess_test_result_output':
+            path = case_data.get(key)
+            if path is None:
+                continue
+            content = _read_content(path, ignore_missing=True)
+            if content:
+                test_result['attachments'].append(
+                    create_attachment(key + '.txt', _read_content(path)))

=== modified file 'setup.py'
--- setup.py	2012-12-15 18:11:32 +0000
+++ setup.py	2012-12-16 22:20:53 +0000
@@ -20,6 +20,7 @@
 
     [lava.signal_handlers]
     add-duration = lava_dispatcher.signals.duration:AddDuration
+    arm-probe = lava_dispatcher.signals.armprobe:ArmProbe
     shell-hooks = lava_dispatcher.signals.shellhooks:ShellHooks
     """,
     packages=find_packages(),

