• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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