Improve oprofile wrapper commands.

Added a new wrapper script that will help automate more of the process
of setting up and running oprofile on a remote device.  There is
more work to be done here once the kernel perf event issues that hinder
reliability (bug: 2975913) are resolved.

Change-Id: I942ee74912f1e4c87b4c43aca9937b3f3f1780f6
diff --git a/oprofile_android b/oprofile_android
new file mode 100755
index 0000000..afefe71
--- /dev/null
+++ b/oprofile_android
@@ -0,0 +1,162 @@
+#!/usr/bin/env python2.6
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Remotely controls an OProfile session on an Android device.
+#
+
+import os
+import sys
+import subprocess
+import getopt
+import re
+
+
+class Adb:
+  def __init__(self, serial_number):
+    self._base_args = ['adb']
+    if serial_number != None:
+      self._base_args.append('-s')
+      self._base_args.append(serial_number)
+
+  def shell(self, command_args, echo=True):
+    print 'adb: %s' % (' '.join(command_args))
+    popen = subprocess.Popen(self._base_args + ['shell'] + command_args,
+      stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    output = ''
+    while True:
+      stdout, stderr = popen.communicate()
+      if echo:
+        print stdout
+        print stderr
+      output += stdout
+      output += stderr
+      rc = popen.poll()
+      if rc is not None:
+        break
+    print 'exit code: %d' % rc
+    return rc, output
+
+
+class Tool:
+  def __init__(self, argv):
+    self.argv = argv
+    self.verbose = False
+
+  def usage(self):
+    print "Usage:" + self.argv[0]
+    print "    -h, --help          : show this help text"
+    print "    -s, --serial=number : the serial number of the device being profiled"
+    print "    -v, --verbose       : show verbose output"
+    print "    --setup             : setup profiler"
+    print "    --shutdown          : shutdown profiler"
+    print "    --start             : start profiling"
+    print "    --stop              : stop profiling"
+    print "    --status            : show profiler status"
+    print
+
+  def main(self):
+    try:
+      opts, args = getopt.getopt(self.argv[1:],
+        "hs:v",
+        ["help", "serial=", "setup", "start", "stop", "status", "shutdown", "verbose"])
+    except getopt.GetoptError, e:
+      self.usage()
+      print str(e)
+      return 1
+
+    serial_number = None
+    command = None
+    for o, a in opts:
+      if o in ('-h', '--help'):
+        self.usage()
+        return 0
+      elif o in ('-s', '--serial'):
+        serial_number = a
+      elif o in ('-v', '--verbose'):
+        self.verbose = True
+      elif o in ('--setup', '--start', '--stop', '--status', '--shutdown'):
+        command = o[2:]
+      else:
+        assert False, 'unhandled option' + o
+
+    self.adb = Adb(serial_number)
+
+    if command == 'setup':
+      rc = self.setup()
+    elif command == 'shutdown':
+      rc = self.shutdown()
+    elif command == 'start':
+      rc = self.start()
+    elif command == 'stop':
+      rc = self.stop()
+    elif command == 'status':
+      rc = self.status()
+    else:
+      self.usage()
+      print 'A command must be specified.'
+      rc = 1
+    return rc
+
+  def setup(self):
+    rc, output = self.adb.shell(['cat', '/proc/kallsyms'], echo=False)
+    if rc != 0:
+      print 'Failed to determine kernel VMA range.'
+      return rc
+    vma_start = re.search('([0-9a-fA-F]{8}) T _text', output).group(1)
+    vma_end = re.search('([0-9a-fA-F]{8}) A _etext', output).group(1)
+
+    rc, output = self.adb.shell(['/system/xbin/opcontrol'] + self.opcontrol_verbose() + [
+      '--reset',
+      '--kernel-range=' + vma_start + '-' + vma_end,
+      '--event=CPU_CYCLES:100000',
+      '--setup',
+      '--status', '--verbose-log=all'])
+
+  def shutdown(self):
+    rc, output = self.adb.shell(['/system/xbin/opcontrol'] + self.opcontrol_verbose() + [
+      '--shutdown'])
+    if rc != 0:
+      print 'Failed to shutdown.'
+      return rc
+    return rc
+
+  def start(self):
+    rc, output = self.adb.shell(['/system/xbin/opcontrol'] + self.opcontrol_verbose() + [
+      '--start', '--status'])
+    return rc
+
+  def stop(self):
+    rc, output = self.adb.shell(['/system/xbin/opcontrol'] + self.opcontrol_verbose() + [
+      '--stop', '--status'])
+    return rc
+
+  def status(self):
+    rc, output = self.adb.shell(['/system/xbin/opcontrol'] + self.opcontrol_verbose() + [
+      '--status'])
+    return rc
+
+  def opcontrol_verbose(self):
+    if self.verbose:
+      return ['--verbose']
+    else:
+      return []
+
+# Main entry point
+tool = Tool(sys.argv)
+rc = tool.main()
+sys.exit(rc)
\ No newline at end of file