1 /*
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 <string.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <signal.h>
30 #include <dirent.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34
35 #include "op_config.h"
36
37 #define verbose(fmt...) if (verbose_print) printf(fmt)
38
39 struct event_info {
40 int id;
41 int counters;
42 int um;
43 const char *name;
44 const char *explanation;
45 };
46
47 #define CTR(n) (1<<(n))
48
49 #if defined(__i386__) || defined(__x86_64__)
50 struct event_info event_info_arch_perfmon[] = {
51 #include "../events/i386/arch_perfmon/events.h"
52 };
53
54 #define MAX_EVENTS 2
55 int min_count[MAX_EVENTS] = {60000, 100000};
56
57 const char *default_event = "CPU_CLK_UNHALTED";
58 #endif
59
60 #if defined(__arm__)
61 #if !defined(WITH_ARM_V7_A)
62 struct event_info event_info_armv6[] = {
63 #include "../events/arm/armv6/events.h"
64 };
65
66 #define MAX_EVENTS 3
67 int min_count[MAX_EVENTS] = {150000, 200000, 250000};
68
69 #else
70 struct event_info event_info_armv7[] = {
71 #include "../events/arm/armv7/events.h"
72 };
73
74 #define MAX_EVENTS 5
75 int min_count[MAX_EVENTS] = {150000, 20000, 25000, 30000, 35000};
76 #endif
77
78 const char *default_event = "CPU_CYCLES";
79 #endif
80
81 #if defined(__mips__)
82 struct event_info event_info_24K[] = {
83 #include "../events/mips/24K/events.h"
84 };
85 struct event_info event_info_34K[] = {
86 #include "../events/mips/34K/events.h"
87 };
88 struct event_info event_info_74K[] = {
89 #include "../events/mips/74K/events.h"
90 };
91 struct event_info event_info_1004K[] = {
92 #include "../events/mips/1004K/events.h"
93 };
94
95 #define MAX_EVENTS 4
96 int min_count[MAX_EVENTS] = {150000, 20000, 25000, 30000};
97
98 const char *default_event = "CYCLES";
99 #endif /* defined(__mips__) */
100
101 #define ARRAYSZ(x) (sizeof(x)/sizeof((x)[0]))
102
103 struct cpuevents {
104 const char *cpu;
105 struct event_info *event_info;
106 unsigned int nevents;
107 } cpuevents[] = {
108 #if defined(__i386__) || defined(__x86_64__)
109 {"i386/arch_perfmon", event_info_arch_perfmon, ARRAYSZ(event_info_arch_perfmon)},
110 #endif /* defined(__i386__) || defined(__x86_64__) */
111 #if defined(__arm__)
112 #if !defined(WITH_ARM_V7_A)
113 {"arm/armv6", event_info_armv6, ARRAYSZ(event_info_armv6)},
114 #else
115 {"arm/armv7", event_info_armv7, ARRAYSZ(event_info_armv7)},
116 #endif
117 #endif /* defined(__arm__) */
118 #if defined(__mips__)
119 {"mips/24K", event_info_24K, ARRAYSZ(event_info_24K)},
120 {"mips/34K", event_info_34K, ARRAYSZ(event_info_34K)},
121 {"mips/74K", event_info_74K, ARRAYSZ(event_info_74K)},
122 {"mips/1004K", event_info_1004K, ARRAYSZ(event_info_1004K)},
123 #endif /* defined(__mips__) */
124 };
125
126 struct cpuevents *cpuevent;
127 #define event_info cpuevent->event_info
128 #define NEVENTS cpuevent->nevents
129
130 int verbose_print;
131 int list_events;
132 int show_usage;
133 int setup;
134 int quick;
135 int timer;
136 int num_events;
137 int start;
138 int stop;
139 int reset;
140
141 int selected_events[MAX_EVENTS];
142 int selected_counts[MAX_EVENTS];
143 int max_events;
144
145 char callgraph[8];
146 char kernel_range[512];
147 char vmlinux[512];
148
149 struct option long_options[] = {
150 {"help", 0, &show_usage, 1},
151 {"list-events", 0, &list_events, 1},
152 {"reset", 0, &reset, 1},
153 {"setup", 0, &setup, 1},
154 {"quick", 0, &quick, 1},
155 {"timer", 0, &timer, 1},
156 {"callgraph", 1, 0, 'c'},
157 {"event", 1, 0, 'e'},
158 {"vmlinux", 1, 0, 'v'},
159 {"kernel-range", 1, 0, 'r'},
160 {"start", 0, &start, 1},
161 {"stop", 0, &stop, 1},
162 {"dump", 0, 0, 'd'},
163 {"shutdown", 0, 0, 'h'},
164 {"status", 0, 0, 't'},
165 {"verbose", 0, 0, 'V'},
166 {"verbose-log", 1, 0, 'l'},
167 {0, 0, 0, 0},
168 };
169
170
usage()171 void usage()
172 {
173 printf("\nopcontrol: usage:\n"
174 " --list-events list event types\n"
175 " --help this message\n"
176 " --verbose show extra status\n"
177 " --verbose-log=lvl set daemon logging verbosity during setup\n"
178 " levels are: all,sfile,arcs,samples,module,misc\n"
179 " --setup setup directories\n"
180 #if defined(__i386__) || defined(__x86_64__)
181 " --quick setup and select CPU_CLK_UNHALTED:60000\n"
182 #elif defined(__arm__)
183 " --quick setup and select CPU_CYCLES:150000\n"
184 #elif defined(__mips__)
185 " --quick setup and select CYCLES:150000\n"
186 #endif
187 " --timer timer-based profiling\n"
188 " --status show configuration\n"
189 " --start start data collection\n"
190 " --stop stop data collection\n"
191 " --reset clears out data from current session\n"
192 " --shutdown kill the oprofile daemon\n"
193 " --callgraph=depth callgraph depth\n"
194 " --event=eventspec\n"
195 " Choose an event. May be specified multiple times.\n"
196 " eventspec is in the form of name[:count], where :\n"
197 " name: event name, see \"opcontrol --list-events\"\n"
198 " count: reset counter value\n"
199 " --vmlinux=file vmlinux kernel image\n"
200 " --kernel-range=start,end\n"
201 " kernel range vma address in hexadecimal\n"
202 );
203 }
204
setup_device(void)205 int setup_device(void)
206 {
207 if (mkdir(OP_DRIVER_BASE, 0755)) {
208 if (errno != EEXIST) {
209 fprintf(stderr, "Cannot create directory "OP_DRIVER_BASE": %s\n",
210 strerror(errno));
211 return -1;
212 }
213 }
214
215 if (access(OP_DRIVER_BASE"/stats", F_OK)) {
216 if (system("mount -t oprofilefs nodev "OP_DRIVER_BASE)) {
217 return -1;
218 }
219 }
220
221 /* Selecting the event information by cpu_type has only been tested on MIPS */
222 #if defined(__mips__)
223 /* Use cpu_type to select the events */
224 int fd = open(OP_DRIVER_BASE "/cpu_type", O_RDONLY);
225 if (fd < 0) {
226 fprintf(stderr, OP_DRIVER_BASE "/cpu_type: %s\n",
227 strerror(errno));
228 return -1;
229 }
230
231 char buf[512];
232 int n = read(fd, buf, sizeof(buf)-1);
233 close(fd);
234 if (n < 0) {
235 fprintf(stderr, OP_DRIVER_BASE "/cpu_type: %s\n",
236 strerror(errno));
237 return -1;
238 }
239 buf[n] = '\0';
240 for (unsigned int i = 0; i < ARRAYSZ(cpuevents); i++) {
241 if (strcmp(buf, cpuevents[i].cpu) == 0) {
242 cpuevent = &cpuevents[i];
243 }
244 }
245 if (cpuevent == NULL) {
246 fprintf(stderr, "Unrecognised CPU type %s\n", buf);
247 return -1;
248 }
249 for (max_events = 0; max_events < MAX_EVENTS; max_events++) {
250 snprintf(buf, sizeof(buf), OP_DRIVER_BASE"/%d", max_events);
251 if (access(buf, F_OK) < 0)
252 break;
253 }
254 #else
255 max_events = MAX_EVENTS;
256 cpuevent = &cpuevents[0];
257 #endif
258 return 0;
259 }
260
setup_session_dir()261 void setup_session_dir()
262 {
263 if (access(OP_DATA_DIR, F_OK) == 0)
264 system("rm -r "OP_DATA_DIR);
265
266 if (mkdir(OP_DATA_DIR, 0755)) {
267 fprintf(stderr, "Cannot create directory \"%s\": %s\n",
268 OP_DATA_DIR, strerror(errno));
269 }
270 if (mkdir(OP_DATA_DIR"/samples", 0755)) {
271 fprintf(stderr, "Cannot create directory \"%s\": %s\n",
272 OP_DATA_DIR"/samples", strerror(errno));
273 }
274 }
275
read_num(const char * file)276 int read_num(const char* file)
277 {
278 char buffer[256];
279 int fd = open(file, O_RDONLY);
280 if (fd<0) return -1;
281 int rd = read(fd, buffer, sizeof(buffer)-1);
282 buffer[rd] = 0;
283 close(fd);
284 return atoi(buffer);
285 }
286
do_setup()287 int do_setup()
288 {
289 char dir[1024];
290
291 /*
292 * Kill the old daemon so that setup can be done more than once to achieve
293 * the same effect as reset.
294 */
295 int num = read_num(OP_DATA_DIR"/lock");
296 if (num >= 0) {
297 printf("Terminating the old daemon...\n");
298 kill(num, SIGTERM);
299 sleep(5);
300 }
301
302 setup_session_dir();
303
304 return 0;
305 }
306
stringify_counters(char * ctr_string,int ctr_mask)307 void stringify_counters(char *ctr_string, int ctr_mask)
308 {
309 int i, n, len;
310 char *p = ctr_string;
311
312 *p = '\0';
313 for (i=0; i<32; ++i) {
314 if (ctr_mask & (1<<i)) {
315 p += sprintf(p, "%d,", i);
316 }
317 }
318 if (p != ctr_string) {
319 *(p-1) = '\0'; /* erase the final comma */
320 }
321 }
322
do_list_events()323 void do_list_events()
324 {
325 unsigned int i;
326 char ctrs[32*3+1];
327
328 printf("%-12s | %-30s: %s\n", "counter", "name", "meaning");
329 printf("----------------------------------------"
330 "--------------------------------------\n");
331 for (i = 0; i < NEVENTS; i++) {
332 stringify_counters(ctrs, event_info[i].counters);
333 printf("%-12s | %-30s: %s\n", ctrs, event_info[i].name, event_info[i].explanation);
334 }
335 }
336
find_event_idx_from_name(const char * name)337 int find_event_idx_from_name(const char *name)
338 {
339 unsigned int i;
340
341 for (i = 0; i < NEVENTS; i++) {
342 if (!strcmp(name, event_info[i].name)) {
343 return i;
344 }
345 }
346 return -1;
347 }
348
find_event_name_from_id(int id,int mask)349 const char * find_event_name_from_id(int id, int mask)
350 {
351 unsigned int i;
352
353 for (i = 0; i < NEVENTS; i++) {
354 if (event_info[i].id == id && (event_info[i].counters == 0 || (event_info[i].counters & mask))) {
355 return event_info[i].name;
356 }
357 }
358 return "Undefined Event";
359 }
360
process_event(const char * event_spec)361 int process_event(const char *event_spec)
362 {
363 char event_name[512];
364 char count_name[512];
365 unsigned int i;
366 int event_idx;
367 int count_val;
368
369 strncpy(event_name, event_spec, 512);
370 count_name[0] = 0;
371
372 /* First, check if the name is followed by ":" */
373 for (i = 0; i < strlen(event_name); i++) {
374 if (event_name[i] == 0) {
375 break;
376 }
377 if (event_name[i] == ':') {
378 strncpy(count_name, event_name+i+1, 512);
379 event_name[i] = 0;
380 break;
381 }
382 }
383 event_idx = find_event_idx_from_name(event_name);
384 if (event_idx == -1) {
385 fprintf(stderr, "Unknown event name: %s\n", event_name);
386 return -1;
387 }
388
389 /*
390 * check that the named event is valid for this event counter
391 * 'num_events' represents the cpu internal counter number
392 */
393 verbose("idx: %d, name: %s, mask: %02x, ctr#: %d\n",
394 event_idx, event_info[event_idx].name,
395 event_info[event_idx].counters, num_events);
396 if (event_info[event_idx].counters != 0 &&
397 (event_info[event_idx].counters & CTR(num_events)) == 0) {
398 fprintf(stderr, "Bad event name: %s for counter %d, see --list\n",
399 event_name, num_events);
400 return -1;
401 }
402
403 /* Use default count */
404 if (count_name[0] == 0) {
405 count_val = min_count[0];
406 } else {
407 count_val = atoi(count_name);
408 }
409
410 selected_events[num_events] = event_idx;
411 selected_counts[num_events++] = count_val;
412 verbose("event_id is %d\n", event_info[event_idx].id);
413 verbose("count_val is %d\n", count_val);
414 return 0;
415 }
416
echo_dev(const char * str,int val,const char * file,int counter)417 int echo_dev(const char* str, int val, const char* file, int counter)
418 {
419 char fullname[512];
420 char content[128];
421 int fd;
422
423 if (counter >= 0) {
424 snprintf(fullname, 512, OP_DRIVER_BASE"/%d/%s", counter, file);
425 }
426 else {
427 snprintf(fullname, 512, OP_DRIVER_BASE"/%s", file);
428 }
429 fd = open(fullname, O_WRONLY);
430 if (fd<0) {
431 fprintf(stderr, "Cannot open %s: %s\n", fullname, strerror(errno));
432 return fd;
433 }
434 if (str == 0) {
435 sprintf(content, "%d", val);
436 }
437 else {
438 strncpy(content, str, 128);
439 }
440 verbose("Configure %s (%s)\n", fullname, content);
441 write(fd, content, strlen(content));
442 close(fd);
443 return 0;
444 }
445
do_status()446 void do_status()
447 {
448 int num;
449 char fullname[512];
450 int i;
451
452 printf("Driver directory: %s\n", OP_DRIVER_BASE);
453 printf("Session directory: %s\n", OP_DATA_DIR);
454 for (i = 0; i < max_events; i++) {
455 sprintf(fullname, OP_DRIVER_BASE"/%d/enabled", i);
456 num = read_num(fullname);
457 if (num > 0) {
458 printf("Counter %d:\n", i);
459
460 /* event name */
461 sprintf(fullname, OP_DRIVER_BASE"/%d/event", i);
462 num = read_num(fullname);
463 printf(" name: %s\n", find_event_name_from_id(num, CTR(i)));
464
465 /* profile interval */
466 sprintf(fullname, OP_DRIVER_BASE"/%d/count", i);
467 num = read_num(fullname);
468 printf(" count: %d\n", num);
469 }
470 else {
471 printf("Counter %d disabled\n", i);
472 }
473 }
474
475 num = read_num(OP_DATA_DIR"/lock");
476 if (num >= 0) {
477 /* Still needs to check if this lock is left-over */
478 sprintf(fullname, "/proc/%d", num);
479 if (access(fullname, R_OK) != 0) {
480 printf("OProfile daemon exited prematurely - redo setup"
481 " before you continue\n");
482 return;
483 }
484 else {
485
486 printf("oprofiled pid: %d\n", num);
487 num = read_num(OP_DRIVER_BASE"/enable");
488
489 printf("profiler is%s running\n", num == 0 ? " not" : "");
490
491 DIR* dir = opendir(OP_DRIVER_BASE"/stats");
492 if (dir) {
493 for (struct dirent* dirent; !!(dirent = readdir(dir));) {
494 if (strlen(dirent->d_name) >= 4 && memcmp(dirent->d_name, "cpu", 3) == 0) {
495 char cpupath[256];
496 strcpy(cpupath, OP_DRIVER_BASE"/stats/");
497 strcat(cpupath, dirent->d_name);
498
499 strcpy(fullname, cpupath);
500 strcat(fullname, "/sample_received");
501 num = read_num(fullname);
502 printf(" %s %9u samples received\n", dirent->d_name, num);
503
504 strcpy(fullname, cpupath);
505 strcat(fullname, "/sample_lost_overflow");
506 num = read_num(fullname);
507 printf(" %s %9u samples lost overflow\n", dirent->d_name, num);
508
509 strcpy(fullname, cpupath);
510 strcat(fullname, "/sample_invalid_eip");
511 num = read_num(fullname);
512 printf(" %s %9u samples invalid eip\n", dirent->d_name, num);
513
514 strcpy(fullname, cpupath);
515 strcat(fullname, "/backtrace_aborted");
516 num = read_num(fullname);
517 printf(" %s %9u backtrace aborted\n", dirent->d_name, num);
518 }
519 }
520 closedir(dir);
521 }
522
523 num = read_num(OP_DRIVER_BASE"/backtrace_depth");
524 printf("backtrace_depth: %u\n", num);
525 }
526 }
527 else {
528 printf("oprofiled is not running\n");
529 }
530 }
531
do_reset()532 void do_reset()
533 {
534 /*
535 * Sending SIGHUP will result in the following crash in oprofiled when
536 * profiling subsequent runs:
537 * Stack Trace:
538 * RELADDR FUNCTION FILE:LINE
539 * 00008cd8 add_node+12 oprofilelibdb/db_insert.c:32
540 * 00008d69 odb_update_node_with_offset+60 oprofilelibdb/db_insert.c:102
541 *
542 * However without sending SIGHUP oprofile cannot be restarted successfully.
543 * As a temporary workaround, change do_reset into a no-op for now and kill
544 * the old daemon in do_setup to start all over again as a heavy-weight
545 * reset.
546 */
547 #if 0
548 int pid = read_num(OP_DATA_DIR"/lock");
549 if (pid >= 0)
550 kill(pid, SIGHUP); /* HUP makes oprofiled close its sample files */
551
552 if (access(OP_DATA_DIR"/samples/current", R_OK) == 0)
553 system("rm -r "OP_DATA_DIR"/samples/current");
554 #endif
555 }
556
main(int argc,char * const argv[])557 int main(int argc, char * const argv[])
558 {
559 int option_index;
560 bool show_status = false;
561 char* verbose_log = NULL;
562
563 /* Initialize default strings */
564 strcpy(vmlinux, "--no-vmlinux");
565 strcpy(kernel_range, "");
566
567 setup_device();
568
569 while (1) {
570 int c = getopt_long(argc, argv, "c:e:v:r:dhVtl:", long_options, &option_index);
571 if (c == -1) {
572 break;
573 }
574 switch (c) {
575 case 0:
576 break;
577 /* --callgraph */
578 case 'c':
579 strncpy(callgraph, optarg, sizeof(callgraph));
580 break;
581 /* --event */
582 case 'e':
583 if (num_events == MAX_EVENTS) {
584 fprintf(stderr, "More than %d events specified\n",
585 MAX_EVENTS);
586 exit(1);
587 }
588 if (process_event(optarg)) {
589 exit(1);
590 }
591 break;
592 /* --vmlinux */
593 case 'v':
594 sprintf(vmlinux, "-k %s", optarg);
595 break;
596 /* --kernel-range */
597 case 'r':
598 sprintf(kernel_range, "-r %s", optarg);
599 break;
600 case 'd':
601 /* --dump */ {
602 int pid = read_num(OP_DATA_DIR"/lock");
603 echo_dev("1", 0, "dump", -1);
604 break;
605 }
606 /* --shutdown */
607 case 'h': {
608 int pid = read_num(OP_DATA_DIR"/lock");
609 if (pid >= 0) {
610 kill(pid, SIGHUP); /* Politely ask the daemon to close files */
611 sleep(1);
612 kill(pid, SIGTERM);/* Politely ask the daemon to die */
613 sleep(1);
614 kill(pid, SIGKILL);
615 }
616 setup_session_dir();
617 break;
618 }
619 /* --verbose */
620 case 'V':
621 verbose_print++;
622 break;
623 /* --verbose-log */
624 case 'l':
625 verbose_log = strdup(optarg);
626 break;
627 /* --status */
628 case 't':
629 show_status = true;
630 break;
631 default:
632 usage();
633 exit(1);
634 }
635 }
636 verbose("list_events = %d\n", list_events);
637 verbose("setup = %d\n", setup);
638
639 if (list_events) {
640 do_list_events();
641 }
642
643 if (quick) {
644 process_event(default_event);
645 setup = 1;
646 }
647
648 if (timer) {
649 setup = 1;
650 }
651
652 if (reset) {
653 do_reset();
654 }
655
656 if (show_usage) {
657 usage();
658 }
659
660 if (setup) {
661 if (do_setup()) {
662 fprintf(stderr, "do_setup failed");
663 exit(1);
664 }
665 }
666
667 if (strlen(callgraph)) {
668 echo_dev(callgraph, 0, "backtrace_depth", -1);
669 }
670
671 if (num_events != 0 || timer != 0) {
672 char command[1024];
673 int i;
674
675 strcpy(command, argv[0]);
676 char* slash = strrchr(command, '/');
677 strcpy(slash ? slash + 1 : command, "oprofiled --session-dir="OP_DATA_DIR);
678
679 #if defined(__arm__) && !defined(WITH_ARM_V7_A)
680 /* Since counter #3 can only handle CPU_CYCLES, check and shuffle the
681 * order a bit so that the maximal number of events can be profiled
682 * simultaneously
683 */
684 if (num_events == 3) {
685 for (i = 0; i < num_events; i++) {
686 int event_idx = selected_events[i];
687
688 if (event_info[event_idx].id == 0xff) {
689 break;
690 }
691 }
692
693 /* No CPU_CYCLES is found */
694 if (i == 3) {
695 fprintf(stderr, "You can only specify three events if one of "
696 "them is CPU_CYCLES\n");
697 exit(1);
698 }
699 /* Swap CPU_CYCLES to counter #2 (starting from #0)*/
700 else if (i != 2) {
701 int temp;
702
703 temp = selected_events[2];
704 selected_events[2] = selected_events[i];
705 selected_events[i] = temp;
706
707 temp = selected_counts[2];
708 selected_counts[2] = selected_counts[i];
709 selected_counts[i] = temp;
710 }
711 }
712 #endif
713
714 /* Configure the counters and enable them */
715 for (i = 0; i < num_events; i++) {
716 int event_idx = selected_events[i];
717 int setup_result = 0;
718
719 if (i == 0) {
720 snprintf(command + strlen(command), sizeof(command) - strlen(command),
721 " --events=");
722 } else {
723 snprintf(command + strlen(command), sizeof(command) - strlen(command), ",");
724 }
725 /* Compose name:id:count:unit_mask:kernel:user, something like
726 * --events=CYCLES_DATA_STALL:2:0:200000:0:1:1,....
727 */
728 snprintf(command + strlen(command), sizeof(command) - strlen(command),
729 "%s:%d:%d:%d:%d:1:1",
730 event_info[event_idx].name,
731 event_info[event_idx].id,
732 i,
733 selected_counts[i],
734 event_info[event_idx].um);
735
736 setup_result |= echo_dev("1", 0, "user", i);
737 setup_result |= echo_dev("1", 0, "kernel", i);
738 setup_result |= echo_dev(NULL, event_info[event_idx].um, "unit_mask", i);
739 setup_result |= echo_dev("1", 0, "enabled", i);
740 setup_result |= echo_dev(NULL, selected_counts[i], "count", i);
741 setup_result |= echo_dev(NULL, event_info[event_idx].id,
742 "event", i);
743 if (setup_result) {
744 fprintf(stderr, "Counter configuration failed for %s\n",
745 event_info[event_idx].name);
746 fprintf(stderr, "Did you do \"opcontrol --setup\" first?\n");
747 exit(1);
748 }
749 }
750
751 if (timer == 0) {
752 /* If not in timer mode, disable unused counters */
753 for (i = num_events; i < max_events; i++) {
754 echo_dev("0", 0, "enabled", i);
755 }
756 } else {
757 /* Timer mode uses empty event list */
758 snprintf(command + strlen(command), sizeof(command) - strlen(command),
759 " --events=");
760 }
761
762 snprintf(command + strlen(command), sizeof(command) - strlen(command),
763 " %s", vmlinux);
764 if (kernel_range[0]) {
765 snprintf(command + strlen(command), sizeof(command) - strlen(command),
766 " %s", kernel_range);
767 }
768
769 if (verbose_log) {
770 snprintf(command + strlen(command), sizeof(command) - strlen(command),
771 " --verbose=%s", verbose_log);
772 }
773
774 printf("Starting oprofiled...\n");
775 verbose("command: %s\n", command);
776
777 int rc = system(command);
778 if (rc) {
779 fprintf(stderr, "Failed, oprofile returned exit code: %d\n", rc);
780 } else {
781 sleep(2);
782 printf("Ready\n");
783 }
784 }
785
786 if (start) {
787 echo_dev("1", 0, "enable", -1);
788 int num = read_num(OP_DATA_DIR"/lock");
789
790 if (num >= 0) {
791 kill(num, SIGUSR1);
792 }
793 }
794
795 if (stop) {
796 echo_dev("1", 0, "dump", -1);
797 echo_dev("0", 0, "enable", -1);
798 }
799
800 if (show_status) {
801 do_status();
802 }
803 }
804