blob: 4cfc59565733655b08dd75a20cc01edc5a65f31f [file] [log] [blame]
The Android Open Source Project10e23ee2009-03-03 19:30:30 -08001/*
2 * Copyright 2008, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * Binary implementation of the original opcontrol script due to missing tools
19 * like awk, test, etc.
20 */
21
22#include <unistd.h>
23#include <getopt.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <errno.h>
27#include <fcntl.h>
28#include <signal.h>
29#include <sys/stat.h>
30
31#include "op_config.h"
32
Bruce Beare751a4432010-03-04 10:30:51 -080033#define verbose(fmt...) if (verbose_print) printf(fmt)
The Android Open Source Project10e23ee2009-03-03 19:30:30 -080034
35/* Experiments found that using a small interval may hang the device, and the
36 * more events tracked simultaneously, the longer the interval has to be.
37 */
Ben Cheng5a4eb4e2009-09-14 16:00:41 -070038
Bruce Beare751a4432010-03-04 10:30:51 -080039#if defined(__i386__) || defined(__x86_64__)
40#define MAX_EVENTS 2
41int min_count[MAX_EVENTS] = {60000, 100000};
42#elif !defined(WITH_ARM_V7_A)
Ben Cheng5a4eb4e2009-09-14 16:00:41 -070043#define MAX_EVENTS 3
Ben Cheng14345072009-09-16 11:31:39 -070044int min_count[MAX_EVENTS] = {150000, 200000, 250000};
Ben Cheng5a4eb4e2009-09-14 16:00:41 -070045#else
Ben Cheng14345072009-09-16 11:31:39 -070046#define MAX_EVENTS 5
47int min_count[MAX_EVENTS] = {150000, 200000, 250000, 300000, 350000};
Ben Cheng5a4eb4e2009-09-14 16:00:41 -070048#endif
49
Bruce Beare751a4432010-03-04 10:30:51 -080050int verbose_print;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -080051int list_events;
52int show_usage;
53int setup;
54int quick;
55int num_events;
56int start;
57int stop;
58int reset;
59
Ben Cheng5a4eb4e2009-09-14 16:00:41 -070060int selected_events[MAX_EVENTS];
61int selected_counts[MAX_EVENTS];
The Android Open Source Project10e23ee2009-03-03 19:30:30 -080062
Bruce Beare751a4432010-03-04 10:30:51 -080063char callgraph[8];
The Android Open Source Project10e23ee2009-03-03 19:30:30 -080064char kernel_range[512];
65char vmlinux[512];
66
67struct option long_options[] = {
68 {"help", 0, &show_usage, 1},
69 {"list-events", 0, &list_events, 1},
70 {"reset", 0, &reset, 1},
71 {"setup", 0, &setup, 1},
72 {"quick", 0, &quick, 1},
Bruce Beare751a4432010-03-04 10:30:51 -080073 {"callgraph", 1, 0, 'c'},
The Android Open Source Project10e23ee2009-03-03 19:30:30 -080074 {"event", 1, 0, 'e'},
75 {"vmlinux", 1, 0, 'v'},
76 {"kernel-range", 1, 0, 'r'},
77 {"start", 0, &start, 1},
78 {"stop", 0, &stop, 1},
Bruce Beare751a4432010-03-04 10:30:51 -080079 {"dump", 0, 0, 'd'},
The Android Open Source Project10e23ee2009-03-03 19:30:30 -080080 {"shutdown", 0, 0, 'h'},
81 {"status", 0, 0, 't'},
Bruce Beare751a4432010-03-04 10:30:51 -080082 {"verbose", 0, 0, 'V'},
The Android Open Source Project10e23ee2009-03-03 19:30:30 -080083 {0, 0, 0, 0},
84};
85
86struct event_info {
87 int id;
Bruce Beare751a4432010-03-04 10:30:51 -080088 int um;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -080089 const char *name;
90 const char *explanation;
91} event_info[] = {
Bruce Beare751a4432010-03-04 10:30:51 -080092#if defined(__i386__) || defined(__x86_64__)
93 /* INTEL_ARCH_PERFMON events */
94
95 /* 0x3c counters:cpuid um:zero minimum:6000 filter:0 name:CPU_CLK_UNHALTED :
96 * Clock cycles when not halted
97 */
98 {0x3c, 0, "CPU_CLK_UNHALTED",
99 "Clock cycles when not halted" },
100
101 /* event:0x3c counters:cpuid um:one minimum:6000 filter:2 name:UNHALTED_REFERENCE_CYCLES :
102 * Unhalted reference cycles
103 */
104 {0x3c, 1, "UNHALTED_REFERENCE_CYCLES",
105 "Unhalted reference cycles" },
106
107 /* event:0xc0 counters:cpuid um:zero minimum:6000 filter:1 name:INST_RETIRED :
108 * number of instructions retired
109 */
110 {0xc0, 0, "INST_RETIRED",
111 "number of instructions retired"},
112
113 /* event:0x2e counters:cpuid um:x41 minimum:6000 filter:5 name:LLC_MISSES :
114 * Last level cache demand requests from this core that missed the LLC
115 */
116 {0x2e, 0x41, "LLC_MISSES",
117 "Last level cache demand requests from this core that missed the LLC"},
118
119 /* event:0x2e counters:cpuid um:x4f minimum:6000 filter:4 name:LLC_REFS :
120 * Last level cache demand requests from this core
121 */
122 {0x2e, 0x4f, "LLC_REFS",
123 "Last level cache demand requests from this core"},
124
125 /* event:0xc4 counters:cpuid um:zero minimum:500 filter:6 name:BR_INST_RETIRED :
126 * number of branch instructions retired
127 */
128 {0xc4, 0, "BR_INST_RETIRED",
129 "number of branch instructions retired"},
130
131 /* event:0xc5 counters:cpuid um:zero minimum:500 filter:7 name:BR_MISS_PRED_RETIRED :
132 * number of mispredicted branches retired (precise)
133 */
134 {0xc5, 0, "BR_MISS_PRED_RETIRED",
135 "number of mispredicted branches retired (precise)"},
136
137#elif !defined(WITH_ARM_V7_A)
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700138 /* ARM V6 events */
Bruce Beare751a4432010-03-04 10:30:51 -0800139 {0x00, 0, "IFU_IFETCH_MISS",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800140 "number of instruction fetch misses"},
Bruce Beare751a4432010-03-04 10:30:51 -0800141 {0x01, 0, "CYCLES_IFU_MEM_STALL",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800142 "cycles instruction fetch pipe is stalled"},
Bruce Beare751a4432010-03-04 10:30:51 -0800143 {0x02, 0, "CYCLES_DATA_STALL",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800144 "cycles stall occurs for due to data dependency"},
Bruce Beare751a4432010-03-04 10:30:51 -0800145 {0x03, 0, "ITLB_MISS",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800146 "number of Instruction MicroTLB misses"},
Bruce Beare751a4432010-03-04 10:30:51 -0800147 {0x04, 0, "DTLB_MISS",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800148 "number of Data MicroTLB misses"},
Bruce Beare751a4432010-03-04 10:30:51 -0800149 {0x05, 0, "BR_INST_EXECUTED",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800150 "branch instruction executed w/ or w/o program flow change"},
Bruce Beare751a4432010-03-04 10:30:51 -0800151 {0x06, 0, "BR_INST_MISS_PRED",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800152 "branch mispredicted"},
Bruce Beare751a4432010-03-04 10:30:51 -0800153 {0x07, 0, "INSN_EXECUTED",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800154 "instructions executed"},
Bruce Beare751a4432010-03-04 10:30:51 -0800155 {0x09, 0, "DCACHE_ACCESS",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800156 "data cache access, cacheable locations"},
Bruce Beare751a4432010-03-04 10:30:51 -0800157 {0x0a, 0, "DCACHE_ACCESS_ALL",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800158 "data cache access, all locations"},
Bruce Beare751a4432010-03-04 10:30:51 -0800159 {0x0b, 0, "DCACHE_MISS",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800160 "data cache miss"},
Bruce Beare751a4432010-03-04 10:30:51 -0800161 {0x0c, 0, "DCACHE_WB",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800162 "data cache writeback, 1 event for every half cacheline"},
Bruce Beare751a4432010-03-04 10:30:51 -0800163 {0x0d, 0, "PC_CHANGE",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800164 "number of times the program counter was changed without a mode switch"},
Bruce Beare751a4432010-03-04 10:30:51 -0800165 {0x0f, 0, "TLB_MISS",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800166 "Main TLB miss"},
Bruce Beare751a4432010-03-04 10:30:51 -0800167 {0x10, 0, "EXP_EXTERNAL",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800168 "Explicit external data access"},
Bruce Beare751a4432010-03-04 10:30:51 -0800169 {0x11, 0, "LSU_STALL",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800170 "cycles stalled because Load Store request queue is full"},
Bruce Beare751a4432010-03-04 10:30:51 -0800171 {0x12, 0, "WRITE_DRAIN",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800172 "Times write buffer was drained"},
Bruce Beare751a4432010-03-04 10:30:51 -0800173 {0xff, 0, "CPU_CYCLES",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800174 "clock cycles counter"},
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700175#else
176 /* ARM V7 events */
Bruce Beare751a4432010-03-04 10:30:51 -0800177 {0x00, 0, "PMNC_SW_INCR",
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700178 "Software increment of PMNC registers"},
Bruce Beare751a4432010-03-04 10:30:51 -0800179 {0x01, 0, "IFETCH_MISS",
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700180 "Instruction fetch misses from cache or normal cacheable memory"},
Bruce Beare751a4432010-03-04 10:30:51 -0800181 {0x02, 0, "ITLB_MISS",
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700182 "Instruction fetch misses from TLB"},
Bruce Beare751a4432010-03-04 10:30:51 -0800183 {0x03, 0, "DCACHE_REFILL",
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700184 "Data R/W operation that causes a refill from cache or normal cacheable"
185 "memory"},
Bruce Beare751a4432010-03-04 10:30:51 -0800186 {0x04, 0, "DCACHE_ACCESS",
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700187 "Data R/W from cache"},
Bruce Beare751a4432010-03-04 10:30:51 -0800188 {0x05, 0, "DTLB_REFILL",
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700189 "Data R/W that causes a TLB refill"},
Bruce Beare751a4432010-03-04 10:30:51 -0800190 {0x06, 0, "DREAD",
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700191 "Data read architecturally executed (note: architecturally executed = for"
192 "instructions that are unconditional or that pass the condition code)"},
Bruce Beare751a4432010-03-04 10:30:51 -0800193 {0x07, 0, "DWRITE",
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700194 "Data write architecturally executed"},
Bruce Beare751a4432010-03-04 10:30:51 -0800195 {0x08, 0, "INSTR_EXECUTED",
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700196 "All executed instructions"},
Bruce Beare751a4432010-03-04 10:30:51 -0800197 {0x09, 0, "EXC_TAKEN",
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700198 "Exception taken"},
Bruce Beare751a4432010-03-04 10:30:51 -0800199 {0x0A, 0, "EXC_EXECUTED",
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700200 "Exception return architecturally executed"},
201 {0x0B, "CID_WRITE",
202 "Instruction that writes to the Context ID Register architecturally"
203 "executed"},
204 {0x0C, "PC_WRITE",
205 "SW change of PC, architecturally executed (not by exceptions)"},
206 {0x0D, "PC_IMM_BRANCH",
207 "Immediate branch instruction executed (taken or not)"},
208 {0x0E, "PC_PROC_RETURN",
209 "Procedure return architecturally executed (not by exceptions)"},
210 {0x0F, "UNALIGNED_ACCESS",
211 "Unaligned access architecturally executed"},
212 {0x10, "PC_BRANCH_MIS_PRED",
213 "Branch mispredicted or not predicted. Counts pipeline flushes because of"
214 "misprediction"},
215 {0x12, "PC_BRANCH_MIS_USED",
216 "Branch or change in program flow that could have been predicted"},
217 {0x40, "WRITE_BUFFER_FULL",
218 "Any write buffer full cycle"},
219 {0x41, "L2_STORE_MERGED",
220 "Any store that is merged in L2 cache"},
221 {0x42, "L2_STORE_BUFF",
222 "Any bufferable store from load/store to L2 cache"},
223 {0x43, "L2_ACCESS",
224 "Any access to L2 cache"},
225 {0x44, "L2_CACH_MISS",
226 "Any cacheable miss in L2 cache"},
227 {0x45, "AXI_READ_CYCLES",
228 "Number of cycles for an active AXI read"},
229 {0x46, "AXI_WRITE_CYCLES",
230 "Number of cycles for an active AXI write"},
231 {0x47, "MEMORY_REPLAY",
232 "Any replay event in the memory subsystem"},
233 {0x48, "UNALIGNED_ACCESS_REPLAY",
234 "Unaligned access that causes a replay"},
235 {0x49, "L1_DATA_MISS",
236 "L1 data cache miss as a result of the hashing algorithm"},
237 {0x4A, "L1_INST_MISS",
238 "L1 instruction cache miss as a result of the hashing algorithm"},
239 {0x4B, "L1_DATA_COLORING",
240 "L1 data access in which a page coloring alias occurs"},
241 {0x4C, "L1_NEON_DATA",
242 "NEON data access that hits L1 cache"},
243 {0x4D, "L1_NEON_CACH_DATA",
244 "NEON cacheable data access that hits L1 cache"},
245 {0x4E, "L2_NEON",
246 "L2 access as a result of NEON memory access"},
247 {0x4F, "L2_NEON_HIT",
248 "Any NEON hit in L2 cache"},
249 {0x50, "L1_INST",
250 "Any L1 instruction cache access, excluding CP15 cache accesses"},
251 {0x51, "PC_RETURN_MIS_PRED",
252 "Return stack misprediction at return stack pop"
253 "(incorrect target address)"},
254 {0x52, "PC_BRANCH_FAILED",
255 "Branch prediction misprediction"},
256 {0x53, "PC_BRANCH_TAKEN",
257 "Any predicted branch that is taken"},
258 {0x54, "PC_BRANCH_EXECUTED",
259 "Any taken branch that is executed"},
260 {0x55, "OP_EXECUTED",
261 "Number of operations executed"
262 "(in instruction or mutli-cycle instruction)"},
263 {0x56, "CYCLES_INST_STALL",
264 "Cycles where no instruction available"},
265 {0x57, "CYCLES_INST",
266 "Number of instructions issued in a cycle"},
267 {0x58, "CYCLES_NEON_DATA_STALL",
268 "Number of cycles the processor waits on MRC data from NEON"},
269 {0x59, "CYCLES_NEON_INST_STALL",
270 "Number of cycles the processor waits on NEON instruction queue or"
271 "NEON load queue"},
272 {0x5A, "NEON_CYCLES",
273 "Number of cycles NEON and integer processors are not idle"},
274 {0x70, "PMU0_EVENTS",
275 "Number of events from external input source PMUEXTIN[0]"},
276 {0x71, "PMU1_EVENTS",
277 "Number of events from external input source PMUEXTIN[1]"},
278 {0x72, "PMU_EVENTS",
279 "Number of events from both external input sources PMUEXTIN[0]"
280 "and PMUEXTIN[1]"},
281 {0xFF, "CPU_CYCLES",
282 "Number of CPU cycles"},
283#endif
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800284};
285
Ben Cheng14345072009-09-16 11:31:39 -0700286void usage()
287{
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800288 printf("\nopcontrol: usage:\n"
289 " --list-events list event types\n"
290 " --help this message\n"
Bruce Beare751a4432010-03-04 10:30:51 -0800291 " --verbose show extra status\n"
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800292 " --setup setup directories\n"
Bruce Beare751a4432010-03-04 10:30:51 -0800293#if defined(__i386__) || defined(__x86_64__)
294 " --quick setup and select CPU_CLK_UNHALTED:60000\n"
295#else
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800296 " --quick setup and select CPU_CYCLES:150000\n"
Bruce Beare751a4432010-03-04 10:30:51 -0800297#endif
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800298 " --status show configuration\n"
299 " --start start data collection\n"
300 " --stop stop data collection\n"
301 " --reset clears out data from current session\n"
302 " --shutdown kill the oprofile daeman\n"
Bruce Beare751a4432010-03-04 10:30:51 -0800303 " --callgraph=depth callgraph depth\n"
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800304 " --event=eventspec\n"
305 " Choose an event. May be specified multiple times.\n"
306 " eventspec is in the form of name[:count], where :\n"
307 " name: event name, see \"opcontrol --list-events\"\n"
308 " count: reset counter value\n"
309 " --vmlinux=file vmlinux kernel image\n"
310 " --kernel-range=start,end\n"
311 " kernel range vma address in hexadecimal\n"
312 );
313}
314
Ben Cheng14345072009-09-16 11:31:39 -0700315void setup_session_dir()
316{
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800317 int fd;
318
319 fd = open(OP_DATA_DIR, O_RDONLY);
320 if (fd != -1) {
321 system("rm -r "OP_DATA_DIR);
322 close(fd);
323 }
324
325 if (mkdir(OP_DATA_DIR, 755)) {
326 fprintf(stderr, "Cannot create directory \"%s\": %s\n",
327 OP_DATA_DIR, strerror(errno));
328 }
329 if (mkdir(OP_DATA_DIR"/samples", 644)) {
330 fprintf(stderr, "Cannot create directory \"%s\": %s\n",
331 OP_DATA_DIR"/samples", strerror(errno));
332 }
333}
334
Ben Cheng14345072009-09-16 11:31:39 -0700335int do_setup()
336{
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800337 char dir[1024];
338
339 setup_session_dir();
340
341 if (mkdir(OP_DRIVER_BASE, 644)) {
342 fprintf(stderr, "Cannot create directory "OP_DRIVER_BASE": %s\n",
343 strerror(errno));
344 return -1;
345 }
346 if (system("mount -t oprofilefs nodev "OP_DRIVER_BASE)) {
347 return -1;
348 }
349 return 0;
350}
351
352void do_list_events()
353{
354 unsigned int i;
355
356 printf("%-20s: %s\n", "name", "meaning");
357 printf("----------------------------------------"
358 "--------------------------------------\n");
359 for (i = 0; i < sizeof(event_info)/sizeof(struct event_info); i++) {
360 printf("%-20s: %s\n", event_info[i].name, event_info[i].explanation);
361 }
362}
363
Ben Cheng14345072009-09-16 11:31:39 -0700364int find_event_idx_from_name(const char *name)
365{
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800366 unsigned int i;
367
368 for (i = 0; i < sizeof(event_info)/sizeof(struct event_info); i++) {
369 if (!strcmp(name, event_info[i].name)) {
370 return i;
371 }
372 }
373 return -1;
374}
375
Ben Cheng14345072009-09-16 11:31:39 -0700376const char * find_event_name_from_id(int id)
377{
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800378 unsigned int i;
379
380 for (i = 0; i < sizeof(event_info)/sizeof(struct event_info); i++) {
381 if (event_info[i].id == id) {
382 return event_info[i].name;
383 }
384 }
385 return NULL;
386}
387
Ben Cheng14345072009-09-16 11:31:39 -0700388int process_event(const char *event_spec)
389{
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800390 char event_name[512];
391 char count_name[512];
392 unsigned int i;
Ben Cheng14345072009-09-16 11:31:39 -0700393 int event_idx;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800394 int count_val;
395
396 strncpy(event_name, event_spec, 512);
397 count_name[0] = 0;
398
399 /* First, check if the name is followed by ":" */
400 for (i = 0; i < strlen(event_name); i++) {
401 if (event_name[i] == 0) {
402 break;
403 }
404 if (event_name[i] == ':') {
405 strncpy(count_name, event_name+i+1, 512);
406 event_name[i] = 0;
407 break;
408 }
409 }
Ben Cheng14345072009-09-16 11:31:39 -0700410 event_idx = find_event_idx_from_name(event_name);
411 if (event_idx == -1) {
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800412 fprintf(stderr, "Unknown event name: %s\n", event_name);
413 return -1;
414 }
415
416 /* Use defualt count */
417 if (count_name[0] == 0) {
418 count_val = min_count[0];
419 } else {
420 count_val = atoi(count_name);
421 }
422
Ben Cheng14345072009-09-16 11:31:39 -0700423 selected_events[num_events] = event_idx;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800424 selected_counts[num_events++] = count_val;
Ben Cheng14345072009-09-16 11:31:39 -0700425 verbose("event_id is %d\n", event_info[event_idx].id);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800426 verbose("count_val is %d\n", count_val);
427 return 0;
428}
429
430int echo_dev(const char* str, int val, const char* file, int counter)
431{
432 char fullname[512];
433 char content[128];
434 int fd;
435
436 if (counter >= 0) {
437 snprintf(fullname, 512, OP_DRIVER_BASE"/%d/%s", counter, file);
438 }
439 else {
440 snprintf(fullname, 512, OP_DRIVER_BASE"/%s", file);
441 }
442 fd = open(fullname, O_WRONLY);
443 if (fd<0) {
444 fprintf(stderr, "Cannot open %s: %s\n", fullname, strerror(errno));
445 return fd;
446 }
447 if (str == 0) {
448 sprintf(content, "%d", val);
449 }
450 else {
451 strncpy(content, str, 128);
452 }
453 verbose("Configure %s (%s)\n", fullname, content);
454 write(fd, content, strlen(content));
455 close(fd);
456 return 0;
457}
458
459int read_num(const char* file)
460{
461 char buffer[256];
462 int fd = open(file, O_RDONLY);
463 if (fd<0) return -1;
464 int rd = read(fd, buffer, sizeof(buffer)-1);
465 buffer[rd] = 0;
466 return atoi(buffer);
467}
468
469void do_status()
470{
471 int num;
472 char fullname[512];
473 int i;
474
475 printf("Driver directory: %s\n", OP_DRIVER_BASE);
476 printf("Session directory: %s\n", OP_DATA_DIR);
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700477 for (i = 0; i < MAX_EVENTS; i++) {
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800478 sprintf(fullname, OP_DRIVER_BASE"/%d/enabled", i);
479 num = read_num(fullname);
480 if (num > 0) {
481 printf("Counter %d:\n", i);
482
483 /* event name */
484 sprintf(fullname, OP_DRIVER_BASE"/%d/event", i);
485 num = read_num(fullname);
486 printf(" name: %s\n", find_event_name_from_id(num));
487
488 /* profile interval */
489 sprintf(fullname, OP_DRIVER_BASE"/%d/count", i);
490 num = read_num(fullname);
491 printf(" count: %d\n", num);
492 }
493 else {
494 printf("Counter %d disabled\n", i);
495 }
496 }
497
498 num = read_num(OP_DATA_DIR"/lock");
499 if (num >= 0) {
500 int fd;
501 /* Still needs to check if this lock is left-over */
502 sprintf(fullname, "/proc/%d", num);
503 fd = open(fullname, O_RDONLY);
504 if (fd == -1) {
505 printf("Session directory is not clean - do \"opcontrol --setup\""
506 " before you continue\n");
507 return;
508 }
509 else {
510 close(fd);
511 printf("oprofiled pid: %d\n", num);
512 num = read_num(OP_DRIVER_BASE"/enable");
513 printf("profiler is%s running\n", num == 0 ? " not" : "");
514 num = read_num(OP_DRIVER_BASE"/stats/cpu0/sample_received");
515 printf(" %9u samples received\n", num);
516 num = read_num(OP_DRIVER_BASE"/stats/cpu0/sample_lost_overflow");
517 printf(" %9u samples lost overflow\n", num);
Bruce Beare751a4432010-03-04 10:30:51 -0800518
519#if defined(__i386__) || defined(__x86_64__)
520 /* FIXME on ARM - backtrace seems broken there */
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800521 num = read_num(OP_DRIVER_BASE"/stats/cpu0/backtrace_aborted");
522 printf(" %9u backtrace aborted\n", num);
523 num = read_num(OP_DRIVER_BASE"/backtrace_depth");
524 printf(" %9u backtrace_depth\n", num);
525#endif
526 }
527 }
528 else {
529 printf("oprofiled is not running\n");
530 }
531}
532
533void do_reset()
534{
535 int fd;
536
537 fd = open(OP_DATA_DIR"/samples/current", O_RDONLY);
538 if (fd == -1) {
539 return;
540 }
541 close(fd);
542 system("rm -r "OP_DATA_DIR"/samples/current");
543}
544
545int main(int argc, char * const argv[])
546{
547 int option_index;
548 char command[1024];
549
550 /* Initialize default strings */
551 strcpy(vmlinux, "--no-vmlinux");
552 strcpy(kernel_range, "");
553
554 while (1) {
Bruce Beare751a4432010-03-04 10:30:51 -0800555 int c = getopt_long(argc, argv, "c:e:v:r:dhVt", long_options, &option_index);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800556 if (c == -1) {
557 break;
558 }
559 switch (c) {
560 case 0:
561 break;
Bruce Beare751a4432010-03-04 10:30:51 -0800562 /* --callgraph */
563 case 'c':
564 strncpy(callgraph, optarg, sizeof(callgraph));
565 break;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800566 /* --event */
567 case 'e':
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700568 if (num_events == MAX_EVENTS) {
569 fprintf(stderr, "More than %d events specified\n",
570 MAX_EVENTS);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800571 exit(1);
572 }
573 if (process_event(optarg)) {
574 exit(1);
575 }
576 break;
577 /* --vmlinux */
578 case 'v':
579 sprintf(vmlinux, "-k %s", optarg);
580 break;
581 /* --kernel-range */
582 case 'r':
583 sprintf(kernel_range, "-r %s", optarg);
584 break;
Bruce Beare751a4432010-03-04 10:30:51 -0800585 case 'd':
586 /* --dump */ {
587 int pid = read_num(OP_DATA_DIR"/lock");
588 echo_dev("1", 0, "dump", -1);
589 if (pid >= 0) {
590 sleep(1);
591 kill(pid, SIGHUP);
592 }
593 break;
594 }
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800595 /* --shutdown */
596 case 'h': {
597 int pid = read_num(OP_DATA_DIR"/lock");
598 if (pid >= 0) {
Bruce Beare751a4432010-03-04 10:30:51 -0800599 kill(pid, SIGHUP); /* Politely ask the daemon to close files */
600 sleep(1);
601 kill(pid, SIGTERM);/* Politely ask the daemon to die */
602 sleep(1);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800603 kill(pid, SIGKILL);
604 }
605 setup_session_dir();
606 break;
607 }
Bruce Beare751a4432010-03-04 10:30:51 -0800608 /* --verbose */
609 case 'V':
610 verbose_print++;
611 break;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800612 /* --status */
613 case 't':
614 do_status();
615 break;
616 default:
617 usage();
618 exit(1);
619 }
620 }
621 verbose("list_events = %d\n", list_events);
622 verbose("setup = %d\n", setup);
623
624 if (list_events) {
625 do_list_events();
626 }
627
628 if (quick) {
Bruce Beare751a4432010-03-04 10:30:51 -0800629#if defined(__i386__) || defined(__x86_64__)
630 process_event("CPU_CLK_UNHALTED");
631#else
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800632 process_event("CPU_CYCLES");
Bruce Beare751a4432010-03-04 10:30:51 -0800633#endif
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800634 setup = 1;
635 }
636
637 if (reset) {
638 do_reset();
639 }
640
641 if (show_usage) {
642 usage();
643 }
644
645 if (setup) {
646 if (do_setup()) {
647 fprintf(stderr, "do_setup failed");
648 exit(1);
649 }
650 }
651
Bruce Beare751a4432010-03-04 10:30:51 -0800652 if (strlen(callgraph)) {
653 echo_dev(callgraph, 0, "backtrace_depth", -1);
654 }
655
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800656 if (num_events != 0) {
657 int i;
658
659 strcpy(command, "oprofiled --session-dir="OP_DATA_DIR);
660
Bruce Beare751a4432010-03-04 10:30:51 -0800661#if defined(__i386__) || defined(__x86_64__)
662 /* Nothing */
663#elif !defined(WITH_ARM_V7_A)
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800664 /* Since counter #3 can only handle CPU_CYCLES, check and shuffle the
665 * order a bit so that the maximal number of events can be profiled
666 * simultaneously
667 */
668 if (num_events == 3) {
669 for (i = 0; i < num_events; i++) {
670 int event_idx = selected_events[i];
671
672 if (event_info[event_idx].id == 0xff) {
673 break;
674 }
675 }
676
677 /* No CPU_CYCLES is found */
678 if (i == 3) {
679 fprintf(stderr, "You can only specify three events if one of "
680 "them is CPU_CYCLES\n");
681 exit(1);
682 }
683 /* Swap CPU_CYCLES to counter #2 (starting from #0)*/
684 else if (i != 2) {
685 int temp;
686
687 temp = selected_events[2];
688 selected_events[2] = selected_events[i];
689 selected_events[i] = temp;
690
691 temp = selected_counts[2];
692 selected_counts[2] = selected_counts[i];
693 selected_counts[i] = temp;
694 }
695 }
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700696#endif
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800697
698
699 /* Configure the counters and enable them */
700 for (i = 0; i < num_events; i++) {
701 int event_idx = selected_events[i];
702 int setup_result = 0;
703
704 if (i == 0) {
705 snprintf(command+strlen(command), 1024 - strlen(command),
706 " --events=");
707 }
708 else {
709 snprintf(command+strlen(command), 1024 - strlen(command),
710 ",");
711 }
712 /* Compose name:id:count:unit_mask:kernel:user, something like
713 * --events=CYCLES_DATA_STALL:2:0:200000:0:1:1,....
714 */
715 snprintf(command+strlen(command), 1024 - strlen(command),
Bruce Beare751a4432010-03-04 10:30:51 -0800716 "%s:%d:%d:%d:%d:1:1",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800717 event_info[event_idx].name,
718 event_info[event_idx].id,
719 i,
Bruce Beare751a4432010-03-04 10:30:51 -0800720 selected_counts[i],
721 event_info[event_idx].um);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800722
723 setup_result |= echo_dev("1", 0, "user", i);
724 setup_result |= echo_dev("1", 0, "kernel", i);
Bruce Beare751a4432010-03-04 10:30:51 -0800725 setup_result |= echo_dev(NULL, event_info[event_idx].um, "unit_mask", i);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800726 setup_result |= echo_dev("1", 0, "enabled", i);
727 setup_result |= echo_dev(NULL, selected_counts[i], "count", i);
728 setup_result |= echo_dev(NULL, event_info[event_idx].id,
729 "event", i);
730 if (setup_result) {
731 fprintf(stderr, "Counter configuration failed for %s\n",
732 event_info[event_idx].name);
733 fprintf(stderr, "Did you do \"opcontrol --setup\" first?\n");
734 exit(1);
735 }
736 }
737
738 /* Disable the unused counters */
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700739 for (i = num_events; i < MAX_EVENTS; i++) {
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800740 echo_dev("0", 0, "enabled", i);
741 }
742
743 snprintf(command+strlen(command), 1024 - strlen(command), " %s",
744 vmlinux);
745 if (kernel_range[0]) {
746 snprintf(command+strlen(command), 1024 - strlen(command), " %s",
747 kernel_range);
748 }
749 verbose("command: %s\n", command);
750 system(command);
751 }
752
753 if (start) {
754 echo_dev("1", 0, "enable", -1);
755 }
756
757 if (stop) {
758 echo_dev("0", 0, "enable", -1);
759 }
760}