9ns: Fix devtab function pointer signatures
[akaros.git] / kern / drivers / dev / kprof.c
1 /*
2  * This file is part of the UCB release of Plan 9. It is subject to the license
3  * terms in the LICENSE file found in the top-level directory of this
4  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
5  * part of the UCB release of Plan 9, including this file, may be copied,
6  * modified, propagated, or distributed except according to the terms contained
7  * in the LICENSE file.
8  */
9
10 #include <ros/profiler_records.h>
11 #include <arch/time.h>
12 #include <vfs.h>
13 #include <slab.h>
14 #include <kmalloc.h>
15 #include <kref.h>
16 #include <atomic.h>
17 #include <kthread.h>
18 #include <string.h>
19 #include <stdio.h>
20 #include <assert.h>
21 #include <error.h>
22 #include <pmap.h>
23 #include <smp.h>
24 #include <time.h>
25 #include <circular_buffer.h>
26 #include <umem.h>
27 #include <profiler.h>
28 #include <kprof.h>
29 #include <ros/procinfo.h>
30 #include <init.h>
31
32 #define KTRACE_BUFFER_SIZE (128 * 1024)
33 #define TRACE_PRINTK_BUFFER_SIZE (8 * 1024)
34
35 enum {
36         Kprofdirqid = 0,
37         Kprofdataqid,
38         Kprofctlqid,
39         Kptracectlqid,
40         Kptraceqid,
41         Kprintxqid,
42         Kmpstatqid,
43         Kmpstatrawqid,
44 };
45
46 struct trace_printk_buffer {
47         atomic_t in_use;
48         char buffer[TRACE_PRINTK_BUFFER_SIZE];
49 };
50
51 struct kprof {
52         qlock_t lock;
53         bool mpstat_ipi;
54         bool profiling;
55         bool opened;
56 };
57
58 struct dev kprofdevtab;
59 struct dirtab kproftab[] = {
60         {".",                   {Kprofdirqid,           0, QTDIR}, 0,   DMDIR|0550},
61         {"kpdata",              {Kprofdataqid},         0,      0600},
62         {"kpctl",               {Kprofctlqid},          0,      0600},
63         {"kptrace_ctl", {Kptracectlqid},        0,      0660},
64         {"kptrace",             {Kptraceqid},           0,      0600},
65         {"kprintx",             {Kprintxqid},           0,      0600},
66         {"mpstat",              {Kmpstatqid},           0,      0600},
67         {"mpstat-raw",  {Kmpstatrawqid},        0,      0600},
68 };
69
70 static struct kprof kprof;
71 static bool ktrace_init_done = FALSE;
72 static spinlock_t ktrace_lock = SPINLOCK_INITIALIZER_IRQSAVE;
73 static struct circular_buffer ktrace_data;
74 static char ktrace_buffer[KTRACE_BUFFER_SIZE];
75 static char kprof_control_usage[128];
76
77 static size_t mpstat_len(void)
78 {
79         size_t each_row = 7 + NR_CPU_STATES * 26;
80
81         return each_row * (num_cores + 1) + 1;
82 }
83
84 static size_t mpstatraw_len(void)
85 {
86         size_t header_row = 27 + NR_CPU_STATES * 7 + 1;
87         size_t cpu_row = 7 + NR_CPU_STATES * 17;
88
89         return header_row + cpu_row * num_cores + 1;
90 }
91
92 static char *devname(void)
93 {
94         return kprofdevtab.name;
95 }
96
97 static struct chan *kprof_attach(char *spec)
98 {
99         return devattach(devname(), spec);
100 }
101
102 /* Start collecting samples from perf events into the profiler.
103  *
104  * This command only runs if the user successfully opened kpctl, which gives
105  * them a profiler (the global profiler, for now). */
106 static void kprof_start_profiler(void)
107 {
108         ERRSTACK(1);
109
110         qlock(&kprof.lock);
111         if (waserror()) {
112                 qunlock(&kprof.lock);
113                 nexterror();
114         }
115         if (!kprof.profiling) {
116                 profiler_start();
117                 kprof.profiling = TRUE;
118         }
119         poperror();
120         qunlock(&kprof.lock);
121 }
122
123 /* Stops collecting samples from perf events.
124  *
125  * This command only runs if the user successfully opened kpctl, which gives
126  * them a profiler (the global profiler, for now). */
127 static void kprof_stop_profiler(void)
128 {
129         ERRSTACK(1);
130
131         qlock(&kprof.lock);
132         if (waserror()) {
133                 qunlock(&kprof.lock);
134                 nexterror();
135         }
136         if (kprof.profiling) {
137                 profiler_stop();
138                 kprof.profiling = FALSE;
139         }
140         poperror();
141         qunlock(&kprof.lock);
142 }
143
144 /* Makes each core flush its results into the profiler queue.  You can do this
145  * while the profiler is still running.  However, this does not hang up the
146  * queue, so reads on kpdata will block. */
147 static void kprof_flush_profiler(void)
148 {
149         ERRSTACK(1);
150
151         qlock(&kprof.lock);
152         if (waserror()) {
153                 qunlock(&kprof.lock);
154                 nexterror();
155         }
156         if (kprof.profiling)
157                 profiler_trace_data_flush();
158         poperror();
159         qunlock(&kprof.lock);
160 }
161
162 static void kprof_init(void)
163 {
164         profiler_init();
165
166         qlock_init(&kprof.lock);
167         kprof.profiling = FALSE;
168         kprof.opened = FALSE;
169
170         for (int i = 0; i < ARRAY_SIZE(kproftab); i++)
171                 kproftab[i].length = 0;
172
173         kprof.mpstat_ipi = TRUE;
174         kproftab[Kmpstatqid].length = mpstat_len();
175         kproftab[Kmpstatrawqid].length = mpstatraw_len();
176
177         strlcpy(kprof_control_usage, "start|stop|flush",
178                 sizeof(kprof_control_usage));
179         profiler_append_configure_usage(kprof_control_usage,
180                                         sizeof(kprof_control_usage));
181 }
182
183 static void kprof_shutdown(void)
184 {
185 }
186
187 static struct walkqid *kprof_walk(struct chan *c, struct chan *nc, char **name,
188                                   unsigned int nname)
189 {
190         return devwalk(c, nc, name, nname, kproftab, ARRAY_SIZE(kproftab), devgen);
191 }
192
193 static size_t kprof_profdata_size(void)
194 {
195         return profiler_size();
196 }
197
198 static long kprof_profdata_read(void *dest, long size, int64_t off)
199 {
200         return profiler_read(dest, size);
201 }
202
203 static size_t kprof_stat(struct chan *c, uint8_t *db, size_t n)
204 {
205         kproftab[Kprofdataqid].length = kprof_profdata_size();
206         kproftab[Kptraceqid].length = kprof_tracedata_size();
207
208         return devstat(c, db, n, kproftab, ARRAY_SIZE(kproftab), devgen);
209 }
210
211 static struct chan *kprof_open(struct chan *c, int omode)
212 {
213         if (c->qid.type & QTDIR) {
214                 if (openmode(omode) != O_READ)
215                         error(EPERM, ERROR_FIXME);
216         }
217         switch ((int) c->qid.path) {
218         case Kprofctlqid:
219                 /* We have one global profiler.  Only one FD may be opened at a time for
220                  * it.  If we ever have separate profilers, we can create the profiler
221                  * here, and every open would get a separate instance. */
222                 qlock(&kprof.lock);
223                 if (kprof.opened) {
224                         qunlock(&kprof.lock);
225                         error(EBUSY, "Global profiler is already open");
226                 }
227                 kprof.opened = TRUE;
228                 /* TODO: have a real creation function for a non-global profiler */
229                 profiler_setup();
230                 qunlock(&kprof.lock);
231                 break;
232         }
233         c->mode = openmode(omode);
234         c->flag |= COPEN;
235         c->offset = 0;
236         return c;
237 }
238
239 static void kprof_close(struct chan *c)
240 {
241         if (c->flag & COPEN) {
242                 switch ((int) c->qid.path) {
243                 case Kprofctlqid:
244                         kprof_stop_profiler();
245                         qlock(&kprof.lock);
246                         profiler_cleanup();
247                         kprof.opened = FALSE;
248                         qunlock(&kprof.lock);
249                         break;
250                 }
251         }
252 }
253
254 static long mpstat_read(void *va, long n, int64_t off)
255 {
256         size_t bufsz = mpstat_len();
257         char *buf = kmalloc(bufsz, MEM_WAIT);
258         int len = 0;
259         struct per_cpu_info *pcpui;
260         uint64_t cpu_total;
261         struct timespec ts;
262
263         /* the IPI interferes with other cores, might want to disable that. */
264         if (kprof.mpstat_ipi)
265                 send_broadcast_ipi(I_POKE_CORE);
266
267         len += snprintf(buf + len, bufsz - len, "  CPU: ");
268         for (int j = 0; j < NR_CPU_STATES; j++)
269                 len += snprintf(buf + len, bufsz - len, "%23s%s", cpu_state_names[j],
270                                 j != NR_CPU_STATES - 1 ? "   " : "  \n");
271
272         for (int i = 0; i < num_cores; i++) {
273                 pcpui = &per_cpu_info[i];
274                 cpu_total = 0;
275                 len += snprintf(buf + len, bufsz - len, "%5d: ", i);
276                 for (int j = 0; j < NR_CPU_STATES; j++)
277                         cpu_total += pcpui->state_ticks[j];
278                 cpu_total = MAX(cpu_total, 1);  /* for the divide later */
279                 for (int j = 0; j < NR_CPU_STATES; j++) {
280                         ts = tsc2timespec(pcpui->state_ticks[j]);
281                         len += snprintf(buf + len, bufsz - len, "%10d.%06d (%3d%%)%s",
282                                         ts.tv_sec, ts.tv_nsec / 1000,
283                                         MIN((pcpui->state_ticks[j] * 100) / cpu_total, 100),
284                                         j != NR_CPU_STATES - 1 ? ", " : " \n");
285                 }
286         }
287         n = readstr(off, va, n, buf);
288         kfree(buf);
289         return n;
290 }
291
292 static long mpstatraw_read(void *va, long n, int64_t off)
293 {
294         size_t bufsz = mpstatraw_len();
295         char *buf = kmalloc(bufsz, MEM_WAIT);
296         int len = 0;
297         struct per_cpu_info *pcpui;
298
299         /* could spit it all out in binary, though then it'd be harder to process
300          * the data across a mnt (if we export #K).  probably not a big deal. */
301
302         /* header line: version, num_cores, tsc freq, state names */
303         len += snprintf(buf + len, bufsz - len, "v%03d %5d %16llu", 1, num_cores,
304                         __proc_global_info.tsc_freq);
305         for (int j = 0; j < NR_CPU_STATES; j++)
306                 len += snprintf(buf + len, bufsz - len, " %6s", cpu_state_names[j]);
307         len += snprintf(buf + len, bufsz - len, "\n");
308
309         for (int i = 0; i < num_cores; i++) {
310                 pcpui = &per_cpu_info[i];
311                 len += snprintf(buf + len, bufsz - len, "%5d: ", i);
312                 for (int j = 0; j < NR_CPU_STATES; j++) {
313                         len += snprintf(buf + len, bufsz - len, "%16llx%s",
314                                         pcpui->state_ticks[j],
315                                         j != NR_CPU_STATES - 1 ? " " : "\n");
316                 }
317         }
318         n = readstr(off, va, n, buf);
319         kfree(buf);
320         return n;
321 }
322
323 static size_t kprof_read(struct chan *c, void *va, size_t n, off64_t off)
324 {
325         uint64_t w, *bp;
326         char *a, *ea;
327         uintptr_t offset = off;
328         uint64_t pc;
329
330         switch ((int) c->qid.path) {
331         case Kprofdirqid:
332                 return devdirread(c, va, n, kproftab, ARRAY_SIZE(kproftab), devgen);
333         case Kprofdataqid:
334                 n = kprof_profdata_read(va, n, off);
335                 break;
336         case Kptraceqid:
337                 n = kprof_tracedata_read(va, n, off);
338                 break;
339         case Kprintxqid:
340                 n = readstr(offset, va, n, printx_on ? "on" : "off");
341                 break;
342         case Kmpstatqid:
343                 n = mpstat_read(va, n, offset);
344                 break;
345         case Kmpstatrawqid:
346                 n = mpstatraw_read(va, n, offset);
347                 break;
348         default:
349                 n = 0;
350                 break;
351         }
352         return n;
353 }
354
355 static size_t kprof_write(struct chan *c, void *a, size_t n, off64_t unused)
356 {
357         ERRSTACK(1);
358         struct cmdbuf *cb = parsecmd(a, n);
359
360         if (waserror()) {
361                 kfree(cb);
362                 nexterror();
363         }
364         switch ((int) c->qid.path) {
365         case Kprofctlqid:
366                 if (cb->nf < 1)
367                         error(EFAIL, kprof_control_usage);
368                 if (profiler_configure(cb))
369                         break;
370                 if (!strcmp(cb->f[0], "start")) {
371                         kprof_start_profiler();
372                 } else if (!strcmp(cb->f[0], "flush")) {
373                         kprof_flush_profiler();
374                 } else if (!strcmp(cb->f[0], "stop")) {
375                         kprof_stop_profiler();
376                 } else {
377                         error(EFAIL, kprof_control_usage);
378                 }
379                 break;
380         case Kptracectlqid:
381                 if (cb->nf < 1)
382                         error(EFAIL, "Bad kptrace_ctl option (reset)");
383                 if (!strcmp(cb->f[0], "clear")) {
384                         spin_lock_irqsave(&ktrace_lock);
385                         circular_buffer_clear(&ktrace_data);
386                         spin_unlock_irqsave(&ktrace_lock);
387                 }
388                 break;
389         case Kptraceqid:
390                 if (a && (n > 0)) {
391                         char *uptr = user_strdup_errno(current, a, n);
392
393                         if (uptr) {
394                                 trace_printk("%s", uptr);
395                                 user_memdup_free(current, uptr);
396                         } else {
397                                 n = -1;
398                         }
399                 }
400                 break;
401         case Kprintxqid:
402                 if (!strncmp(a, "on", 2))
403                         set_printx(1);
404                 else if (!strncmp(a, "off", 3))
405                         set_printx(0);
406                 else if (!strncmp(a, "toggle", 6))
407                         set_printx(2);
408                 else
409                         error(EFAIL, "Invalid option to Kprintx %s\n", a);
410                 break;
411         case Kmpstatqid:
412         case Kmpstatrawqid:
413                 if (cb->nf < 1)
414                         error(EFAIL, "Bad mpstat option (reset|ipi|on|off)");
415                 if (!strcmp(cb->f[0], "reset")) {
416                         for (int i = 0; i < num_cores; i++)
417                                 reset_cpu_state_ticks(i);
418                 } else if (!strcmp(cb->f[0], "on")) {
419                         /* TODO: enable the ticks */ ;
420                 } else if (!strcmp(cb->f[0], "off")) {
421                         /* TODO: disable the ticks */ ;
422                 } else if (!strcmp(cb->f[0], "ipi")) {
423                         if (cb->nf < 2)
424                                 error(EFAIL, "Need another arg: ipi [on|off]");
425                         if (!strcmp(cb->f[1], "on"))
426                                 kprof.mpstat_ipi = TRUE;
427                         else if (!strcmp(cb->f[1], "off"))
428                                 kprof.mpstat_ipi = FALSE;
429                         else
430                                 error(EFAIL, "ipi [on|off]");
431                 } else {
432                         error(EFAIL, "Bad mpstat option (reset|ipi|on|off)");
433                 }
434                 break;
435         default:
436                 error(EBADFD, ERROR_FIXME);
437         }
438         kfree(cb);
439         poperror();
440         return n;
441 }
442
443 size_t kprof_tracedata_size(void)
444 {
445         return circular_buffer_size(&ktrace_data);
446 }
447
448 size_t kprof_tracedata_read(void *data, size_t size, size_t offset)
449 {
450         spin_lock_irqsave(&ktrace_lock);
451         if (likely(ktrace_init_done))
452                 size = circular_buffer_read(&ktrace_data, data, size, offset);
453         else
454                 size = 0;
455         spin_unlock_irqsave(&ktrace_lock);
456
457         return size;
458 }
459
460 void kprof_dump_data(void)
461 {
462         void *buf;
463         size_t len = kprof_tracedata_size();
464
465         buf = kmalloc(len, MEM_WAIT);
466         kprof_tracedata_read(buf, len, 0);
467         printk("%s", buf);
468         kfree(buf);
469 }
470
471 void kprof_tracedata_write(const char *pretty_buf, size_t len)
472 {
473         spin_lock_irqsave(&ktrace_lock);
474         if (unlikely(!ktrace_init_done)) {
475                 circular_buffer_init(&ktrace_data, sizeof(ktrace_buffer),
476                                      ktrace_buffer);
477                 ktrace_init_done = TRUE;
478         }
479         circular_buffer_write(&ktrace_data, pretty_buf, len);
480         spin_unlock_irqsave(&ktrace_lock);
481 }
482
483 static struct trace_printk_buffer *kprof_get_printk_buffer(void)
484 {
485         static struct trace_printk_buffer boot_tpb;
486         static struct trace_printk_buffer *cpu_tpbs;
487         static atomic_t alloc_done;
488
489         if (unlikely(booting))
490                 return &boot_tpb;
491         if (unlikely(!cpu_tpbs)) {
492                 /* Poor man per-CPU data structure. I really do no like littering global
493                  * data structures with module specific data.
494                  * We cannot take the ktrace_lock to protect the kzmalloc() call, as
495                  * that might trigger printk()s, and we would reenter here.
496                  * Let only one core into the kzmalloc() path, and let the others get
497                  * the boot_tpb until finished.
498                  */
499                 if (!atomic_cas(&alloc_done, 0, 1))
500                         return &boot_tpb;
501                 cpu_tpbs = kzmalloc(num_cores * sizeof(struct trace_printk_buffer), 0);
502         }
503
504         return cpu_tpbs + core_id_early();
505 }
506
507 void trace_vprintk(const char *fmt, va_list args)
508 {
509         struct print_buf {
510                 char *ptr;
511                 char *top;
512         };
513
514         void emit_print_buf_str(struct print_buf *pb, const char *str, ssize_t size)
515         {
516                 if (size < 0) {
517                         for (; *str && (pb->ptr < pb->top); str++)
518                                 *(pb->ptr++) = *str;
519                 } else {
520                         for (; (size > 0) && (pb->ptr < pb->top); str++, size--)
521                                 *(pb->ptr++) = *str;
522                 }
523         }
524
525         static const size_t bufsz = TRACE_PRINTK_BUFFER_SIZE;
526         static const size_t usr_bufsz = (3 * bufsz) / 8;
527         static const size_t kp_bufsz = bufsz - usr_bufsz;
528         struct trace_printk_buffer *tpb = kprof_get_printk_buffer();
529         struct timespec ts_now = { 0, 0 };
530         struct print_buf pb;
531         char *usrbuf = tpb->buffer, *kpbuf = tpb->buffer + usr_bufsz;
532         const char *utop, *uptr;
533         char hdr[64];
534
535         if (!atomic_cas(&tpb->in_use, 0, 1))
536                 return;
537         if (likely(__proc_global_info.tsc_freq))
538                 ts_now = tsc2timespec(read_tsc());
539         snprintf(hdr, sizeof(hdr), "[%lu.%09lu]:cpu%d: ", ts_now.tv_sec,
540                  ts_now.tv_nsec, core_id_early());
541
542         pb.ptr = usrbuf + vsnprintf(usrbuf, usr_bufsz, fmt, args);
543         pb.top = usrbuf + usr_bufsz;
544
545         if (pb.ptr[-1] != '\n')
546                 emit_print_buf_str(&pb, "\n", 1);
547         /* snprintf null terminates the buffer, and does not count that as part of
548          * the len.  If we maxed out the buffer, let's make sure it has a \n.
549          */
550         if (pb.ptr == pb.top)
551                 pb.ptr[-1] = '\n';
552         utop = pb.ptr;
553
554         pb.ptr = kpbuf;
555         pb.top = kpbuf + kp_bufsz;
556         for (uptr = usrbuf; uptr < utop;) {
557                 const char *nlptr = memchr(uptr, '\n', utop - uptr);
558
559                 if (nlptr == NULL)
560                         nlptr = utop;
561                 emit_print_buf_str(&pb, hdr, -1);
562                 emit_print_buf_str(&pb, uptr, (nlptr - uptr) + 1);
563                 uptr = nlptr + 1;
564         }
565         kprof_tracedata_write(kpbuf, pb.ptr - kpbuf);
566         atomic_set(&tpb->in_use, 0);
567 }
568
569 void trace_printk(const char *fmt, ...)
570 {
571         va_list args;
572
573         va_start(args, fmt);
574         trace_vprintk(fmt, args);
575         va_end(args);
576 }
577
578 struct dev kprofdevtab __devtab = {
579         .name = "kprof",
580
581         .reset = devreset,
582         .init = kprof_init,
583         .shutdown = kprof_shutdown,
584         .attach = kprof_attach,
585         .walk = kprof_walk,
586         .stat = kprof_stat,
587         .open = kprof_open,
588         .create = devcreate,
589         .close = kprof_close,
590         .read = kprof_read,
591         .bread = devbread,
592         .write = kprof_write,
593         .bwrite = devbwrite,
594         .remove = devremove,
595         .wstat = devwstat,
596 };