]> CyberLeo.Net >> Repos - FreeBSD/releng/8.0.git/blob - usr.sbin/pmcstat/pmcstat.c
Adjust to reflect 8.0-RELEASE.
[FreeBSD/releng/8.0.git] / usr.sbin / pmcstat / pmcstat.c
1 /*-
2  * Copyright (c) 2003-2008, Joseph Koshy
3  * Copyright (c) 2007 The FreeBSD Foundation
4  * All rights reserved.
5  *
6  * Portions of this software were developed by A. Joseph Koshy under
7  * sponsorship from the FreeBSD Foundation and Google, Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/types.h>
35 #include <sys/event.h>
36 #include <sys/param.h>
37 #include <sys/queue.h>
38 #include <sys/socket.h>
39 #include <sys/stat.h>
40 #include <sys/sysctl.h>
41 #include <sys/time.h>
42 #include <sys/ttycom.h>
43 #include <sys/user.h>
44 #include <sys/wait.h>
45
46 #include <assert.h>
47 #include <err.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <kvm.h>
51 #include <libgen.h>
52 #include <limits.h>
53 #include <math.h>
54 #include <pmc.h>
55 #include <pmclog.h>
56 #include <regex.h>
57 #include <signal.h>
58 #include <stdarg.h>
59 #include <stdint.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <sysexits.h>
64 #include <unistd.h>
65
66 #include "pmcstat.h"
67
68 /*
69  * A given invocation of pmcstat(8) can manage multiple PMCs of both
70  * the system-wide and per-process variety.  Each of these could be in
71  * 'counting mode' or in 'sampling mode'.
72  *
73  * For 'counting mode' PMCs, pmcstat(8) will periodically issue a
74  * pmc_read() at the configured time interval and print out the value
75  * of the requested PMCs.
76  *
77  * For 'sampling mode' PMCs it can log to a file for offline analysis,
78  * or can analyse sampling data "on the fly", either by converting
79  * samples to printed textual form or by creating gprof(1) compatible
80  * profiles, one per program executed.  When creating gprof(1)
81  * profiles it can optionally merge entries from multiple processes
82  * for a given executable into a single profile file.
83  *
84  * pmcstat(8) can also execute a command line and attach PMCs to the
85  * resulting child process.  The protocol used is as follows:
86  *
87  * - parent creates a socketpair for two way communication and
88  *   fork()s.
89  * - subsequently:
90  *
91  *   /Parent/                           /Child/
92  *
93  *   - Wait for childs token.
94  *                                      - Sends token.
95  *                                      - Awaits signal to start.
96  *  - Attaches PMCs to the child's pid
97  *    and starts them. Sets up
98  *    monitoring for the child.
99  *  - Signals child to start.
100  *                                      - Recieves signal, attempts exec().
101  *
102  * After this point normal processing can happen.
103  */
104
105 /* Globals */
106
107 int     pmcstat_interrupt = 0;
108 int     pmcstat_displayheight = DEFAULT_DISPLAY_HEIGHT;
109 int     pmcstat_sockpair[NSOCKPAIRFD];
110 int     pmcstat_kq;
111 kvm_t   *pmcstat_kvm;
112 struct kinfo_proc *pmcstat_plist;
113
114 void
115 pmcstat_attach_pmcs(struct pmcstat_args *a)
116 {
117         struct pmcstat_ev *ev;
118         struct pmcstat_target *pt;
119         int count;
120
121         /* Attach all process PMCs to target processes. */
122         count = 0;
123         STAILQ_FOREACH(ev, &a->pa_events, ev_next) {
124                 if (PMC_IS_SYSTEM_MODE(ev->ev_mode))
125                         continue;
126                 SLIST_FOREACH(pt, &a->pa_targets, pt_next)
127                         if (pmc_attach(ev->ev_pmcid, pt->pt_pid) == 0)
128                                 count++;
129                         else if (errno != ESRCH)
130                                 err(EX_OSERR, "ERROR: cannot attach pmc "
131                                     "\"%s\" to process %d", ev->ev_name,
132                                     (int) pt->pt_pid);
133         }
134
135         if (count == 0)
136                 errx(EX_DATAERR, "ERROR: No processes were attached to.");
137 }
138
139
140 void
141 pmcstat_cleanup(struct pmcstat_args *a)
142 {
143         struct pmcstat_ev *ev, *tmp;
144
145         /* release allocated PMCs. */
146         STAILQ_FOREACH_SAFE(ev, &a->pa_events, ev_next, tmp)
147             if (ev->ev_pmcid != PMC_ID_INVALID) {
148                 if (pmc_stop(ev->ev_pmcid) < 0)
149                         err(EX_OSERR, "ERROR: cannot stop pmc 0x%x "
150                             "\"%s\"", ev->ev_pmcid, ev->ev_name);
151                 if (pmc_release(ev->ev_pmcid) < 0)
152                         err(EX_OSERR, "ERROR: cannot release pmc "
153                             "0x%x \"%s\"", ev->ev_pmcid, ev->ev_name);
154                 free(ev->ev_name);
155                 free(ev->ev_spec);
156                 STAILQ_REMOVE(&a->pa_events, ev, pmcstat_ev, ev_next);
157                 free(ev);
158             }
159
160         /* de-configure the log file if present. */
161         if (a->pa_flags & (FLAG_HAS_PIPE | FLAG_HAS_OUTPUT_LOGFILE))
162                 (void) pmc_configure_logfile(-1);
163
164         if (a->pa_logparser) {
165                 pmclog_close(a->pa_logparser);
166                 a->pa_logparser = NULL;
167         }
168
169         if (a->pa_flags & (FLAG_HAS_PIPE | FLAG_HAS_OUTPUT_LOGFILE))
170                 pmcstat_shutdown_logging(a);
171 }
172
173 void
174 pmcstat_clone_event_descriptor(struct pmcstat_args *a, struct pmcstat_ev *ev,
175     uint32_t cpumask)
176 {
177         int cpu;
178         struct pmcstat_ev *ev_clone;
179
180         while ((cpu = ffs(cpumask)) > 0) {
181                 cpu--;
182
183                 if ((ev_clone = malloc(sizeof(*ev_clone))) == NULL)
184                         errx(EX_SOFTWARE, "ERROR: Out of memory");
185                 (void) memset(ev_clone, 0, sizeof(*ev_clone));
186
187                 ev_clone->ev_count = ev->ev_count;
188                 ev_clone->ev_cpu   = cpu;
189                 ev_clone->ev_cumulative = ev->ev_cumulative;
190                 ev_clone->ev_flags = ev->ev_flags;
191                 ev_clone->ev_mode  = ev->ev_mode;
192                 ev_clone->ev_name  = strdup(ev->ev_name);
193                 ev_clone->ev_pmcid = ev->ev_pmcid;
194                 ev_clone->ev_saved = ev->ev_saved;
195                 ev_clone->ev_spec  = strdup(ev->ev_spec);
196
197                 STAILQ_INSERT_TAIL(&a->pa_events, ev_clone, ev_next);
198
199                 cpumask &= ~(1 << cpu);
200         }
201 }
202
203 void
204 pmcstat_create_process(struct pmcstat_args *a)
205 {
206         char token;
207         pid_t pid;
208         struct kevent kev;
209         struct pmcstat_target *pt;
210
211         if (socketpair(AF_UNIX, SOCK_STREAM, 0, pmcstat_sockpair) < 0)
212                 err(EX_OSERR, "ERROR: cannot create socket pair");
213
214         switch (pid = fork()) {
215         case -1:
216                 err(EX_OSERR, "ERROR: cannot fork");
217                 /*NOTREACHED*/
218
219         case 0:         /* child */
220                 (void) close(pmcstat_sockpair[PARENTSOCKET]);
221
222                 /* Write a token to tell our parent we've started executing. */
223                 if (write(pmcstat_sockpair[CHILDSOCKET], "+", 1) != 1)
224                         err(EX_OSERR, "ERROR (child): cannot write token");
225
226                 /* Wait for our parent to signal us to start. */
227                 if (read(pmcstat_sockpair[CHILDSOCKET], &token, 1) < 0)
228                         err(EX_OSERR, "ERROR (child): cannot read token");
229                 (void) close(pmcstat_sockpair[CHILDSOCKET]);
230
231                 /* exec() the program requested */
232                 execvp(*a->pa_argv, a->pa_argv);
233                 /* and if that fails, notify the parent */
234                 kill(getppid(), SIGCHLD);
235                 err(EX_OSERR, "ERROR: execvp \"%s\" failed", *a->pa_argv);
236                 /*NOTREACHED*/
237
238         default:        /* parent */
239                 (void) close(pmcstat_sockpair[CHILDSOCKET]);
240                 break;
241         }
242
243         /* Ask to be notified via a kevent when the target process exits. */
244         EV_SET(&kev, pid, EVFILT_PROC, EV_ADD|EV_ONESHOT, NOTE_EXIT, 0,
245             NULL);
246         if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0)
247                 err(EX_OSERR, "ERROR: cannot monitor child process %d", pid);
248
249         if ((pt = malloc(sizeof(*pt))) == NULL)
250                 errx(EX_SOFTWARE, "ERROR: Out of memory.");
251
252         pt->pt_pid = pid;
253         SLIST_INSERT_HEAD(&a->pa_targets, pt, pt_next);
254
255         /* Wait for the child to signal that its ready to go. */
256         if (read(pmcstat_sockpair[PARENTSOCKET], &token, 1) < 0)
257                 err(EX_OSERR, "ERROR (parent): cannot read token");
258
259         return;
260 }
261
262 void
263 pmcstat_find_targets(struct pmcstat_args *a, const char *spec)
264 {
265         int n, nproc, pid, rv;
266         struct pmcstat_target *pt;
267         char errbuf[_POSIX2_LINE_MAX], *end;
268         static struct kinfo_proc *kp;
269         regex_t reg;
270         regmatch_t regmatch;
271
272         /* First check if we've been given a process id. */
273         pid = strtol(spec, &end, 0);
274         if (end != spec && pid >= 0) {
275                 if ((pt = malloc(sizeof(*pt))) == NULL)
276                         goto outofmemory;
277                 pt->pt_pid = pid;
278                 SLIST_INSERT_HEAD(&a->pa_targets, pt, pt_next);
279                 return;
280         }
281
282         /* Otherwise treat arg as a regular expression naming processes. */
283         if (pmcstat_kvm == NULL) {
284                 if ((pmcstat_kvm = kvm_openfiles(NULL, "/dev/null", NULL, 0,
285                     errbuf)) == NULL)
286                         err(EX_OSERR, "ERROR: Cannot open kernel \"%s\"",
287                             errbuf);
288                 if ((pmcstat_plist = kvm_getprocs(pmcstat_kvm, KERN_PROC_PROC,
289                     0, &nproc)) == NULL)
290                         err(EX_OSERR, "ERROR: Cannot get process list: %s",
291                             kvm_geterr(pmcstat_kvm));
292         }
293
294         if ((rv = regcomp(&reg, spec, REG_EXTENDED|REG_NOSUB)) != 0) {
295                 regerror(rv, &reg, errbuf, sizeof(errbuf));
296                 err(EX_DATAERR, "ERROR: Failed to compile regex \"%s\": %s",
297                     spec, errbuf);
298         }
299
300         for (n = 0, kp = pmcstat_plist; n < nproc; n++, kp++) {
301                 if ((rv = regexec(&reg, kp->ki_comm, 1, &regmatch, 0)) == 0) {
302                         if ((pt = malloc(sizeof(*pt))) == NULL)
303                                 goto outofmemory;
304                         pt->pt_pid = kp->ki_pid;
305                         SLIST_INSERT_HEAD(&a->pa_targets, pt, pt_next);
306                 } else if (rv != REG_NOMATCH) {
307                         regerror(rv, &reg, errbuf, sizeof(errbuf));
308                         errx(EX_SOFTWARE, "ERROR: Regex evalation failed: %s",
309                             errbuf);
310                 }
311         }
312
313         regfree(&reg);
314
315         return;
316
317  outofmemory:
318         errx(EX_SOFTWARE, "Out of memory.");
319         /*NOTREACHED*/
320 }
321
322 uint32_t
323 pmcstat_get_cpumask(const char *cpuspec)
324 {
325         uint32_t cpumask;
326         int cpu;
327         const char *s;
328         char *end;
329
330         s = cpuspec;
331         cpumask = 0ULL;
332
333         do {
334                 cpu = strtol(s, &end, 0);
335                 if (cpu < 0 || end == s)
336                         errx(EX_USAGE, "ERROR: Illegal CPU specification "
337                             "\"%s\".", cpuspec);
338                 cpumask |= (1 << cpu);
339                 s = end + strspn(end, ", \t");
340         } while (*s);
341
342         return (cpumask);
343 }
344
345 void
346 pmcstat_kill_process(struct pmcstat_args *a)
347 {
348         struct pmcstat_target *pt;
349
350         assert(a->pa_flags & FLAG_HAS_COMMANDLINE);
351
352         /*
353          * If a command line was specified, it would be the very first
354          * in the list, before any other processes specified by -t.
355          */
356         pt = SLIST_FIRST(&a->pa_targets);
357         assert(pt != NULL);
358
359         if (kill(pt->pt_pid, SIGINT) != 0)
360                 err(EX_OSERR, "ERROR: cannot signal child process");
361 }
362
363 void
364 pmcstat_start_pmcs(struct pmcstat_args *a)
365 {
366         struct pmcstat_ev *ev;
367
368         STAILQ_FOREACH(ev, &args.pa_events, ev_next) {
369
370             assert(ev->ev_pmcid != PMC_ID_INVALID);
371
372             if (pmc_start(ev->ev_pmcid) < 0) {
373                 warn("ERROR: Cannot start pmc 0x%x \"%s\"",
374                     ev->ev_pmcid, ev->ev_name);
375                 pmcstat_cleanup(a);
376                 exit(EX_OSERR);
377             }
378         }
379
380 }
381
382 void
383 pmcstat_print_headers(struct pmcstat_args *a)
384 {
385         struct pmcstat_ev *ev;
386         int c, w;
387
388         (void) fprintf(a->pa_printfile, PRINT_HEADER_PREFIX);
389
390         STAILQ_FOREACH(ev, &a->pa_events, ev_next) {
391                 if (PMC_IS_SAMPLING_MODE(ev->ev_mode))
392                         continue;
393
394                 c = PMC_IS_SYSTEM_MODE(ev->ev_mode) ? 's' : 'p';
395
396                 if (ev->ev_fieldskip != 0)
397                         (void) fprintf(a->pa_printfile, "%*s",
398                             ev->ev_fieldskip, "");
399                 w = ev->ev_fieldwidth - ev->ev_fieldskip - 2;
400
401                 if (c == 's')
402                         (void) fprintf(a->pa_printfile, "s/%02d/%-*s ",
403                             ev->ev_cpu, w-3, ev->ev_name);
404                 else
405                         (void) fprintf(a->pa_printfile, "p/%*s ", w,
406                             ev->ev_name);
407         }
408
409         (void) fflush(a->pa_printfile);
410 }
411
412 void
413 pmcstat_print_counters(struct pmcstat_args *a)
414 {
415         int extra_width;
416         struct pmcstat_ev *ev;
417         pmc_value_t value;
418
419         extra_width = sizeof(PRINT_HEADER_PREFIX) - 1;
420
421         STAILQ_FOREACH(ev, &a->pa_events, ev_next) {
422
423                 /* skip sampling mode counters */
424                 if (PMC_IS_SAMPLING_MODE(ev->ev_mode))
425                         continue;
426
427                 if (pmc_read(ev->ev_pmcid, &value) < 0)
428                         err(EX_OSERR, "ERROR: Cannot read pmc "
429                             "\"%s\"", ev->ev_name);
430
431                 (void) fprintf(a->pa_printfile, "%*ju ",
432                     ev->ev_fieldwidth + extra_width,
433                     (uintmax_t) ev->ev_cumulative ? value :
434                     (value - ev->ev_saved));
435
436                 if (ev->ev_cumulative == 0)
437                         ev->ev_saved = value;
438                 extra_width = 0;
439         }
440
441         (void) fflush(a->pa_printfile);
442 }
443
444 /*
445  * Print output
446  */
447
448 void
449 pmcstat_print_pmcs(struct pmcstat_args *a)
450 {
451         static int linecount = 0;
452
453         /* check if we need to print a header line */
454         if (++linecount > pmcstat_displayheight) {
455                 (void) fprintf(a->pa_printfile, "\n");
456                 linecount = 1;
457         }
458         if (linecount == 1)
459                 pmcstat_print_headers(a);
460         (void) fprintf(a->pa_printfile, "\n");
461
462         pmcstat_print_counters(a);
463
464         return;
465 }
466
467 /*
468  * Do process profiling
469  *
470  * If a pid was specified, attach each allocated PMC to the target
471  * process.  Otherwise, fork a child and attach the PMCs to the child,
472  * and have the child exec() the target program.
473  */
474
475 void
476 pmcstat_start_process(void)
477 {
478         /* Signal the child to proceed. */
479         if (write(pmcstat_sockpair[PARENTSOCKET], "!", 1) != 1)
480                 err(EX_OSERR, "ERROR (parent): write of token failed");
481
482         (void) close(pmcstat_sockpair[PARENTSOCKET]);
483 }
484
485 void
486 pmcstat_show_usage(void)
487 {
488         errx(EX_USAGE,
489             "[options] [commandline]\n"
490             "\t Measure process and/or system performance using hardware\n"
491             "\t performance monitoring counters.\n"
492             "\t Options include:\n"
493             "\t -C\t\t (toggle) show cumulative counts\n"
494             "\t -D path\t create profiles in directory \"path\"\n"
495             "\t -E\t\t (toggle) show counts at process exit\n"
496             "\t -G file\t write a system-wide callgraph to \"file\"\n"
497             "\t -M file\t print executable/gmon file map to \"file\"\n"
498             "\t -N\t\t (toggle) capture callchains\n"
499             "\t -O file\t send log output to \"file\"\n"
500             "\t -P spec\t allocate a process-private sampling PMC\n"
501             "\t -R file\t read events from \"file\"\n"
502             "\t -S spec\t allocate a system-wide sampling PMC\n"
503             "\t -W\t\t (toggle) show counts per context switch\n"
504             "\t -c cpu-list\t set cpus for subsequent system-wide PMCs\n"
505             "\t -d\t\t (toggle) track descendants\n"
506             "\t -g\t\t produce gprof(1) compatible profiles\n"
507             "\t -k dir\t\t set the path to the kernel\n"
508             "\t -n rate\t set sampling rate\n"
509             "\t -o file\t send print output to \"file\"\n"
510             "\t -p spec\t allocate a process-private counting PMC\n"
511             "\t -q\t\t suppress verbosity\n"
512             "\t -r fsroot\t specify FS root directory\n"
513             "\t -s spec\t allocate a system-wide counting PMC\n"
514             "\t -t process-spec attach to running processes matching "
515                 "\"process-spec\"\n"
516             "\t -v\t\t increase verbosity\n"
517             "\t -w secs\t set printing time interval\n"
518             "\t -z depth\t limit callchain display depth"
519         );
520 }
521
522 /*
523  * Main
524  */
525
526 int
527 main(int argc, char **argv)
528 {
529         double interval;
530         int option, npmc, ncpu, haltedcpus;
531         int c, check_driver_stats, current_cpu, current_sampling_count;
532         int do_callchain, do_descendants, do_logproccsw, do_logprocexit;
533         int do_print;
534         size_t dummy;
535         int graphdepth;
536         int pipefd[2];
537         int use_cumulative_counts;
538         uint32_t cpumask;
539         char *end, *tmp;
540         const char *errmsg, *graphfilename;
541         enum pmcstat_state runstate;
542         struct pmc_driverstats ds_start, ds_end;
543         struct pmcstat_ev *ev;
544         struct sigaction sa;
545         struct kevent kev;
546         struct winsize ws;
547         struct stat sb;
548         char buffer[PATH_MAX];
549
550         check_driver_stats      = 0;
551         current_cpu             = 0;
552         current_sampling_count  = DEFAULT_SAMPLE_COUNT;
553         do_callchain            = 1;
554         do_descendants          = 0;
555         do_logproccsw           = 0;
556         do_logprocexit          = 0;
557         use_cumulative_counts   = 0;
558         graphfilename           = "-";
559         args.pa_required        = 0;
560         args.pa_flags           = 0;
561         args.pa_verbosity       = 1;
562         args.pa_logfd           = -1;
563         args.pa_fsroot          = "";
564         args.pa_kernel          = strdup("/boot/kernel");
565         args.pa_samplesdir      = ".";
566         args.pa_printfile       = stderr;
567         args.pa_graphdepth      = DEFAULT_CALLGRAPH_DEPTH;
568         args.pa_graphfile       = NULL;
569         args.pa_interval        = DEFAULT_WAIT_INTERVAL;
570         args.pa_mapfilename     = NULL;
571         args.pa_inputpath       = NULL;
572         args.pa_outputpath      = NULL;
573         STAILQ_INIT(&args.pa_events);
574         SLIST_INIT(&args.pa_targets);
575         bzero(&ds_start, sizeof(ds_start));
576         bzero(&ds_end, sizeof(ds_end));
577         ev = NULL;
578
579         /*
580          * The initial CPU mask specifies all non-halted CPUS in the
581          * system.
582          */
583         dummy = sizeof(int);
584         if (sysctlbyname("hw.ncpu", &ncpu, &dummy, NULL, 0) < 0)
585                 err(EX_OSERR, "ERROR: Cannot determine the number of CPUs");
586         cpumask = (1 << ncpu) - 1;
587         haltedcpus = 0;
588         if (ncpu > 1) {
589                 if (sysctlbyname("machdep.hlt_cpus", &haltedcpus, &dummy,
590                     NULL, 0) < 0)
591                         err(EX_OSERR, "ERROR: Cannot determine which CPUs are "
592                             "halted");
593                 cpumask &= ~haltedcpus;
594         }
595
596         while ((option = getopt(argc, argv,
597             "CD:EG:M:NO:P:R:S:Wc:dgk:m:n:o:p:qr:s:t:vw:z:")) != -1)
598                 switch (option) {
599                 case 'C':       /* cumulative values */
600                         use_cumulative_counts = !use_cumulative_counts;
601                         args.pa_required |= FLAG_HAS_COUNTING_PMCS;
602                         break;
603
604                 case 'c':       /* CPU */
605
606                         if (optarg[0] == '*' && optarg[1] == '\0')
607                                 cpumask = ((1 << ncpu) - 1) & ~haltedcpus;
608                         else
609                                 cpumask = pmcstat_get_cpumask(optarg);
610
611                         args.pa_required |= FLAG_HAS_SYSTEM_PMCS;
612                         break;
613
614                 case 'D':
615                         if (stat(optarg, &sb) < 0)
616                                 err(EX_OSERR, "ERROR: Cannot stat \"%s\"",
617                                     optarg);
618                         if (!S_ISDIR(sb.st_mode))
619                                 errx(EX_USAGE, "ERROR: \"%s\" is not a "
620                                     "directory.", optarg);
621                         args.pa_samplesdir = optarg;
622                         args.pa_flags     |= FLAG_HAS_SAMPLESDIR;
623                         args.pa_required  |= FLAG_DO_GPROF;
624                         break;
625
626                 case 'd':       /* toggle descendents */
627                         do_descendants = !do_descendants;
628                         args.pa_required |= FLAG_HAS_PROCESS_PMCS;
629                         break;
630
631                 case 'G':       /* produce a system-wide callgraph */
632                         args.pa_flags |= FLAG_DO_CALLGRAPHS;
633                         graphfilename = optarg;
634                         break;
635
636                 case 'g':       /* produce gprof compatible profiles */
637                         args.pa_flags |= FLAG_DO_GPROF;
638                         break;
639
640                 case 'k':       /* pathname to the kernel */
641                         free(args.pa_kernel);
642                         args.pa_kernel = strdup(optarg);
643                         args.pa_required |= FLAG_DO_ANALYSIS;
644                         args.pa_flags    |= FLAG_HAS_KERNELPATH;
645                         break;
646
647                 case 'm':
648                         args.pa_flags |= FLAG_WANTS_MAPPINGS;
649                         graphfilename = optarg;
650                         break;
651
652                 case 'E':       /* log process exit */
653                         do_logprocexit = !do_logprocexit;
654                         args.pa_required |= (FLAG_HAS_PROCESS_PMCS |
655                             FLAG_HAS_COUNTING_PMCS | FLAG_HAS_OUTPUT_LOGFILE);
656                         break;
657
658                 case 'M':       /* mapfile */
659                         args.pa_mapfilename = optarg;
660                         break;
661
662                 case 'N':
663                         do_callchain = !do_callchain;
664                         args.pa_required |= FLAG_HAS_SAMPLING_PMCS;
665                         break;
666
667                 case 'p':       /* process virtual counting PMC */
668                 case 's':       /* system-wide counting PMC */
669                 case 'P':       /* process virtual sampling PMC */
670                 case 'S':       /* system-wide sampling PMC */
671                         if ((ev = malloc(sizeof(*ev))) == NULL)
672                                 errx(EX_SOFTWARE, "ERROR: Out of memory.");
673
674                         switch (option) {
675                         case 'p': ev->ev_mode = PMC_MODE_TC; break;
676                         case 's': ev->ev_mode = PMC_MODE_SC; break;
677                         case 'P': ev->ev_mode = PMC_MODE_TS; break;
678                         case 'S': ev->ev_mode = PMC_MODE_SS; break;
679                         }
680
681                         if (option == 'P' || option == 'p') {
682                                 args.pa_flags |= FLAG_HAS_PROCESS_PMCS;
683                                 args.pa_required |= (FLAG_HAS_COMMANDLINE |
684                                     FLAG_HAS_TARGET);
685                         }
686
687                         if (option == 'P' || option == 'S') {
688                                 args.pa_flags |= FLAG_HAS_SAMPLING_PMCS;
689                                 args.pa_required |= (FLAG_HAS_PIPE |
690                                     FLAG_HAS_OUTPUT_LOGFILE);
691                         }
692
693                         if (option == 'p' || option == 's')
694                                 args.pa_flags |= FLAG_HAS_COUNTING_PMCS;
695
696                         if (option == 's' || option == 'S')
697                                 args.pa_flags |= FLAG_HAS_SYSTEM_PMCS;
698
699                         ev->ev_spec  = strdup(optarg);
700
701                         if (option == 'S' || option == 'P')
702                                 ev->ev_count = current_sampling_count;
703                         else
704                                 ev->ev_count = -1;
705
706                         if (option == 'S' || option == 's')
707                                 ev->ev_cpu = ffs(cpumask) - 1;
708                         else
709                                 ev->ev_cpu = PMC_CPU_ANY;
710
711                         ev->ev_flags = 0;
712                         if (do_callchain)
713                                 ev->ev_flags |= PMC_F_CALLCHAIN;
714                         if (do_descendants)
715                                 ev->ev_flags |= PMC_F_DESCENDANTS;
716                         if (do_logprocexit)
717                                 ev->ev_flags |= PMC_F_LOG_PROCEXIT;
718                         if (do_logproccsw)
719                                 ev->ev_flags |= PMC_F_LOG_PROCCSW;
720
721                         ev->ev_cumulative  = use_cumulative_counts;
722
723                         ev->ev_saved = 0LL;
724                         ev->ev_pmcid = PMC_ID_INVALID;
725
726                         /* extract event name */
727                         c = strcspn(optarg, ", \t");
728                         ev->ev_name = malloc(c + 1);
729                         (void) strncpy(ev->ev_name, optarg, c);
730                         *(ev->ev_name + c) = '\0';
731
732                         STAILQ_INSERT_TAIL(&args.pa_events, ev, ev_next);
733
734                         if (option == 's' || option == 'S')
735                                 pmcstat_clone_event_descriptor(&args, ev,
736                                     cpumask & ~(1 << ev->ev_cpu));
737
738                         break;
739
740                 case 'n':       /* sampling count */
741                         current_sampling_count = strtol(optarg, &end, 0);
742                         if (*end != '\0' || current_sampling_count <= 0)
743                                 errx(EX_USAGE,
744                                     "ERROR: Illegal count value \"%s\".",
745                                     optarg);
746                         args.pa_required |= FLAG_HAS_SAMPLING_PMCS;
747                         break;
748
749                 case 'o':       /* outputfile */
750                         if (args.pa_printfile != NULL)
751                                 (void) fclose(args.pa_printfile);
752                         if ((args.pa_printfile = fopen(optarg, "w")) == NULL)
753                                 errx(EX_OSERR, "ERROR: cannot open \"%s\" for "
754                                     "writing.", optarg);
755                         args.pa_flags |= FLAG_DO_PRINT;
756                         break;
757
758                 case 'O':       /* sampling output */
759                         if (args.pa_outputpath)
760                                 errx(EX_USAGE, "ERROR: option -O may only be "
761                                     "specified once.");
762                         args.pa_outputpath = optarg;
763                         args.pa_flags |= FLAG_HAS_OUTPUT_LOGFILE;
764                         break;
765
766                 case 'q':       /* quiet mode */
767                         args.pa_verbosity = 0;
768                         break;
769
770                 case 'r':       /* root FS path */
771                         args.pa_fsroot = optarg;
772                         break;
773
774                 case 'R':       /* read an existing log file */
775                         if (args.pa_inputpath != NULL)
776                                 errx(EX_USAGE, "ERROR: option -R may only be "
777                                     "specified once.");
778                         args.pa_inputpath = optarg;
779                         if (args.pa_printfile == stderr)
780                                 args.pa_printfile = stdout;
781                         args.pa_flags |= FLAG_READ_LOGFILE;
782                         break;
783
784                 case 't':       /* target pid or process name */
785                         pmcstat_find_targets(&args, optarg);
786
787                         args.pa_flags |= FLAG_HAS_TARGET;
788                         args.pa_required |= FLAG_HAS_PROCESS_PMCS;
789                         break;
790
791                 case 'v':       /* verbose */
792                         args.pa_verbosity++;
793                         break;
794
795                 case 'w':       /* wait interval */
796                         interval = strtod(optarg, &end);
797                         if (*end != '\0' || interval <= 0)
798                                 errx(EX_USAGE, "ERROR: Illegal wait interval "
799                                     "value \"%s\".", optarg);
800                         args.pa_flags |= FLAG_HAS_WAIT_INTERVAL;
801                         args.pa_required |= FLAG_HAS_COUNTING_PMCS;
802                         args.pa_interval = interval;
803                         break;
804
805                 case 'W':       /* toggle LOG_CSW */
806                         do_logproccsw = !do_logproccsw;
807                         args.pa_required |= (FLAG_HAS_PROCESS_PMCS |
808                             FLAG_HAS_COUNTING_PMCS | FLAG_HAS_OUTPUT_LOGFILE);
809                         break;
810
811                 case 'z':
812                         graphdepth = strtod(optarg, &end);
813                         if (*end != '\0' || graphdepth <= 0)
814                                 errx(EX_USAGE, "ERROR: Illegal callchain "
815                                     "depth \"%s\".", optarg);
816                         args.pa_graphdepth = graphdepth;
817                         args.pa_required |= FLAG_DO_CALLGRAPHS;
818                         break;
819
820                 case '?':
821                 default:
822                         pmcstat_show_usage();
823                         break;
824
825                 }
826
827         args.pa_argc = (argc -= optind);
828         args.pa_argv = (argv += optind);
829
830         args.pa_cpumask = cpumask; /* For selecting CPUs using -R. */
831
832         if (argc)       /* command line present */
833                 args.pa_flags |= FLAG_HAS_COMMANDLINE;
834
835         if (args.pa_flags & (FLAG_DO_GPROF | FLAG_DO_CALLGRAPHS |
836             FLAG_WANTS_MAPPINGS))
837                 args.pa_flags |= FLAG_DO_ANALYSIS;
838
839         /*
840          * Check invocation syntax.
841          */
842
843         /* disallow -O and -R together */
844         if (args.pa_outputpath && args.pa_inputpath)
845                 errx(EX_USAGE, "ERROR: options -O and -R are mutually "
846                     "exclusive.");
847
848         /* -m option is allowed with -R only. */
849         if (args.pa_flags & FLAG_WANTS_MAPPINGS && args.pa_inputpath == NULL)
850                 errx(EX_USAGE, "ERROR: option -m requires an input file");
851
852         /* -m option is not allowed combined with -g or -G. */
853         if (args.pa_flags & FLAG_WANTS_MAPPINGS &&
854             args.pa_flags & (FLAG_DO_GPROF | FLAG_DO_CALLGRAPHS))
855                 errx(EX_USAGE, "ERROR: option -m and -g | -G are mutually "
856                     "exclusive");
857
858         if (args.pa_flags & FLAG_READ_LOGFILE) {
859                 errmsg = NULL;
860                 if (args.pa_flags & FLAG_HAS_COMMANDLINE)
861                         errmsg = "a command line specification";
862                 else if (args.pa_flags & FLAG_HAS_TARGET)
863                         errmsg = "option -t";
864                 else if (!STAILQ_EMPTY(&args.pa_events))
865                         errmsg = "a PMC event specification";
866                 if (errmsg)
867                         errx(EX_USAGE, "ERROR: option -R may not be used with "
868                             "%s.", errmsg);
869         } else if (STAILQ_EMPTY(&args.pa_events))
870                 /* All other uses require a PMC spec. */
871                 pmcstat_show_usage();
872
873         /* check for -t pid without a process PMC spec */
874         if ((args.pa_required & FLAG_HAS_TARGET) &&
875             (args.pa_flags & FLAG_HAS_PROCESS_PMCS) == 0)
876                 errx(EX_USAGE, "ERROR: option -t requires a process mode PMC "
877                     "to be specified.");
878
879         /* check for process-mode options without a command or -t pid */
880         if ((args.pa_required & FLAG_HAS_PROCESS_PMCS) &&
881             (args.pa_flags & (FLAG_HAS_COMMANDLINE | FLAG_HAS_TARGET)) == 0)
882                 errx(EX_USAGE, "ERROR: options -d, -E, -p, -P, and -W require "
883                     "a command line or target process.");
884
885         /* check for -p | -P without a target process of some sort */
886         if ((args.pa_required & (FLAG_HAS_COMMANDLINE | FLAG_HAS_TARGET)) &&
887             (args.pa_flags & (FLAG_HAS_COMMANDLINE | FLAG_HAS_TARGET)) == 0)
888                 errx(EX_USAGE, "ERROR: options -P and -p require a "
889                     "target process or a command line.");
890
891         /* check for process-mode options without a process-mode PMC */
892         if ((args.pa_required & FLAG_HAS_PROCESS_PMCS) &&
893             (args.pa_flags & FLAG_HAS_PROCESS_PMCS) == 0)
894                 errx(EX_USAGE, "ERROR: options -d, -E, and -W require a "
895                     "process mode PMC to be specified.");
896
897         /* check for -c cpu with no system mode PMCs or logfile. */
898         if ((args.pa_required & FLAG_HAS_SYSTEM_PMCS) &&
899             (args.pa_flags & FLAG_HAS_SYSTEM_PMCS) == 0 &&
900             (args.pa_flags & FLAG_READ_LOGFILE) == 0)
901                 errx(EX_USAGE, "ERROR: option -c requires at least one "
902                     "system mode PMC to be specified.");
903
904         /* check for counting mode options without a counting PMC */
905         if ((args.pa_required & FLAG_HAS_COUNTING_PMCS) &&
906             (args.pa_flags & FLAG_HAS_COUNTING_PMCS) == 0)
907                 errx(EX_USAGE, "ERROR: options -C, -W, -o and -w require at "
908                     "least one counting mode PMC to be specified.");
909
910         /* check for sampling mode options without a sampling PMC spec */
911         if ((args.pa_required & FLAG_HAS_SAMPLING_PMCS) &&
912             (args.pa_flags & FLAG_HAS_SAMPLING_PMCS) == 0)
913                 errx(EX_USAGE, "ERROR: options -N, -n and -O require at "
914                     "least one sampling mode PMC to be specified.");
915
916         /* check if -g/-G are being used correctly */
917         if ((args.pa_flags & FLAG_DO_ANALYSIS) &&
918             !(args.pa_flags & (FLAG_HAS_SAMPLING_PMCS|FLAG_READ_LOGFILE)))
919                 errx(EX_USAGE, "ERROR: options -g/-G require sampling PMCs "
920                     "or -R to be specified.");
921
922         /* check if -O was spuriously specified */
923         if ((args.pa_flags & FLAG_HAS_OUTPUT_LOGFILE) &&
924             (args.pa_required & FLAG_HAS_OUTPUT_LOGFILE) == 0)
925                 errx(EX_USAGE,
926                     "ERROR: option -O is used only with options "
927                     "-E, -P, -S and -W.");
928
929         /* -k kernel path require -g/-G or -R */
930         if ((args.pa_flags & FLAG_HAS_KERNELPATH) &&
931             (args.pa_flags & FLAG_DO_ANALYSIS) == 0 &&
932             (args.pa_flags & FLAG_READ_LOGFILE) == 0)
933             errx(EX_USAGE, "ERROR: option -k is only used with -g/-R.");
934
935         /* -D only applies to gprof output mode (-g) */
936         if ((args.pa_flags & FLAG_HAS_SAMPLESDIR) &&
937             (args.pa_flags & FLAG_DO_GPROF) == 0)
938             errx(EX_USAGE, "ERROR: option -D is only used with -g.");
939
940         /* -M mapfile requires -g or -R */
941         if (args.pa_mapfilename != NULL &&
942             (args.pa_flags & FLAG_DO_GPROF) == 0 &&
943             (args.pa_flags & FLAG_READ_LOGFILE) == 0)
944             errx(EX_USAGE, "ERROR: option -M is only used with -g/-R.");
945
946         /*
947          * Disallow textual output of sampling PMCs if counting PMCs
948          * have also been asked for, mostly because the combined output
949          * is difficult to make sense of.
950          */
951         if ((args.pa_flags & FLAG_HAS_COUNTING_PMCS) &&
952             (args.pa_flags & FLAG_HAS_SAMPLING_PMCS) &&
953             ((args.pa_flags & FLAG_HAS_OUTPUT_LOGFILE) == 0))
954                 errx(EX_USAGE, "ERROR: option -O is required if counting and "
955                     "sampling PMCs are specified together.");
956
957         /*
958          * Check if "-k kerneldir" was specified, and if whether
959          * 'kerneldir' actually refers to a a file.  If so, use
960          * `dirname path` to determine the kernel directory.
961          */
962         if (args.pa_flags & FLAG_HAS_KERNELPATH) {
963                 (void) snprintf(buffer, sizeof(buffer), "%s%s", args.pa_fsroot,
964                     args.pa_kernel);
965                 if (stat(buffer, &sb) < 0)
966                         err(EX_OSERR, "ERROR: Cannot locate kernel \"%s\"",
967                             buffer);
968                 if (!S_ISREG(sb.st_mode) && !S_ISDIR(sb.st_mode))
969                         errx(EX_USAGE, "ERROR: \"%s\": Unsupported file type.",
970                             buffer);
971                 if (!S_ISDIR(sb.st_mode)) {
972                         tmp = args.pa_kernel;
973                         args.pa_kernel = strdup(dirname(args.pa_kernel));
974                         free(tmp);
975                         (void) snprintf(buffer, sizeof(buffer), "%s%s",
976                             args.pa_fsroot, args.pa_kernel);
977                         if (stat(buffer, &sb) < 0)
978                                 err(EX_OSERR, "ERROR: Cannot stat \"%s\"",
979                                     buffer);
980                         if (!S_ISDIR(sb.st_mode))
981                                 errx(EX_USAGE, "ERROR: \"%s\" is not a "
982                                     "directory.", buffer);
983                 }
984         }
985
986         /*
987          * If we have a callgraph be created, select the outputfile.
988          */
989         if (args.pa_flags & FLAG_DO_CALLGRAPHS) {
990                 if (strcmp(graphfilename, "-") == 0)
991                     args.pa_graphfile = args.pa_printfile;
992                 else {
993                         args.pa_graphfile = fopen(graphfilename, "w");
994                         if (args.pa_graphfile == NULL)
995                                 err(EX_OSERR, "ERROR: cannot open \"%s\" "
996                                     "for writing", graphfilename);
997                 }
998         }
999         if (args.pa_flags & FLAG_WANTS_MAPPINGS) {
1000                 args.pa_graphfile = fopen(graphfilename, "w");
1001                 if (args.pa_graphfile == NULL)
1002                         err(EX_OSERR, "ERROR: cannot open \"%s\" for writing",
1003                             graphfilename);
1004         }
1005
1006         /* if we've been asked to process a log file, do that and exit */
1007         if (args.pa_flags & FLAG_READ_LOGFILE) {
1008                 /*
1009                  * Print the log in textual form if we haven't been
1010                  * asked to generate profiling information.
1011                  */
1012                 if ((args.pa_flags & FLAG_DO_ANALYSIS) == 0)
1013                         args.pa_flags |= FLAG_DO_PRINT;
1014
1015                 pmcstat_initialize_logging(&args);
1016                 args.pa_logfd = pmcstat_open_log(args.pa_inputpath,
1017                     PMCSTAT_OPEN_FOR_READ);
1018                 if ((args.pa_logparser = pmclog_open(args.pa_logfd)) == NULL)
1019                         err(EX_OSERR, "ERROR: Cannot create parser");
1020                 pmcstat_process_log(&args);
1021                 pmcstat_shutdown_logging(&args);
1022                 exit(EX_OK);
1023         }
1024
1025         /* otherwise, we've been asked to collect data */
1026         if (pmc_init() < 0)
1027                 err(EX_UNAVAILABLE,
1028                     "ERROR: Initialization of the pmc(3) library failed");
1029
1030         if ((npmc = pmc_npmc(0)) < 0) /* assume all CPUs are identical */
1031                 err(EX_OSERR, "ERROR: Cannot determine the number of PMCs "
1032                     "on CPU %d", 0);
1033
1034         /* Allocate a kqueue */
1035         if ((pmcstat_kq = kqueue()) < 0)
1036                 err(EX_OSERR, "ERROR: Cannot allocate kqueue");
1037
1038         /*
1039          * Configure the specified log file or setup a default log
1040          * consumer via a pipe.
1041          */
1042         if (args.pa_required & FLAG_HAS_OUTPUT_LOGFILE) {
1043                 if (args.pa_outputpath)
1044                         args.pa_logfd = pmcstat_open_log(args.pa_outputpath,
1045                             PMCSTAT_OPEN_FOR_WRITE);
1046                 else {
1047                         /*
1048                          * process the log on the fly by reading it in
1049                          * through a pipe.
1050                          */
1051                         if (pipe(pipefd) < 0)
1052                                 err(EX_OSERR, "ERROR: pipe(2) failed");
1053
1054                         if (fcntl(pipefd[READPIPEFD], F_SETFL, O_NONBLOCK) < 0)
1055                                 err(EX_OSERR, "ERROR: fcntl(2) failed");
1056
1057                         EV_SET(&kev, pipefd[READPIPEFD], EVFILT_READ, EV_ADD,
1058                             0, 0, NULL);
1059
1060                         if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0)
1061                                 err(EX_OSERR, "ERROR: Cannot register kevent");
1062
1063                         args.pa_logfd = pipefd[WRITEPIPEFD];
1064
1065                         args.pa_flags |= (FLAG_HAS_PIPE | FLAG_DO_PRINT);
1066                         args.pa_logparser = pmclog_open(pipefd[READPIPEFD]);
1067                 }
1068
1069                 if (pmc_configure_logfile(args.pa_logfd) < 0)
1070                         err(EX_OSERR, "ERROR: Cannot configure log file");
1071         }
1072
1073         /* remember to check for driver errors if we are sampling or logging */
1074         check_driver_stats = (args.pa_flags & FLAG_HAS_SAMPLING_PMCS) ||
1075             (args.pa_flags & FLAG_HAS_OUTPUT_LOGFILE);
1076
1077         /*
1078          * Allocate PMCs.
1079          */
1080
1081         STAILQ_FOREACH(ev, &args.pa_events, ev_next) {
1082             if (pmc_allocate(ev->ev_spec, ev->ev_mode,
1083                     ev->ev_flags, ev->ev_cpu, &ev->ev_pmcid) < 0)
1084                     err(EX_OSERR, "ERROR: Cannot allocate %s-mode pmc with "
1085                         "specification \"%s\"",
1086                         PMC_IS_SYSTEM_MODE(ev->ev_mode) ? "system" : "process",
1087                         ev->ev_spec);
1088
1089             if (PMC_IS_SAMPLING_MODE(ev->ev_mode) &&
1090                 pmc_set(ev->ev_pmcid, ev->ev_count) < 0)
1091                     err(EX_OSERR, "ERROR: Cannot set sampling count "
1092                         "for PMC \"%s\"", ev->ev_name);
1093         }
1094
1095         /* compute printout widths */
1096         STAILQ_FOREACH(ev, &args.pa_events, ev_next) {
1097                 int counter_width;
1098                 int display_width;
1099                 int header_width;
1100
1101                 (void) pmc_width(ev->ev_pmcid, &counter_width);
1102                 header_width = strlen(ev->ev_name) + 2; /* prefix '%c/' */
1103                 display_width = (int) floor(counter_width / 3.32193) + 1;
1104
1105                 if (PMC_IS_SYSTEM_MODE(ev->ev_mode))
1106                         header_width += 3; /* 2 digit CPU number + '/' */
1107
1108                 if (header_width > display_width) {
1109                         ev->ev_fieldskip = 0;
1110                         ev->ev_fieldwidth = header_width;
1111                 } else {
1112                         ev->ev_fieldskip = display_width -
1113                             header_width;
1114                         ev->ev_fieldwidth = display_width;
1115                 }
1116         }
1117
1118         /*
1119          * If our output is being set to a terminal, register a handler
1120          * for window size changes.
1121          */
1122
1123         if (isatty(fileno(args.pa_printfile))) {
1124
1125                 if (ioctl(fileno(args.pa_printfile), TIOCGWINSZ, &ws) < 0)
1126                         err(EX_OSERR, "ERROR: Cannot determine window size");
1127
1128                 pmcstat_displayheight = ws.ws_row - 1;
1129
1130                 EV_SET(&kev, SIGWINCH, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
1131
1132                 if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0)
1133                         err(EX_OSERR, "ERROR: Cannot register kevent for "
1134                             "SIGWINCH");
1135         }
1136
1137         EV_SET(&kev, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
1138         if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0)
1139                 err(EX_OSERR, "ERROR: Cannot register kevent for SIGINT");
1140
1141         EV_SET(&kev, SIGIO, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
1142         if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0)
1143                 err(EX_OSERR, "ERROR: Cannot register kevent for SIGIO");
1144
1145         /*
1146          * An exec() failure of a forked child is signalled by the
1147          * child sending the parent a SIGCHLD.  We don't register an
1148          * actual signal handler for SIGCHLD, but instead use our
1149          * kqueue to pick up the signal.
1150          */
1151         EV_SET(&kev, SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
1152         if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0)
1153                 err(EX_OSERR, "ERROR: Cannot register kevent for SIGCHLD");
1154
1155         /* setup a timer if we have counting mode PMCs needing to be printed */
1156         if ((args.pa_flags & FLAG_HAS_COUNTING_PMCS) &&
1157             (args.pa_required & FLAG_HAS_OUTPUT_LOGFILE) == 0) {
1158                 EV_SET(&kev, 0, EVFILT_TIMER, EV_ADD, 0,
1159                     args.pa_interval * 1000, NULL);
1160
1161                 if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0)
1162                         err(EX_OSERR, "ERROR: Cannot register kevent for "
1163                             "timer");
1164         }
1165
1166         /* attach PMCs to the target process, starting it if specified */
1167         if (args.pa_flags & FLAG_HAS_COMMANDLINE)
1168                 pmcstat_create_process(&args);
1169
1170         if (check_driver_stats && pmc_get_driver_stats(&ds_start) < 0)
1171                 err(EX_OSERR, "ERROR: Cannot retrieve driver statistics");
1172
1173         /* Attach process pmcs to the target process. */
1174         if (args.pa_flags & (FLAG_HAS_TARGET | FLAG_HAS_COMMANDLINE)) {
1175                 if (SLIST_EMPTY(&args.pa_targets))
1176                         errx(EX_DATAERR, "ERROR: No matching target "
1177                             "processes.");
1178                 if (args.pa_flags & FLAG_HAS_PROCESS_PMCS)
1179                         pmcstat_attach_pmcs(&args);
1180
1181                 if (pmcstat_kvm) {
1182                         kvm_close(pmcstat_kvm);
1183                         pmcstat_kvm = NULL;
1184                 }
1185         }
1186
1187         /* start the pmcs */
1188         pmcstat_start_pmcs(&args);
1189
1190         /* start the (commandline) process if needed */
1191         if (args.pa_flags & FLAG_HAS_COMMANDLINE)
1192                 pmcstat_start_process();
1193
1194         /* initialize logging if printing the configured log */
1195         if ((args.pa_flags & FLAG_DO_PRINT) &&
1196             (args.pa_flags & (FLAG_HAS_PIPE | FLAG_HAS_OUTPUT_LOGFILE)))
1197                 pmcstat_initialize_logging(&args);
1198
1199         /* Handle SIGINT using the kqueue loop */
1200         sa.sa_handler = SIG_IGN;
1201         sa.sa_flags   = 0;
1202         (void) sigemptyset(&sa.sa_mask);
1203
1204         if (sigaction(SIGINT, &sa, NULL) < 0)
1205                 err(EX_OSERR, "ERROR: Cannot install signal handler");
1206
1207         /*
1208          * loop till either the target process (if any) exits, or we
1209          * are killed by a SIGINT.
1210          */
1211         runstate = PMCSTAT_RUNNING;
1212         do_print = 0;
1213         do {
1214                 if ((c = kevent(pmcstat_kq, NULL, 0, &kev, 1, NULL)) <= 0) {
1215                         if (errno != EINTR)
1216                                 err(EX_OSERR, "ERROR: kevent failed");
1217                         else
1218                                 continue;
1219                 }
1220
1221                 if (kev.flags & EV_ERROR)
1222                         errc(EX_OSERR, kev.data, "ERROR: kevent failed");
1223
1224                 switch (kev.filter) {
1225                 case EVFILT_PROC:  /* target has exited */
1226                         if (args.pa_flags & (FLAG_HAS_OUTPUT_LOGFILE |
1227                                 FLAG_HAS_PIPE))
1228                                 runstate = pmcstat_close_log(&args);
1229                         else
1230                                 runstate = PMCSTAT_FINISHED;
1231                         do_print = 1;
1232                         break;
1233
1234                 case EVFILT_READ:  /* log file data is present */
1235                         runstate = pmcstat_process_log(&args);
1236                         break;
1237
1238                 case EVFILT_SIGNAL:
1239                         if (kev.ident == SIGCHLD) {
1240                                 /*
1241                                  * The child process sends us a
1242                                  * SIGCHLD if its exec() failed.  We
1243                                  * wait for it to exit and then exit
1244                                  * ourselves.
1245                                  */
1246                                 (void) wait(&c);
1247                                 runstate = PMCSTAT_FINISHED;
1248                         } else if (kev.ident == SIGIO) {
1249                                 /*
1250                                  * We get a SIGIO if a PMC loses all
1251                                  * of its targets, or if logfile
1252                                  * writes encounter an error.
1253                                  */
1254                                 if (args.pa_flags & (FLAG_HAS_OUTPUT_LOGFILE |
1255                                     FLAG_HAS_PIPE)) {
1256                                         runstate = pmcstat_close_log(&args);
1257                                         if (args.pa_flags &
1258                                             (FLAG_DO_PRINT|FLAG_DO_ANALYSIS))
1259                                                 pmcstat_process_log(&args);
1260                                 }
1261                                 do_print = 1; /* print PMCs at exit */
1262                                 runstate = PMCSTAT_FINISHED;
1263                         } else if (kev.ident == SIGINT) {
1264                                 /* Kill the child process if we started it */
1265                                 if (args.pa_flags & FLAG_HAS_COMMANDLINE)
1266                                         pmcstat_kill_process(&args);
1267                                 /* Close the pipe to self, if present. */
1268                                 if (args.pa_flags & FLAG_HAS_PIPE)
1269                                         (void) close(pipefd[READPIPEFD]);
1270                                 runstate = PMCSTAT_FINISHED;
1271                         } else if (kev.ident == SIGWINCH) {
1272                                 if (ioctl(fileno(args.pa_printfile),
1273                                         TIOCGWINSZ, &ws) < 0)
1274                                     err(EX_OSERR, "ERROR: Cannot determine "
1275                                         "window size");
1276                                 pmcstat_displayheight = ws.ws_row - 1;
1277                         } else
1278                                 assert(0);
1279
1280                         break;
1281
1282                 case EVFILT_TIMER: /* print out counting PMCs */
1283                         do_print = 1;
1284                         break;
1285
1286                 }
1287
1288                 if (do_print &&
1289                     (args.pa_required & FLAG_HAS_OUTPUT_LOGFILE) == 0) {
1290                         pmcstat_print_pmcs(&args);
1291                         if (runstate == PMCSTAT_FINISHED && /* final newline */
1292                             (args.pa_flags & FLAG_DO_PRINT) == 0)
1293                                 (void) fprintf(args.pa_printfile, "\n");
1294                         do_print = 0;
1295                 }
1296
1297         } while (runstate != PMCSTAT_FINISHED);
1298
1299         /* flush any pending log entries */
1300         if (args.pa_flags & (FLAG_HAS_OUTPUT_LOGFILE | FLAG_HAS_PIPE))
1301                 pmc_flush_logfile();
1302
1303         pmcstat_cleanup(&args);
1304
1305         free(args.pa_kernel);
1306
1307         /* check if the driver lost any samples or events */
1308         if (check_driver_stats) {
1309                 if (pmc_get_driver_stats(&ds_end) < 0)
1310                         err(EX_OSERR, "ERROR: Cannot retrieve driver "
1311                             "statistics");
1312                 if (ds_start.pm_intr_bufferfull != ds_end.pm_intr_bufferfull &&
1313                     args.pa_verbosity > 0)
1314                         warnx("WARNING: some samples were dropped.  Please "
1315                             "consider tuning the \"kern.hwpmc.nsamples\" "
1316                             "tunable.");
1317                 if (ds_start.pm_buffer_requests_failed !=
1318                     ds_end.pm_buffer_requests_failed &&
1319                     args.pa_verbosity > 0)
1320                         warnx("WARNING: some events were discarded.  Please "
1321                             "consider tuning the \"kern.hwpmc.nbuffers\" "
1322                             "tunable.");
1323         }
1324
1325         exit(EX_OK);
1326 }