diff options
author | Jeff Brown <jeffbrown@google.com> | 2011-02-02 13:27:17 -0800 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2011-02-04 16:58:40 -0800 |
commit | 87866d93bd7de46ffe9333437e5230c6eda58448 (patch) | |
tree | 28b6e54563f8a21e36c89a85d94e45ed281c6083 | |
parent | 7a33c86eb98056ef0570c99e713214f8dc56b6ef (diff) | |
download | oprofile-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.cpp | 128 | ||||
-rw-r--r-- | opcontrol_remote | 94 | ||||
-rwxr-xr-x | oprofile_android | 162 |
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 |