static void kernel_syscall_entry_process(struct ltt_module *mod, struct parse_result *res, int pass) { unsigned int ip, id; kernel_common(res, pass); if (sscanf(res->values, " ip = 0x%x, syscall_id = %u", &ip, &id) != 2) { PARSE_ERROR(mod, res->values); return; } if (pass == 1) { atag_store(ip); } if (pass == 2) { struct ltt_trace *current_process; current_process = find_task_trace(res->pid); emit_trace(current_process, (union ltt_value)PROCESS_KERNEL); current_process->value = (union ltt_value)PROCESS_KERNEL; if (id < sizeof(syscall_name)/sizeof(syscall_name[0])) emit_trace(¤t_process[1], (union ltt_value)syscall_name[id]); else emit_trace(¤t_process[1], (union ltt_value)"syscall %d", id); emit_trace(&syscall_id, (union ltt_value)id); emit_trace(&syscall_pc, (union ltt_value)ip); } }
static void kernel_common(struct parse_result *res, int pass) { static char old_mode [15]; static double start_time; if (pass == 1) { init_traces(); find_or_add_task_trace(res->pname, res->pid, 0); } if (pass == 2) { if (strcmp(old_mode, res->mode)) emit_trace(&mode, (union ltt_value)res->mode); memcpy(old_mode, res->mode, sizeof(old_mode)); old_mode[sizeof(old_mode)-1] = 0; /* 300 ms average for cpu load */ if (res->clock - start_time > 0.3) { double idle_run = emit_cpu_idle_state(res, (union ltt_value)(char *)NULL); if (start_time > 0) { emit_trace(&cpu_load, (union ltt_value)(1.0-idle_run/(res->clock - start_time))); } start_time = res->clock; } } }
static void kernel_softirq_entry_process(struct ltt_module *mod, struct parse_result *res, int pass) { int id; char *s; kernel_common(res, pass); if (sscanf(res->values, " softirq_id = %d [%m[^]]", &id, &s) != 2) { PARSE_ERROR(mod, res->values); return; } if (pass == 2) { emit_trace(&sirq[0], (union ltt_value)SOFTIRQ_RUNNING); emit_cpu_idle_state(res, (union ltt_value)IDLE_CPU_PREEMPT); if (id < sizeof(sofirq_tag)/sizeof(char *) && sofirq_tag[id]) emit_trace(&sirq[1], (union ltt_value)sofirq_tag[id]); else emit_trace(&sirq[1], (union ltt_value)"softirq %d", id); emit_trace(&sirq[2], (union ltt_value)s); softirqstate = SOFTIRQS_RUN; /* stat stuff */ strncpy(softirqtask, s, sizeof(softirqtask)); softirqtask[sizeof(softirqtask)-1] = 0; softirqtime = res->clock; /* end stat stuff */ } free(s); }
static void kernel_page_fault_get_user_exit_process(struct ltt_module *mod, struct parse_result *res, int pass) { if (pass == 1) { init_traces(); } if (pass == 2) { emit_trace(&trace_fault[2], (union ltt_value)LT_IDLE); } }
static void kernel_tasklet_low_exit_process(struct ltt_module *mod, struct parse_result *res, int pass) { kernel_common(res, pass); if (pass == 1) { } if (pass == 2) { emit_trace(&tlow[0], (union ltt_value)LT_IDLE); } }
static void kernel_sched_try_wakeup_process(struct ltt_module *mod, struct parse_result *res, int pass) { unsigned int pid, cpu_id, state; kernel_common(res, pass); if (sscanf(res->values, " pid = %u, cpu_id = %u, state = %u", &pid, &cpu_id, &state) != 3) { PARSE_ERROR(mod, res->values); return; } if (pass == 2) { emit_trace(&sched_event, (union ltt_value)"%d try wakeup %d", res->pid, pid); if (res->pid != pid) { struct ltt_trace *next_process; next_process = find_task_trace(pid); emit_trace(next_process, (union ltt_value)PROCESS_WAKEUP); } } }
static void kernel_page_fault_exit_process(struct ltt_module *mod, struct parse_result *res, int pass) { int fault; if (pass == 1) { init_traces(); } if (sscanf(res->values, " res = %d", &fault) != 1) { PARSE_ERROR(mod, res->values); return; } if (pass == 2) { emit_trace(&trace_fault[0], (union ltt_value)LT_IDLE); emit_trace(&trace_fault[1], (union ltt_value)"-> %d", fault); } }
static void kernel_page_fault_get_user_entry_process(struct ltt_module *mod, struct parse_result *res, int pass) { int wr; unsigned long long address; if (pass == 1) { init_traces(); } if (sscanf(res->values, " address = %llx, write_access = %d", &address, &wr) != 2) { PARSE_ERROR(mod, res->values); return; } if (pass == 2) { emit_trace(&trace_fault[2], (union ltt_value)(wr?LT_S2:LT_S0)); emit_trace(&trace_fault[3], (union ltt_value)"%c@0x%08x", (wr)? 'W' : 'R', (uint32_t)address); } }
static void kernel_softirq_raise_process(struct ltt_module *mod, struct parse_result *res, int pass) { int id; kernel_common(res, pass); if (sscanf(res->values, " softirq_id = %d", &id) != 1) { PARSE_ERROR(mod, res->values); return; } if (pass == 2) { if (softirqstate == SOFTIRQS_IDLE) emit_trace(&sirq[0], (union ltt_value)SOFTIRQ_RAISING); if (id < sizeof(sofirq_tag)/sizeof(char *) && sofirq_tag[id]) emit_trace(&sirq[1], (union ltt_value)"! %s", sofirq_tag[id]); else emit_trace(&sirq[1], (union ltt_value)"raise %d", id); softirqstate = SOFTIRQS_RAISE; } }
static void kernel_irq_exit_process(struct ltt_module *mod, struct parse_result *res, int pass) { kernel_common(res, pass); if ((pass == 2) && (irqlevel > 0)) { emit_trace(&trace[irqtab[--irqlevel]], (union ltt_value)IRQ_IDLE); if (irqlevel > 0) { emit_trace(&trace[irqtab[irqlevel-1]], (union ltt_value)IRQ_RUNNING); } if (irqlevel == 0 && idle_cpu_state == IDLE_RUNNING) emit_cpu_idle_state(res, (union ltt_value)IDLE_CPU_RUNNING); else emit_cpu_idle_state(res, (union ltt_value)IDLE_CPU_IDLE); /* stat stuff */ /* we allow up to 0.1ms irq */ if (irqlevel == 0 && res->clock - irqtime > 0.0001) TDIAG(res, "long irq (%s) : %fs!!!\n", irq_tag[irqtab[0]], res->clock - irqtime); /* end stat stuff */ } }
static void kernel_syscall_exit_process(struct ltt_module *mod, struct parse_result *res, int pass) { int ret; kernel_common(res, pass); if (sscanf(res->values, " ret = %d", &ret) != 1) { PARSE_ERROR(mod, res->values); return; } if (pass == 2) { struct ltt_trace *current_process; current_process = find_task_trace(res->pid); emit_trace(current_process, (union ltt_value)PROCESS_USER); current_process->value = (union ltt_value)PROCESS_USER; /* ret is not valid ... */ emit_trace(¤t_process[1], (union ltt_value)"->%d", ret); } }
static void kernel_page_fault_entry_process(struct ltt_module *mod, struct parse_result *res, int pass) { int wr; unsigned long ip; unsigned long address; if (pass == 1) { init_traces(); } if (sscanf(res->values, " ip = %lx, address = %lx, trap_id = 14, write_access = %d", &ip, &address, &wr) != 3) { PARSE_ERROR(mod, res->values); return; } if (pass == 2) { emit_trace(&trace_fault[0], (union ltt_value)(wr?LT_S2:LT_S0)); emit_trace(&trace_fault[1], (union ltt_value)"0x%08x@%c0x%08x", ip, (wr)? 'W' : 'R', (uint32_t)address); } }
static void userspace_message_process(const char *modname, int pass, double clock, int cpu, void *args) { const char * str = get_arg_str(args, "message"); if (pass == 1) init_trace(&trace_g, TG_PROCESS, 0.1, TRACE_SYM_F_STRING, "user event"); if (pass == 2) emit_trace(&trace_g, (union ltt_value)"%s", str); }
static void kernel_softirq_exit_process(struct ltt_module *mod, struct parse_result *res, int pass) { kernel_common(res, pass); if (pass == 2) { if (softirqstate == SOFTIRQS_RAISE) emit_trace(&sirq[0], (union ltt_value)SOFTIRQ_RAISING); else emit_trace(&sirq[0], (union ltt_value)SOFTIRQ_IDLE); if (idle_cpu_state == IDLE_RUNNING) emit_cpu_idle_state(res, (union ltt_value)IDLE_CPU_RUNNING); else emit_cpu_idle_state(res, (union ltt_value)IDLE_CPU_IDLE); softirqstate = SOFTIRQS_IDLE; /* stat stuff */ /* we allow up to 0.7ms softirq */ if (res->clock - softirqtime > 0.0007) TDIAG(res, "long softirq(%s) : %fs!!!\n", softirqtask, res->clock - softirqtime); /* end stat stuff */ } }
static void kernel_parrot_evt_stop_process(struct ltt_module *mod, struct parse_result *res, int pass) { int id; kernel_common(res, pass); if (sscanf(res->values, " id = %d", &id) != 1) { PARSE_ERROR(mod, res->values); return; } if (pass == 1) { init_traces(); if (id < sizeof(parrot_evt_n)/sizeof(parrot_evt_n[0]) && id >= 0) init_trace(&parrot_evt_n[id], TG_PROCESS, 0.0+0.1*id, TRACE_SYM_F_BITS, "kernel event %d", id); } if (pass == 2) { emit_trace(&parrot_evt, (union ltt_value)"%d->", id); if (id < sizeof(parrot_evt_n)/sizeof(parrot_evt_n[0]) && id >= 0) emit_trace(&parrot_evt_n[id], (union ltt_value)LT_IDLE); } }
static void kernel_tasklet_low_entry_process(struct ltt_module *mod, struct parse_result *res, int pass) { unsigned int data, func; kernel_common(res, pass); if (sscanf(res->values, " func = 0x%x, data = %u", &func, &data) != 2) { PARSE_ERROR(mod, res->values); return; } if (pass == 1) { atag_store(func); } if (pass == 2) { emit_trace(&tlow[0], (union ltt_value)LT_S0); emit_trace(&tlow[1], (union ltt_value)func); if (atag_enabled) { strncpy(softirqtask, atag_get(func), sizeof(softirqtask)); softirqtask[sizeof(softirqtask)-1] = 0; } } }
static void kernel_sched_schedule_process(struct ltt_module *mod, struct parse_result *res, int pass) { unsigned int prev_pid, next_pid, prev_state; kernel_common(res, pass); if (sscanf(res->values, " prev_pid = %u, next_pid = %u, prev_state = %u", &prev_pid, &next_pid, &prev_state) != 3) { PARSE_ERROR(mod, res->values); return; } if (pass == 2) { struct ltt_trace *current_process; current_process = find_task_trace(prev_pid); emit_trace(current_process,(union ltt_value)PROCESS_IDLE); if (prev_pid == 0) { emit_cpu_idle_state(res, (union ltt_value)IDLE_CPU_IDLE); idle_cpu_state = IDLE_IDLE; } current_process = find_task_trace(next_pid); /* XXX this is often buggy : some process are in SYCALL mode while running in userspace ... */ if(current_process->value.state) emit_trace(current_process, current_process->value); else if (strcmp(res->mode, "USER_MODE") == 0) emit_trace(current_process, (union ltt_value)PROCESS_USER); else emit_trace(current_process, (union ltt_value)PROCESS_KERNEL); if (next_pid == 0) { emit_cpu_idle_state(res, (union ltt_value)IDLE_CPU_RUNNING); idle_cpu_state = IDLE_RUNNING; } } }
static void kernel_sched_wakeup_new_task_process(struct ltt_module *mod, struct parse_result *res, int pass) { unsigned int pid, cpu_id, state; kernel_common(res, pass); if (sscanf(res->values, " pid = %u, state = %u, cpu_id = %u", &pid, &state, &cpu_id) != 3) { PARSE_ERROR(mod, res->values); return; } if (pass == 2) { emit_trace(&sched_event, (union ltt_value)"new task %d", pid); } }
static void kernel_send_signal_process(struct ltt_module *mod, struct parse_result *res, int pass) { unsigned int pid, signal; kernel_common(res, pass); if (sscanf(res->values, " pid = %u, signal = %u", &pid, &signal) != 2) { PARSE_ERROR(mod, res->values); return; } if (pass == 2) { emit_trace(&sched_event, (union ltt_value)"%d send signal %d to pid %d", res->pid, signal, pid); } }
static void userspace_event_stop_process(const char *modname, int pass, double clock, int cpu, void *args) { int num = (int)get_arg_i64(args, "event_stop"); if (pass == 1) { if (num < (int)(sizeof(traces)/sizeof(traces[0])) && num >= 0) init_trace(&traces[num], TG_PROCESS, 0.1+0.1*num, TRACE_SYM_F_BITS, "user event %d", num); } if (pass == 2) { if (num < (int)(sizeof(traces)/sizeof(traces[0])) && num >= 0) { emit_trace(&traces[num], (union ltt_value)LT_IDLE); } } }
static void kernel_process_free_process(struct ltt_module *mod, struct parse_result *res, int pass) { int pid; kernel_common(res, pass); if (sscanf(res->values, " pid = %d", &pid) != 1) { PARSE_ERROR(mod, res->values); return; } if (pass == 2) { struct ltt_trace *current_process; current_process = find_task_trace(pid); emit_trace(current_process, (union ltt_value)PROCESS_DEAD); } }
static void ardupilot_end_process(const char *modname, int pass, double clock, int cpu, void *args) { const char *name = get_arg_str(args, "name_field"); struct perf_apm *perf = find_or_add_perf(name); if (pass == 1) { init_trace(&perf->trace, TG_APM, 1 + 0.1 * perf->pos, TRACE_SYM_F_BITS, "%s", name); } if (pass == 2) { emit_trace(&perf->trace, (union ltt_value)LT_IDLE); } }
static void kernel_timer_update_time_process(struct ltt_module *mod, struct parse_result *res, int pass) { unsigned int c_jiffies; unsigned long long c_jiffies64; kernel_common(res, pass); if (sscanf(res->values, " jiffies = %llu", &c_jiffies64) != 1) { PARSE_ERROR(mod, res->values); return; } c_jiffies = c_jiffies64 & 0xffffffff; if (pass == 2) { static unsigned int old_jiffies; static double jiffies_clock; static double jiffies_diff; if (old_jiffies && old_jiffies+1 != c_jiffies) TDIAG(res, "missing jiffies jump from %x to %x (broken trace ?)\n", old_jiffies, c_jiffies); if (jiffies_clock > 0) { double diff = res->clock - jiffies_clock; if (jiffies_diff > 0) { /* we allow a jitter of 0,1 ms */ if (diff > jiffies_diff + 0.0001 || diff < jiffies_diff - 0.0001) { TDIAG(res, "unstable jiffies for %x took %fs (instead of %fs)\n", old_jiffies, diff, jiffies_diff); } } else { jiffies_diff = diff; TDIAG(res, "set jiffies times to %fs\n", jiffies_diff); } } jiffies_clock = res->clock; old_jiffies = c_jiffies; emit_trace(&jiffies, (union ltt_value)c_jiffies); } }
static void kernel_printk_process(struct ltt_module *mod, struct parse_result *res, int pass) { unsigned int ip; kernel_common(res, pass); if (sscanf(res->values, " ip = 0x%x", &ip) != 1) { PARSE_ERROR(mod, res->values); return; } if (pass == 1) { atag_store(ip); } if (pass == 2) { emit_trace(&printk_pc, (union ltt_value)ip); } }
static double emit_cpu_idle_state(struct parse_result *res, union ltt_value val) { static double run_start; static double total_run; double ret; if (val.state) { emit_trace(&idle_cpu, val); //printf("clock %f %s start %f total %f\n", res->clock, val.state, run_start, total_run); /* if running account the time */ if (strcmp(val.state, IRQ_RUNNING) == 0) { /* if already started, do nothing */ if (run_start == 0) run_start = res->clock; } /* if stoping record the idle time */ else { /* if already stop, do nothing */ if (run_start > 0) { total_run += res->clock - run_start; run_start = 0; } } //printf("%s start %f total %f\n", val.state, run_start, total_run); ret = total_run; } /* give the total idle time and reset counter */ else { /* idle is running */ if (run_start > 0) { total_run += res->clock - run_start; run_start = res->clock; } ret = total_run; /* reset counter */ total_run = 0; //printf("total clock : %f ret : %f\n", res->clock, ret); } return ret; }
static void task_state_process_state_process(struct ltt_module *mod, struct parse_result *res, int pass) { char *s; uint32_t pid, parent_pid, type, mode, submode, status, tgid; if (sscanf(res->values, " pid = %d, parent_pid = %d, name = \"%m[^\"]\", " "type = %d, mode = %d, submode = %d, status = %d, tgid = %d", &pid, &parent_pid, &s, &type, &mode, &submode, &status, &tgid) != 8) { PARSE_ERROR(mod, res->values); return; } if (pass == 1) { find_or_add_task_trace(clean_name(s), pid, tgid)/*[0].group = 0*/; } if (pass == 2) { //XXX if (status == 1) emit_trace(find_task_trace(pid), (union ltt_value)LT_S0); } free(s); }
static void kernel_irq_entry_process(struct ltt_module *mod, struct parse_result *res, int pass) { int kernel_mode; unsigned int ip,irq; #if defined(ARCH_2_6_3X) void *handler; #endif kernel_common(res, pass); #if defined(ARCH_2_6_3X) if (sscanf(res->values, " ip = %u, handler = %p, irq_id = %u, kernel_mode = %d", &ip, &handler, &irq, &kernel_mode) != 4) { PARSE_ERROR(mod, res->values); return; } #else if (sscanf(res->values, " ip = %u, irq_id = %u, kernel_mode = %d", &ip, &irq, &kernel_mode) != 3) { PARSE_ERROR(mod, res->values); return; } #endif if (irq >= MAX_IRQS) { DIAG("invalid IRQ vector ? (%d)\n", irq); return; } if (pass == 1 && irq_tag[irq]) { init_trace(&trace[irq], TG_IRQ, 1.0+irq, TRACE_SYM_F_BITS, irq_tag[irq]); atag_store(ip); } if (pass == 2) { if (!irq_tag[irq]) { char name[20]; snprintf(name, sizeof(name), "irq %d", irq); init_trace(&trace[irq], TG_IRQ, 1.0+irq, TRACE_SYM_F_BITS, strdup(name)); } if (irqlevel >= MAX_IRQS) { DIAG("IRQ nesting level is too high (%d)\n", irqlevel); return; } if (irqlevel > 0 && irq == irqtab[irqlevel-1]) { DIAG("IRQ reentering in same irq (broken trace ?) %d\n", irqlevel); return; } if (irqlevel > 0) { TDIAG(res, "nesting irq %s -> %s\n", irq_tag[irqtab[irqlevel-1]], irq_tag[irq]); emit_trace(&trace[irqtab[irqlevel-1]], (union ltt_value)IRQ_PREEMPT); } emit_trace(&trace[irq], (union ltt_value)IRQ_RUNNING); emit_trace(&irq_pc, (union ltt_value)ip); irqtab[irqlevel++] = irq; if (irqlevel == 1) emit_cpu_idle_state(res, (union ltt_value)IDLE_CPU_PREEMPT); /* stat stuff */ #ifndef ARCH_2_6_3X if (irq == 19) { static double timer3clock; static double timer3diff; if (timer3clock > 0) { double diff = res->clock - timer3clock; if (timer3diff > 0) { /* we allow a jitter of 0,1 ms */ if (diff > timer3diff + 0.0001) { TDIAG(res, "late irq !!! system timer took %fs (instead of %fs)\n", diff, timer3diff); } } else timer3diff = diff; } timer3clock = res->clock; } #endif /* only account on the first irq */ if (irqlevel == 1) irqtime = res->clock; /* end stat stuff */ } }