| Index: collector.c
|
| diff --git a/collector.c b/collector.c
|
| index 46ffd5a90d80aece4402630e0d18de3d32f1d14d..cb58005122a100006a90308febac5cf08404e806 100644
|
| --- a/collector.c
|
| +++ b/collector.c
|
| @@ -13,51 +13,20 @@
|
| #include <sys/stat.h>
|
| #include <fcntl.h>
|
|
|
| +#include <debug.h>
|
| #include <eprintf.h>
|
| +#include <mylib.h>
|
| #include <style.h>
|
|
|
| -#include "syscall.h"
|
| +#include "collector.h"
|
| #include "ktop.h"
|
| +#include "syscall.h"
|
|
|
| #define _STR(x) #x
|
| #define STR(x) _STR(x)
|
| #define MAX_PATH 256
|
|
|
| -enum { BUF_SIZE = 1 << 12,
|
| - SMALL_READ = BUF_SIZE >> 2 };
|
| -
|
| -typedef struct ring_header_s {
|
| - u64 time_stamp;
|
| - unint commit;
|
| - u8 data[];
|
| -} ring_header_s;
|
| -
|
| -typedef struct ring_event_s {
|
| - u32 type_len : 5,
|
| - time_delta : 27;
|
| - u32 array[];
|
| -} ring_event_s;
|
| -
|
| -typedef struct event_s {
|
| - u16 type;
|
| - u8 flags;
|
| - u8 preempt_count;
|
| - s32 pid;
|
| - s32 lock_depth;
|
| -} event_s;
|
| -
|
| -typedef struct sys_enter_s {
|
| - event_s ev;
|
| - snint id;
|
| - unint args[6];
|
| -} sys_enter_s;
|
| -
|
| -typedef struct sys_exit_s {
|
| - event_s ev;
|
| - snint id;
|
| - snint ret;
|
| -} sys_exit_s;
|
| -
|
| +enum { PIDCALL_BUCKETS = 1543 };
|
|
|
| pthread_mutex_t Count_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
| @@ -66,6 +35,19 @@ u64 MyPidCount;
|
| u64 Slept;
|
| int Pid[MAX_PID];
|
|
|
| +Pidcall_s Pidcall[MAX_PIDCALLS];
|
| +Pidcall_s *Pidclock = Pidcall;
|
| +u64 PidcallIterations;
|
| +u64 PidcallRecord;
|
| +u64 Pidcall_tick;
|
| +
|
| +u64 No_enter;
|
| +u64 Found;
|
| +u64 Out_of_order;
|
| +u64 No_start;
|
| +
|
| +Pidcall_s *Pidcall_bucket[PIDCALL_BUCKETS];
|
| +
|
| static const char *find_debugfs(void)
|
| {
|
| static char debugfs[MAX_PATH+1];
|
| @@ -169,7 +151,7 @@ static void disable_sys_exit (void)
|
| disable_event("sys_exit");
|
| }
|
|
|
| -static int init_raw(int cpu)
|
| +int open_raw(int cpu)
|
| {
|
| char name[MAX_NAME];
|
| int fd;
|
| @@ -182,50 +164,98 @@ static int init_raw(int cpu)
|
| return fd;
|
| }
|
|
|
| -Pidcall_s Pidcall[MAX_PIDCALLS];
|
| -Pidcall_s *Pidnext = Pidcall;
|
| +static Pidcall_s *hash_pidcall(u32 pidcall)
|
| +{
|
| + return (Pidcall_s *)&Pidcall_bucket[pidcall % PIDCALL_BUCKETS];
|
| +}
|
|
|
| -static inline void swap_pidcall(Pidcall_s *p)
|
| +static Pidcall_s *find_pidcall(u32 pidcall)
|
| {
|
| - Pidcall_s tmp;
|
| + Pidcall_s *pc = hash_pidcall(pidcall);
|
| +
|
| +++PidcallRecord;
|
| + for (;;) {
|
| +++PidcallIterations;
|
| + pc = pc->next;
|
| + if (!pc) return NULL;
|
| + if (pc->pidcall == pidcall) {
|
| + pc->clock = 1;
|
| + return pc;
|
| + }
|
| + }
|
| +}
|
|
|
| - if (p == Pidcall) return;
|
| - tmp = *p;
|
| - *p = p[-1];
|
| - p[-1] = tmp;
|
| +#if 0
|
| +static void dump(char *label, Pidcall_s *pc)
|
| +{
|
| + int i;
|
| +
|
| + fprintf(stderr, "%s", label);
|
| + for (i = 0; (i < 10) && pc; i++) {
|
| + fprintf(stderr, " %p", pc);
|
| + pc = pc->next;
|
| + }
|
| + if (pc) fprintf(stderr, "STUCK");
|
| + fprintf(stderr, "\n");
|
| }
|
| +#endif
|
|
|
| -void record_pid_syscall (u32 pidcall)
|
| +static void add_pidcall(Pidcall_s *pidcall)
|
| {
|
| - Pidcall_s *p;
|
| + Pidcall_s *pc = hash_pidcall(pidcall->pidcall);
|
| +
|
| + pidcall->next = pc->next;
|
| + pc->next = pidcall;
|
| +}
|
|
|
| - for (p = Pidcall; p < Pidnext; p++) {
|
| - if (p->pidcall == pidcall) {
|
| - ++p->count;
|
| - swap_pidcall(p);
|
| +static void rmv_pidcall(u32 pidcall)
|
| +{
|
| + Pidcall_s *prev = hash_pidcall(pidcall);
|
| + Pidcall_s *next;
|
| +
|
| + for (;;) {
|
| + next = prev->next;
|
| + if (!next) return;
|
| + if (next->pidcall == pidcall) {
|
| + prev->next = next->next;
|
| return;
|
| }
|
| + prev = next;
|
| }
|
| - if (Pidnext == &Pidcall[MAX_PIDCALLS]) {
|
| - /*
|
| - * Need a better method but this might be good enough
|
| - */
|
| - --p;
|
| - p->pidcall = pidcall;
|
| - p->count = 1;
|
| - swap_pidcall(p);
|
| - return;
|
| +}
|
| +
|
| +static Pidcall_s *victim_pidcall(u32 pidcall)
|
| +{
|
| + Pidcall_s *pc = Pidclock;
|
| +
|
| + while (pc->clock) {
|
| +++Pidcall_tick;
|
| + pc->clock = 0;
|
| + if (++Pidclock == &Pidcall[MAX_PIDCALLS]) {
|
| + Pidclock = Pidcall;
|
| + }
|
| + pc = Pidclock;
|
| + }
|
| + if (pc->pidcall) {
|
| + rmv_pidcall(pc->pidcall);
|
| }
|
| - p = Pidnext++;
|
| - p->pidcall = pidcall;
|
| - p->count = 1;
|
| + if (pc->name) {
|
| + free(pc->name);
|
| + }
|
| + zero(*pc);
|
| + pc->pidcall = pidcall;
|
| + add_pidcall(pc);
|
| +
|
| + return pc;
|
| }
|
|
|
| -static void process_sys_enter(void *event)
|
| +static void parse_sys_enter(void *event, u64 time)
|
| {
|
| sys_enter_s *sy = event;
|
| - int pid = sy->ev.pid;
|
| - snint call_num = sy->id;
|
| + int pid = sy->ev.pid;
|
| + snint call_num = sy->id;
|
| + u32 pidcall = mkpidcall(pid, call_num);
|
| + Pidcall_s *pc;
|
|
|
| ++Pid[pid];
|
|
|
| @@ -234,15 +264,43 @@ static void process_sys_enter(void *event)
|
| return;
|
| }
|
| ++Syscall_count[call_num];
|
| - record_pid_syscall(mkpidcall(pid, call_num));
|
| +
|
| + pc = find_pidcall(pidcall);
|
| + if (!pc) {
|
| + pc = victim_pidcall(pidcall);
|
| + }
|
| + ++pc->count;
|
| + pc->time.start = time;
|
| + memmove(pc->arg, sy->arg, sizeof(pc->arg));
|
| }
|
|
|
| -static void process_sys_exit(void *event)
|
| +static void parse_sys_exit(void *event, u64 time)
|
| {
|
| -// sys_exit_s *sy = event;
|
| + sys_exit_s *sy = event;
|
| + int pid = sy->ev.pid;
|
| + snint call_num = sy->id;
|
| + u32 pidcall = mkpidcall(pid, call_num);
|
| + Pidcall_s *pc;
|
| +
|
| + pc = find_pidcall(pidcall);
|
| + if (!pc) {
|
| + ++No_enter;
|
| + return;
|
| + }
|
| + if (pc->time.start) {
|
| + if (time > pc->time.start) {
|
| + ++Found;
|
| + pc->time.total += time - pc->time.start;
|
| + } else {
|
| + ++Out_of_order;
|
| + }
|
| + pc->time.start = 0;
|
| + } else {
|
| + ++No_start;
|
| + }
|
| }
|
|
|
| -static void process_event(void *buf)
|
| +static void parse_event(void *buf, u64 time)
|
| {
|
| event_s *event = buf;
|
|
|
| @@ -259,10 +317,10 @@ static void process_event(void *buf)
|
| }
|
| switch (event->type) {
|
| case 21:
|
| - process_sys_exit(event);
|
| + parse_sys_exit(event, time);
|
| break;
|
| case 22:
|
| - process_sys_enter(event);
|
| + parse_sys_enter(event, time);
|
| break;
|
| default:
|
| //printf(" no processing\n");
|
| @@ -270,7 +328,7 @@ static void process_event(void *buf)
|
| }
|
| }
|
|
|
| -static unint process_buf(u8 *buf)
|
| +static unint parse_buf(u8 *buf)
|
| {
|
| ring_header_s *rh = (ring_header_s *)buf;
|
| ring_event_s *r;
|
| @@ -297,7 +355,7 @@ static unint process_buf(u8 *buf)
|
| length = r->type_len;
|
| size = 4 + length * 4;
|
| time += r->time_delta;
|
| - process_event(buf+4);
|
| + parse_event(buf+4, time);
|
| } else if (r->type_len == 29) {
|
| /* Left over page padding or discarded event */
|
| if (r->time_delta == 0) {
|
| @@ -312,8 +370,8 @@ static unint process_buf(u8 *buf)
|
| time += (((u64)r->array[0]) << 28) | r->time_delta;
|
| } else if (r->type_len == 31) {
|
| /* Sync time with external clock (NOT IMMPLEMENTED) */
|
| - //tv_nsec = r->array[0];
|
| - //tv_sec = *(u64 *)&(r->array[1]);
|
| + time = r->array[0];
|
| + time += *(u64 *)&(r->array[1]) * A_BILLION;
|
| } else {
|
| warn(" Unknown event %d", r->type_len);
|
| /* Unknown - ignore */
|
| @@ -325,129 +383,6 @@ done:
|
| return commit;
|
| }
|
|
|
| -void pr_buf(int cpu, int sz, u8 buf[sz])
|
| -{
|
| - int i;
|
| - int j;
|
| -
|
| - printf("%d. trace=%d bytes\n", cpu, sz);
|
| - for (i = 0; i < sz; i++) {
|
| - for (j = 0; j < 32; j++, i++) {
|
| - if (i == sz) goto done;
|
| - printf(" %2x", buf[i]);
|
| - }
|
| - printf("\n");
|
| - }
|
| -done:
|
| - printf("\n");
|
| -}
|
| -
|
| -static void pr_event(event_s *event)
|
| -{
|
| - printf(" type=%2u flags=%2x cnt=%2d pid=%5d lock=%2d",
|
| - event->type, event->flags, event->preempt_count, event->pid,
|
| - event->lock_depth);
|
| -}
|
| -
|
| -static void pr_sys_enter(void *event)
|
| -{
|
| - sys_enter_s *sy = event;
|
| - int i;
|
| -
|
| - printf(" %-20s", Syscall[sy->id]);
|
| - for (i = 0; i < 6; i++) {
|
| - printf(" %ld", sy->args[i]);
|
| - }
|
| - printf("\n");
|
| -}
|
| -
|
| -static void pr_sys_exit(void *event)
|
| -{
|
| - sys_exit_s *sy = event;
|
| -
|
| - printf(" %-20s ret=%ld\n", Syscall[sy->id], sy->ret);
|
| -}
|
| -
|
| -static void pr_ring_header(ring_header_s *rh)
|
| -{
|
| - printf("%lld %lld %ld\n",
|
| - rh->time_stamp / A_BILLION, rh->time_stamp % A_BILLION,
|
| - rh->commit);
|
| -}
|
| -
|
| -static void dump_event(void *buf)
|
| -{
|
| - event_s *event = buf;
|
| -
|
| - pr_event(event);
|
| - switch (event->type) {
|
| - case 21:
|
| - pr_sys_exit(event);
|
| - break;
|
| - case 22:
|
| - pr_sys_enter(event);
|
| - break;
|
| - default:
|
| - printf(" no processing\n");
|
| - break;
|
| - }
|
| -}
|
| -
|
| -static void dump_buf(u8 *buf)
|
| -{
|
| - ring_header_s *rh = (ring_header_s *)buf;
|
| - ring_event_s *r;
|
| - unint length;
|
| - unint size;
|
| - u64 time;
|
| - u8 *end;
|
| -
|
| - pr_ring_header(rh);
|
| - time = rh->time_stamp;
|
| - buf += sizeof(*rh);
|
| - end = &buf[rh->commit];
|
| - for (; buf < end; buf += size) {
|
| - r = (ring_event_s *)buf;
|
| - printf("type_len=%2u time=%9d", r->type_len, r->time_delta);
|
| - if (r->type_len == 0) {
|
| - length = r->array[0];
|
| - size = 4 + length * 4;
|
| - time += r->time_delta;
|
| - } else if (r->type_len <= 28) {
|
| - length = r->type_len;
|
| - size = 4 + length * 4;
|
| - time += r->time_delta;
|
| - dump_event(buf+4);
|
| - } else if (r->type_len == 29) {
|
| - printf("\n");
|
| - if (r->time_delta == 0) {
|
| - return;
|
| - } else {
|
| - length = r->array[0];
|
| - size = 4 + length * 4;
|
| - }
|
| - } else if (r->type_len == 30) {
|
| - /* Extended time delta */
|
| - printf("\n");
|
| - size = 8;
|
| - time += (((u64)r->array[0]) << 28) | r->time_delta;
|
| - } else if (r->type_len == 31) {
|
| - /* Sync time with external clock (NOT IMMPLEMENTED) */
|
| - //tv_nsec = r->array[0];
|
| - //tv_sec = *(u64 *)&(r->array[1]);
|
| - } else {
|
| - printf(" Unknown event %d\n", r->type_len);
|
| - /* Unknown - ignore */
|
| - size = 4;
|
| - }
|
| - }
|
| -}
|
| -
|
| -static void dump_raw(int cpu, int sz, u8 buf[sz])
|
| -{
|
| - dump_buf(buf); // Need to do something with sz
|
| -}
|
| -
|
| void *collector(void *args)
|
| {
|
| Collector_args_s *a = args;
|
| @@ -463,45 +398,17 @@ void *collector(void *args)
|
| int i;
|
|
|
| ignore_pid(gettid());
|
| - trace_pipe = init_raw(cpu);
|
| + trace_pipe = open_raw(cpu);
|
| for (i = 0;; i++) {
|
| rc = read(trace_pipe, buf, sizeof(buf));
|
| if (rc == -1) {
|
| close(trace_pipe);
|
| cleanup(0);
|
| }
|
| - rc = process_buf(buf);
|
| + rc = parse_buf(buf);
|
| if (rc < SMALL_READ) {
|
| ++Slept;
|
| nanosleep(&sleep, NULL);
|
| - // sleep(1); // Wait for input to accumulate
|
| - }
|
| - }
|
| - return NULL;
|
| -}
|
| -
|
| -static void *dump_collector(void *args)
|
| -{
|
| - Collector_args_s *a = args;
|
| - u8 buf[BUF_SIZE];
|
| - int cpu = a->cpu_id;
|
| - int trace_pipe;
|
| - int rc;
|
| - int i;
|
| -
|
| - ignore_pid(gettid());
|
| - trace_pipe = init_raw(cpu);
|
| - for (i = 0;; i++) {
|
| - rc = read(trace_pipe, buf, sizeof(buf));
|
| - printf("i=%d rc=%d\n", i, rc);
|
| - if (rc == -1) {
|
| - close(trace_pipe);
|
| - cleanup(0);
|
| - }
|
| - dump_raw(cpu, rc, buf);
|
| - if (rc < SMALL_READ) {
|
| - ++Slept;
|
| - sleep(1); // Wait for input to accumulate
|
| }
|
| }
|
| return NULL;
|
|
|