diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:35 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:35 -0800 |
commit | dfb3f050a7cebd2030ea23dc6fa8964530e4ddcc (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /opcontrol | |
parent | b9958da7adae1c7d4482e958b371401eef387a39 (diff) | |
download | oprofile-dfb3f050a7cebd2030ea23dc6fa8964530e4ddcc.tar.gz |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'opcontrol')
-rw-r--r-- | opcontrol/Android.mk | 18 | ||||
-rw-r--r-- | opcontrol/opcontrol.cpp | 542 |
2 files changed, 0 insertions, 560 deletions
diff --git a/opcontrol/Android.mk b/opcontrol/Android.mk deleted file mode 100644 index 56211ad..0000000 --- a/opcontrol/Android.mk +++ /dev/null @@ -1,18 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - opcontrol.cpp - -LOCAL_STATIC_LIBRARIES := \ - libpopt libutil libdb libabi libop - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/.. \ - $(LOCAL_PATH)/../libop - -LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) -LOCAL_MODULE_TAGS := debug -LOCAL_MODULE:= opcontrol - -include $(BUILD_EXECUTABLE) diff --git a/opcontrol/opcontrol.cpp b/opcontrol/opcontrol.cpp deleted file mode 100644 index 2d9cb2f..0000000 --- a/opcontrol/opcontrol.cpp +++ /dev/null @@ -1,542 +0,0 @@ -/* - * Copyright 2008, 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. - */ - -/* - * Binary implementation of the original opcontrol script due to missing tools - * like awk, test, etc. - */ - -#include <unistd.h> -#include <getopt.h> -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> -#include <sys/stat.h> - -#include "op_config.h" - -#if 0 -#define verbose(fmt...) printf(fmt) -#else -#define verbose(fmt...) -#endif - -/* Experiments found that using a small interval may hang the device, and the - * more events tracked simultaneously, the longer the interval has to be. - */ -int min_count[3] = {150000, 200000, 250000}; -int list_events; -int show_usage; -int setup; -int quick; -int num_events; -int start; -int stop; -int reset; - -int selected_events[3]; -int selected_counts[3]; - -char kernel_range[512]; -char vmlinux[512]; - -struct option long_options[] = { - {"help", 0, &show_usage, 1}, - {"list-events", 0, &list_events, 1}, - {"reset", 0, &reset, 1}, - {"setup", 0, &setup, 1}, - {"quick", 0, &quick, 1}, - {"event", 1, 0, 'e'}, - {"vmlinux", 1, 0, 'v'}, - {"kernel-range", 1, 0, 'r'}, - {"start", 0, &start, 1}, - {"stop", 0, &stop, 1}, - {"shutdown", 0, 0, 'h'}, - {"status", 0, 0, 't'}, - {0, 0, 0, 0}, -}; - -struct event_info { - int id; - const char *name; - const char *explanation; -} event_info[] = { - {0x00, "IFU_IFETCH_MISS", - "number of instruction fetch misses"}, - {0x01, "CYCLES_IFU_MEM_STALL", - "cycles instruction fetch pipe is stalled"}, - {0x02, "CYCLES_DATA_STALL", - "cycles stall occurs for due to data dependency"}, - {0x03, "ITLB_MISS", - "number of Instruction MicroTLB misses"}, - {0x04, "DTLB_MISS", - "number of Data MicroTLB misses"}, - {0x05, "BR_INST_EXECUTED", - "branch instruction executed w/ or w/o program flow change"}, - {0x06, "BR_INST_MISS_PRED", - "branch mispredicted"}, - {0x07, "INSN_EXECUTED", - "instructions executed"}, - {0x09, "DCACHE_ACCESS", - "data cache access, cacheable locations"}, - {0x0a, "DCACHE_ACCESS_ALL", - "data cache access, all locations"}, - {0x0b, "DCACHE_MISS", - "data cache miss"}, - {0x0c, "DCACHE_WB", - "data cache writeback, 1 event for every half cacheline"}, - {0x0d, "PC_CHANGE", - "number of times the program counter was changed without a mode switch"}, - {0x0f, "TLB_MISS", - "Main TLB miss"}, - {0x10, "EXP_EXTERNAL", - "Explicit external data access"}, - {0x11, "LSU_STALL", - "cycles stalled because Load Store request queue is full"}, - {0x12, "WRITE_DRAIN", - "Times write buffer was drained"}, - {0xff, "CPU_CYCLES", - "clock cycles counter"}, -}; - -void usage() { - printf("\nopcontrol: usage:\n" - " --list-events list event types\n" - " --help this message\n" - " --setup setup directories\n" - " --quick setup and select CPU_CYCLES:150000\n" - " --status show configuration\n" - " --start start data collection\n" - " --stop stop data collection\n" - " --reset clears out data from current session\n" - " --shutdown kill the oprofile daeman\n" - " --event=eventspec\n" - " Choose an event. May be specified multiple times.\n" - " eventspec is in the form of name[:count], where :\n" - " name: event name, see \"opcontrol --list-events\"\n" - " count: reset counter value\n" - " --vmlinux=file vmlinux kernel image\n" - " --kernel-range=start,end\n" - " kernel range vma address in hexadecimal\n" - ); -} - -void setup_session_dir() { - int fd; - - fd = open(OP_DATA_DIR, O_RDONLY); - if (fd != -1) { - system("rm -r "OP_DATA_DIR); - close(fd); - } - - if (mkdir(OP_DATA_DIR, 755)) { - fprintf(stderr, "Cannot create directory \"%s\": %s\n", - OP_DATA_DIR, strerror(errno)); - } - if (mkdir(OP_DATA_DIR"/samples", 644)) { - fprintf(stderr, "Cannot create directory \"%s\": %s\n", - OP_DATA_DIR"/samples", strerror(errno)); - } -} - -int do_setup() { - char dir[1024]; - - setup_session_dir(); - - if (mkdir(OP_DRIVER_BASE, 644)) { - 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; - } - return 0; -} - -void do_list_events() -{ - unsigned int i; - - printf("%-20s: %s\n", "name", "meaning"); - printf("----------------------------------------" - "--------------------------------------\n"); - for (i = 0; i < sizeof(event_info)/sizeof(struct event_info); i++) { - printf("%-20s: %s\n", event_info[i].name, event_info[i].explanation); - } -} - -int find_event_id_from_name(const char *name) { - unsigned int i; - - for (i = 0; i < sizeof(event_info)/sizeof(struct event_info); i++) { - if (!strcmp(name, event_info[i].name)) { - return i; - } - } - return -1; -} - -const char * find_event_name_from_id(int id) { - unsigned int i; - - for (i = 0; i < sizeof(event_info)/sizeof(struct event_info); i++) { - if (event_info[i].id == id) { - return event_info[i].name; - } - } - return NULL; -} - -int process_event(const char *event_spec) { - char event_name[512]; - char count_name[512]; - unsigned int i; - int event_id; - int count_val; - - strncpy(event_name, event_spec, 512); - count_name[0] = 0; - - /* First, check if the name is followed by ":" */ - for (i = 0; i < strlen(event_name); i++) { - if (event_name[i] == 0) { - break; - } - if (event_name[i] == ':') { - strncpy(count_name, event_name+i+1, 512); - event_name[i] = 0; - break; - } - } - event_id = find_event_id_from_name(event_name); - if (event_id == -1) { - fprintf(stderr, "Unknown event name: %s\n", event_name); - return -1; - } - - /* Use defualt count */ - if (count_name[0] == 0) { - count_val = min_count[0]; - } else { - count_val = atoi(count_name); - } - - selected_events[num_events] = event_id; - selected_counts[num_events++] = count_val; - verbose("event_id is %d\n", event_id); - verbose("count_val is %d\n", count_val); - return 0; -} - -int echo_dev(const char* str, int val, const char* file, int counter) -{ - char fullname[512]; - char content[128]; - int fd; - - if (counter >= 0) { - snprintf(fullname, 512, OP_DRIVER_BASE"/%d/%s", counter, file); - } - else { - snprintf(fullname, 512, OP_DRIVER_BASE"/%s", file); - } - fd = open(fullname, O_WRONLY); - if (fd<0) { - fprintf(stderr, "Cannot open %s: %s\n", fullname, strerror(errno)); - return fd; - } - if (str == 0) { - sprintf(content, "%d", val); - } - else { - strncpy(content, str, 128); - } - verbose("Configure %s (%s)\n", fullname, content); - write(fd, content, strlen(content)); - close(fd); - return 0; -} - -int read_num(const char* file) -{ - char buffer[256]; - int fd = open(file, O_RDONLY); - if (fd<0) return -1; - int rd = read(fd, buffer, sizeof(buffer)-1); - buffer[rd] = 0; - return atoi(buffer); -} - -void do_status() -{ - int num; - char fullname[512]; - int i; - - printf("Driver directory: %s\n", OP_DRIVER_BASE); - printf("Session directory: %s\n", OP_DATA_DIR); - for (i = 0; i < 3; i++) { - sprintf(fullname, OP_DRIVER_BASE"/%d/enabled", i); - num = read_num(fullname); - if (num > 0) { - printf("Counter %d:\n", i); - - /* event name */ - sprintf(fullname, OP_DRIVER_BASE"/%d/event", i); - num = read_num(fullname); - printf(" name: %s\n", find_event_name_from_id(num)); - - /* profile interval */ - sprintf(fullname, OP_DRIVER_BASE"/%d/count", i); - num = read_num(fullname); - printf(" count: %d\n", num); - } - else { - printf("Counter %d disabled\n", i); - } - } - - num = read_num(OP_DATA_DIR"/lock"); - if (num >= 0) { - int fd; - /* Still needs to check if this lock is left-over */ - sprintf(fullname, "/proc/%d", num); - fd = open(fullname, O_RDONLY); - if (fd == -1) { - printf("Session directory is not clean - do \"opcontrol --setup\"" - " before you continue\n"); - return; - } - 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); -#if 0 - /* FIXME - backtrace seems broken */ - 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 - } - } - else { - printf("oprofiled is not running\n"); - } -} - -void do_reset() -{ - int fd; - - fd = open(OP_DATA_DIR"/samples/current", O_RDONLY); - if (fd == -1) { - return; - } - close(fd); - system("rm -r "OP_DATA_DIR"/samples/current"); -} - -int main(int argc, char * const argv[]) -{ - int option_index; - char command[1024]; - - /* Initialize default strings */ - strcpy(vmlinux, "--no-vmlinux"); - strcpy(kernel_range, ""); - - while (1) { - int c = getopt_long(argc, argv, "", long_options, &option_index); - if (c == -1) { - break; - } - switch (c) { - case 0: - break; - /* --event */ - case 'e': - if (num_events == 3) { - fprintf(stderr, "More than 3 events specified\n"); - exit(1); - } - if (process_event(optarg)) { - exit(1); - } - break; - /* --vmlinux */ - case 'v': - sprintf(vmlinux, "-k %s", optarg); - break; - /* --kernel-range */ - case 'r': - sprintf(kernel_range, "-r %s", optarg); - break; - /* --shutdown */ - case 'h': { - int pid = read_num(OP_DATA_DIR"/lock"); - if (pid >= 0) { - kill(pid, SIGKILL); - } - setup_session_dir(); - break; - } - /* --status */ - case 't': - do_status(); - break; - default: - usage(); - exit(1); - } - } - verbose("list_events = %d\n", list_events); - verbose("setup = %d\n", setup); - - if (list_events) { - do_list_events(); - } - - if (quick) { - process_event("CPU_CYCLES"); - setup = 1; - } - - if (reset) { - do_reset(); - } - - if (show_usage) { - usage(); - } - - if (setup) { - if (do_setup()) { - fprintf(stderr, "do_setup failed"); - exit(1); - } - } - - if (num_events != 0) { - int i; - - strcpy(command, "oprofiled --session-dir="OP_DATA_DIR); - - /* Since counter #3 can only handle CPU_CYCLES, check and shuffle the - * order a bit so that the maximal number of events can be profiled - * simultaneously - */ - if (num_events == 3) { - for (i = 0; i < num_events; i++) { - int event_idx = selected_events[i]; - - if (event_info[event_idx].id == 0xff) { - break; - } - } - - /* No CPU_CYCLES is found */ - if (i == 3) { - fprintf(stderr, "You can only specify three events if one of " - "them is CPU_CYCLES\n"); - exit(1); - } - /* Swap CPU_CYCLES to counter #2 (starting from #0)*/ - else if (i != 2) { - int temp; - - temp = selected_events[2]; - selected_events[2] = selected_events[i]; - selected_events[i] = temp; - - temp = selected_counts[2]; - selected_counts[2] = selected_counts[i]; - selected_counts[i] = temp; - } - } - - - /* 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), - ","); - } - /* 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), - "%s:%d:%d:%d:0:1:1", - event_info[event_idx].name, - event_info[event_idx].id, - i, - selected_counts[i]); - - setup_result |= echo_dev("1", 0, "user", i); - setup_result |= echo_dev("1", 0, "kernel", i); - setup_result |= echo_dev("0", 0, "unit_mask", i); - setup_result |= echo_dev("1", 0, "enabled", i); - setup_result |= echo_dev(NULL, selected_counts[i], "count", i); - setup_result |= echo_dev(NULL, event_info[event_idx].id, - "event", i); - if (setup_result) { - fprintf(stderr, "Counter configuration failed for %s\n", - event_info[event_idx].name); - fprintf(stderr, "Did you do \"opcontrol --setup\" first?\n"); - exit(1); - } - } - - /* Disable the unused counters */ - for (i = num_events; i < 3; i++) { - echo_dev("0", 0, "enabled", i); - } - - snprintf(command+strlen(command), 1024 - strlen(command), " %s", - vmlinux); - if (kernel_range[0]) { - snprintf(command+strlen(command), 1024 - strlen(command), " %s", - kernel_range); - } - verbose("command: %s\n", command); - system(command); - } - - if (start) { - echo_dev("1", 0, "enable", -1); - } - - if (stop) { - echo_dev("0", 0, "enable", -1); - } -} |