aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2011-02-02 13:27:17 -0800
committerJeff Brown <jeffbrown@google.com>2011-02-04 16:58:40 -0800
commit87866d93bd7de46ffe9333437e5230c6eda58448 (patch)
tree28b6e54563f8a21e36c89a85d94e45ed281c6083
parent7a33c86eb98056ef0570c99e713214f8dc56b6ef (diff)
downloadoprofile-87866d93bd7de46ffe9333437e5230c6eda58448.tar.gz
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
-rw-r--r--opcontrol/opcontrol.cpp128
-rw-r--r--opcontrol_remote94
-rwxr-xr-xoprofile_android162
3 files changed, 351 insertions, 33 deletions
diff --git a/opcontrol/opcontrol.cpp b/opcontrol/opcontrol.cpp
index 3eb0d28..075ade6 100644
--- a/opcontrol/opcontrol.cpp
+++ b/opcontrol/opcontrol.cpp
@@ -27,7 +27,10 @@
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
+#include <dirent.h>
#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
#include "op_config.h"
@@ -83,6 +86,7 @@ struct option long_options[] = {
{"shutdown", 0, 0, 'h'},
{"status", 0, 0, 't'},
{"verbose", 0, 0, 'V'},
+ {"verbose-log", 1, 0, 'l'},
{0, 0, 0, 0},
};
@@ -292,6 +296,8 @@ void usage()
" --list-events list event types\n"
" --help this message\n"
" --verbose show extra status\n"
+ " --verbose-log=lvl set daemon logging verbosity during setup\n"
+ " levels are: all,sfile,arcs,samples,module,misc\n"
" --setup setup directories\n"
#if defined(__i386__) || defined(__x86_64__)
" --quick setup and select CPU_CLK_UNHALTED:60000\n"
@@ -343,12 +349,17 @@ int do_setup()
setup_session_dir();
if (mkdir(OP_DRIVER_BASE, 0755)) {
- fprintf(stderr, "Cannot create directory "OP_DRIVER_BASE": %s\n",
- strerror(errno));
- return -1;
+ if (errno != EEXIST) {
+ fprintf(stderr, "Cannot create directory "OP_DRIVER_BASE": %s\n",
+ strerror(errno));
+ return -1;
+ }
}
- if (system("mount -t oprofilefs nodev "OP_DRIVER_BASE)) {
- return -1;
+
+ if (access(OP_DRIVER_BASE"/stats", F_OK)) {
+ if (system("mount -t oprofilefs nodev "OP_DRIVER_BASE)) {
+ return -1;
+ }
}
return 0;
}
@@ -417,7 +428,7 @@ int process_event(const char *event_spec)
return -1;
}
- /* Use defualt count */
+ /* Use default count */
if (count_name[0] == 0) {
count_val = min_count[0];
} else {
@@ -512,18 +523,46 @@ void do_status()
}
else {
close(fd);
+
printf("oprofiled pid: %d\n", num);
num = read_num(OP_DRIVER_BASE"/enable");
+
printf("profiler is%s running\n", num == 0 ? " not" : "");
- num = read_num(OP_DRIVER_BASE"/stats/cpu0/sample_received");
- printf(" %9u samples received\n", num);
- num = read_num(OP_DRIVER_BASE"/stats/cpu0/sample_lost_overflow");
- printf(" %9u samples lost overflow\n", num);
+
+ DIR* dir = opendir(OP_DRIVER_BASE"/stats");
+ if (dir) {
+ for (struct dirent* dirent; !!(dirent = readdir(dir));) {
+ if (strlen(dirent->d_name) >= 4 && memcmp(dirent->d_name, "cpu", 3) == 0) {
+ char cpupath[256];
+ strcpy(cpupath, OP_DRIVER_BASE"/stats/");
+ strcat(cpupath, dirent->d_name);
+
+ strcpy(fullname, cpupath);
+ strcat(fullname, "/sample_received");
+ num = read_num(fullname);
+ printf(" %s %9u samples received\n", dirent->d_name, num);
+
+ strcpy(fullname, cpupath);
+ strcat(fullname, "/sample_lost_overflow");
+ num = read_num(fullname);
+ printf(" %s %9u samples lost overflow\n", dirent->d_name, num);
+
+ strcpy(fullname, cpupath);
+ strcat(fullname, "/sample_invalid_eip");
+ num = read_num(fullname);
+ printf(" %s %9u samples invalid eip\n", dirent->d_name, num);
+
+ strcpy(fullname, cpupath);
+ strcat(fullname, "/backtrace_aborted");
+ num = read_num(fullname);
+ printf(" %s %9u backtrace aborted\n", dirent->d_name, num);
+ }
+ }
+ closedir(dir);
+ }
#if defined(__i386__) || defined(__x86_64__)
/* FIXME on ARM - backtrace seems broken there */
- num = read_num(OP_DRIVER_BASE"/stats/cpu0/backtrace_aborted");
- printf(" %9u backtrace aborted\n", num);
num = read_num(OP_DRIVER_BASE"/backtrace_depth");
printf(" %9u backtrace_depth\n", num);
#endif
@@ -549,14 +588,15 @@ void do_reset()
int main(int argc, char * const argv[])
{
int option_index;
- char command[1024];
+ bool show_status = false;
+ char* verbose_log = NULL;
/* Initialize default strings */
strcpy(vmlinux, "--no-vmlinux");
strcpy(kernel_range, "");
while (1) {
- int c = getopt_long(argc, argv, "c:e:v:r:dhVt", long_options, &option_index);
+ int c = getopt_long(argc, argv, "c:e:v:r:dhVtl:", long_options, &option_index);
if (c == -1) {
break;
}
@@ -565,7 +605,7 @@ int main(int argc, char * const argv[])
break;
/* --callgraph */
case 'c':
- strncpy(callgraph, optarg, sizeof(callgraph));
+ strncpy(callgraph, optarg, sizeof(callgraph));
break;
/* --event */
case 'e':
@@ -605,7 +645,7 @@ int main(int argc, char * const argv[])
kill(pid, SIGTERM);/* Politely ask the daemon to die */
sleep(1);
kill(pid, SIGKILL);
- }
+ }
setup_session_dir();
break;
}
@@ -613,9 +653,13 @@ int main(int argc, char * const argv[])
case 'V':
verbose_print++;
break;
+ /* --verbose-log */
+ case 'l':
+ verbose_log = strdup(optarg);
+ break;
/* --status */
case 't':
- do_status();
+ show_status = true;
break;
default:
usage();
@@ -662,9 +706,12 @@ int main(int argc, char * const argv[])
}
if (num_events != 0 || timer != 0) {
+ char command[1024];
int i;
- strcpy(command, "oprofiled --session-dir="OP_DATA_DIR);
+ strcpy(command, argv[0]);
+ char* slash = strrchr(command, '/');
+ strcpy(slash ? slash + 1 : command, "oprofiled --session-dir="OP_DATA_DIR);
#if defined(__i386__) || defined(__x86_64__)
/* Nothing */
@@ -703,24 +750,21 @@ int main(int argc, char * const argv[])
}
#endif
-
/* Configure the counters and enable them */
for (i = 0; i < num_events; i++) {
int event_idx = selected_events[i];
int setup_result = 0;
if (i == 0) {
- snprintf(command+strlen(command), 1024 - strlen(command),
- " --events=");
- }
- else {
- snprintf(command+strlen(command), 1024 - strlen(command),
- ",");
+ snprintf(command + strlen(command), sizeof(command) - strlen(command),
+ " --events=");
+ } else {
+ snprintf(command + strlen(command), sizeof(command) - strlen(command), ",");
}
/* Compose name:id:count:unit_mask:kernel:user, something like
* --events=CYCLES_DATA_STALL:2:0:200000:0:1:1,....
*/
- snprintf(command+strlen(command), 1024 - strlen(command),
+ snprintf(command + strlen(command), sizeof(command) - strlen(command),
"%s:%d:%d:%d:%d:1:1",
event_info[event_idx].name,
event_info[event_idx].id,
@@ -750,18 +794,32 @@ int main(int argc, char * const argv[])
}
} else {
/* Timer mode uses empty event list */
- snprintf(command+strlen(command), 1024 - strlen(command),
- " --events=");
+ snprintf(command + strlen(command), sizeof(command) - strlen(command),
+ " --events=");
}
- snprintf(command+strlen(command), 1024 - strlen(command), " %s",
- vmlinux);
+ snprintf(command + strlen(command), sizeof(command) - strlen(command),
+ " %s", vmlinux);
if (kernel_range[0]) {
- snprintf(command+strlen(command), 1024 - strlen(command), " %s",
- kernel_range);
+ snprintf(command + strlen(command), sizeof(command) - strlen(command),
+ " %s", kernel_range);
}
+
+ if (verbose_log) {
+ snprintf(command + strlen(command), sizeof(command) - strlen(command),
+ " --verbose=%s", verbose_log);
+ }
+
+ printf("Starting oprofiled...\n");
verbose("command: %s\n", command);
- system(command);
+
+ int rc = system(command);
+ if (rc) {
+ fprintf(stderr, "Failed, oprofile returned exit code: %d\n", rc);
+ } else {
+ sleep(2);
+ printf("Ready\n");
+ }
}
if (start) {
@@ -772,4 +830,8 @@ int main(int argc, char * const argv[])
echo_dev("1", 0, "dump", -1);
echo_dev("0", 0, "enable", -1);
}
+
+ if (show_status) {
+ do_status();
+ }
}
diff --git a/opcontrol_remote b/opcontrol_remote
new file mode 100644
index 0000000..b095e77
--- /dev/null
+++ b/opcontrol_remote
@@ -0,0 +1,94 @@
+#!/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 getopt
+
+class Adb:
+ def __init__(self, serial_number):
+ self._default_args = ''
+ if serial_number != None:
+ self._default_args = '-s ' + serial_number
+
+ def shell(self, command):
+ result = os.system('adb%s shell %s' % (self._default_args, command)
+ return result
+
+def usage():
+ print "Usage:" + sys.argv[0]
+ print " -h, --help : show this help text"
+ print " -s, --serial=number : the serial number of the device being profiled"
+ print " --setup : setup profiler"
+ print " --start : start profiling"
+ print " --stop : stop profiling"
+ print
+
+def main():
+ try:
+ opts, args - getopt.getopt(sys.argv[1:], "hs:", ["help", "serial=", "setup", "start", "stop"])
+ except getopt.GetoptError, e:
+ usage()
+ print str(e)
+ sys.exit(1)
+
+ serial_number = None
+ command = None
+ for o, a in opts:
+ if o in ('-h', '--help'):
+ usage()
+ sys.exit()
+ elif o in ('-s', '--serial'):
+ serial_number = a
+ elif o in ('--setup'):
+ command = 'setup'
+ elif o in ('--start'):
+ command = 'start'
+ elif o in ('--stop'):
+ command = 'stop'
+ else:
+ assert False, 'unhandled option' + o
+
+ adb = Adb(serial_number)
+
+ if command == 'setup':
+ setup(adb)
+ elif command == 'start':
+ start(adb)
+ elif command == 'stop':
+ stop(adb)
+ else:
+ usage()
+ print 'A command must be specified.'
+ sys.exit(1)
+
+def setup(adb):
+ adb.shell
+
+ pass
+
+def start(adb):
+ pass
+
+def stop(adb):
+ pass
+
+main()
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