void trace_view_store_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value) { TraceViewRecord *record; TraceViewStore *trace_view_store; struct trace_seq s; struct pevent *pevent; struct event_format *event; struct record *data; const gchar *comm; gchar *str; guint64 secs, usecs; gint val; int cpu; g_return_if_fail (TRACE_VIEW_IS_LIST (tree_model)); g_return_if_fail (iter != NULL); g_return_if_fail (column < TRACE_VIEW_STORE(tree_model)->n_columns); g_value_init (value, TRACE_VIEW_STORE(tree_model)->column_types[column]); trace_view_store = TRACE_VIEW_STORE(tree_model); pevent = tracecmd_get_pevent(trace_view_store->handle); record = (TraceViewRecord*)iter->user_data; g_return_if_fail ( record != NULL ); column = get_visible_column(TRACE_VIEW_STORE(tree_model), column); switch(column) { case TRACE_VIEW_STORE_COL_INDEX: g_value_set_uint(value, record->pos); break; case TRACE_VIEW_STORE_COL_CPU: g_value_set_uint(value, record->cpu); break; case TRACE_VIEW_STORE_COL_TS: usecs = record->timestamp; usecs /= 1000; secs = usecs / 1000000ULL; usecs -= secs * 1000000ULL; str = g_strdup_printf("%llu.%06llu", (long long)secs, (long long)usecs); g_value_set_string(value, str); g_free(str); break; case TRACE_VIEW_STORE_COL_COMM: case TRACE_VIEW_STORE_COL_PID: case TRACE_VIEW_STORE_COL_LAT: case TRACE_VIEW_STORE_COL_EVENT: case TRACE_VIEW_STORE_COL_INFO: data = tracecmd_read_at(trace_view_store->handle, record->offset, &cpu); g_assert(data != NULL); if (cpu != record->cpu) { free_record(data); return; } switch (column) { case TRACE_VIEW_STORE_COL_COMM: case TRACE_VIEW_STORE_COL_PID: val = pevent_data_pid(pevent, data); if (column == TRACE_VIEW_STORE_COL_PID) g_value_set_uint(value, val); else { comm = pevent_data_comm_from_pid(pevent, val); g_value_set_string(value, comm); } break; case TRACE_VIEW_STORE_COL_LAT: trace_seq_init(&s); pevent_data_lat_fmt(pevent, &s, data); g_value_set_string(value, s.buffer); trace_seq_destroy(&s); break; case TRACE_VIEW_STORE_COL_EVENT: case TRACE_VIEW_STORE_COL_INFO: val = pevent_data_type(pevent, data); event = pevent_data_event_from_type(pevent, val); if (!event) { if (column == TRACE_VIEW_STORE_COL_EVENT) g_value_set_string(value, "[UNKNOWN EVENT]"); break; } if (column == TRACE_VIEW_STORE_COL_EVENT) { g_value_set_string(value, event->name); break; } trace_seq_init(&s); pevent_event_info(&s, event, data); g_value_set_string(value, s.buffer); trace_seq_destroy(&s); break; } free_record(data); } }
void perf_process_bundle::handle_trace_point(void *trace, int cpu, uint64_t time) { struct event_format *event; struct pevent_record rec; /* holder */ struct format_field *field; unsigned long long val; int type; int ret; rec.data = trace; type = pevent_data_type(perf_event::pevent, &rec); event = pevent_find_event(perf_event::pevent, type); if (!event) return; if (time < first_stamp) first_stamp = time; if (time > last_stamp) { last_stamp = time; measurement_time = (0.0001 + last_stamp - first_stamp) / 1000000000 ; } if (strcmp(event->name, "sched_switch") == 0) { class process *old_proc = NULL; class process *new_proc = NULL; const char *next_comm; int next_pid; int prev_pid; field = pevent_find_any_field(event, "next_comm"); if (!field || !(field->flags & FIELD_IS_STRING)) return; /* ?? */ next_comm = get_pevent_field_str(trace, event, field); ret = pevent_get_field_val(NULL, event, "next_pid", &rec, &val, 0); if (ret < 0) return; next_pid = (int)val; ret = pevent_get_field_val(NULL, event, "prev_pid", &rec, &val, 0); if (ret < 0) return; prev_pid = (int)val; /* find new process pointer */ new_proc = find_create_process(next_comm, next_pid); /* find the old process pointer */ while (consumer_depth(cpu) > 1) { pop_consumer(cpu); } if (consumer_depth(cpu) == 1) old_proc = (class process *)current_consumer(cpu); if (old_proc && strcmp(old_proc->name(), "process")) old_proc = NULL; /* retire the old process */ if (old_proc) { old_proc->deschedule_thread(time, prev_pid); old_proc->waker = NULL; } if (consumer_depth(cpu)) pop_consumer(cpu); push_consumer(cpu, new_proc); /* start new process */ new_proc->schedule_thread(time, next_pid); if (strncmp(next_comm,"migration/", 10) && strncmp(next_comm,"kworker/", 8) && strncmp(next_comm, "kondemand/",10)) { if (next_pid) { /* If someone woke us up.. blame him instead */ if (new_proc->waker) { change_blame(cpu, new_proc->waker, LEVEL_PROCESS); } else { change_blame(cpu, new_proc, LEVEL_PROCESS); } } consume_blame(cpu); } new_proc->waker = NULL; } else if (strcmp(event->name, "sched_wakeup") == 0) { class power_consumer *from = NULL; class process *dest_proc = NULL; class process *from_proc = NULL; const char *comm; int flags; int pid; ret = pevent_get_common_field_val(NULL, event, "common_flags", &rec, &val, 0); if (ret < 0) return; flags = (int)val; if ( (flags & TRACE_FLAG_HARDIRQ) || (flags & TRACE_FLAG_SOFTIRQ)) { class timer *timer; timer = (class timer *) current_consumer(cpu); if (timer && strcmp(timer->name(), "timer")==0) { if (strcmp(timer->handler, "delayed_work_timer_fn") && strcmp(timer->handler, "hrtimer_wakeup") && strcmp(timer->handler, "it_real_fn")) from = timer; } /* woken from interrupt */ /* TODO: find the current irq handler and set "from" to that */ } else { from = current_consumer(cpu); } field = pevent_find_any_field(event, "comm"); if (!field || !(field->flags & FIELD_IS_STRING)) return; comm = get_pevent_field_str(trace, event, field); ret = pevent_get_field_val(NULL, event, "pid", &rec, &val, 0); if (ret < 0) return; pid = (int)val; dest_proc = find_create_process(comm, pid); if (from && strcmp(from->name(), "process")!=0){ /* not a process doing the wakeup */ from = NULL; from_proc = NULL; } else { from_proc = (class process *) from; } if (from_proc && (dest_proc->running == 0) && (dest_proc->waker == NULL) && (pid != 0) && !dont_blame_me(from_proc->comm)) dest_proc->waker = from; if (from) dest_proc->last_waker = from; /* Account processes that wake up X specially */ if (from && dest_proc && comm_is_xorg(dest_proc->comm)) from->xwakes ++ ; } else if (strcmp(event->name, "irq_handler_entry") == 0) { class interrupt *irq = NULL; const char *handler; int nr; field = pevent_find_any_field(event, "name"); if (!field || !(field->flags & FIELD_IS_STRING)) return; /* ?? */ handler = get_pevent_field_str(trace, event, field); ret = pevent_get_field_val(NULL, event, "irq", &rec, &val, 0); if (ret < 0) return; nr = (int)val; irq = find_create_interrupt(handler, nr, cpu); push_consumer(cpu, irq); irq->start_interrupt(time); if (strstr(irq->handler, "timer") ==NULL) change_blame(cpu, irq, LEVEL_HARDIRQ); } else if (strcmp(event->name, "irq_handler_exit") == 0) { class interrupt *irq = NULL; uint64_t t; /* find interrupt (top of stack) */ irq = (class interrupt *)current_consumer(cpu); if (!irq || strcmp(irq->name(), "interrupt")) return; pop_consumer(cpu); /* retire interrupt */ t = irq->end_interrupt(time); consumer_child_time(cpu, t); } else if (strcmp(event->name, "softirq_entry") == 0) { class interrupt *irq = NULL; const char *handler = NULL; int vec; ret = pevent_get_field_val(NULL, event, "vec", &rec, &val, 0); if (ret < 0) { fprintf(stderr, "softirq_entry event returned no vector number?\n"); return; } vec = (int)val; if (vec <= 9) handler = softirqs[vec]; if (!handler) return; irq = find_create_interrupt(handler, vec, cpu); push_consumer(cpu, irq); irq->start_interrupt(time); change_blame(cpu, irq, LEVEL_SOFTIRQ); } else if (strcmp(event->name, "softirq_exit") == 0) { class interrupt *irq = NULL; uint64_t t; irq = (class interrupt *) current_consumer(cpu); if (!irq || strcmp(irq->name(), "interrupt")) return; pop_consumer(cpu); /* pop irq */ t = irq->end_interrupt(time); consumer_child_time(cpu, t); } else if (strcmp(event->name, "timer_expire_entry") == 0) { class timer *timer = NULL; uint64_t function; uint64_t tmr; ret = pevent_get_field_val(NULL, event, "function", &rec, &val, 0); if (ret < 0) { fprintf(stderr, "timer_expire_entry event returned no fucntion value?\n"); return; } function = (uint64_t)val; timer = find_create_timer(function); if (timer->is_deferred()) return; ret = pevent_get_field_val(NULL, event, "timer", &rec, &val, 0); if (ret < 0) { fprintf(stderr, "softirq_entry event returned no timer ?\n"); return; } tmr = (uint64_t)val; push_consumer(cpu, timer); timer->fire(time, tmr); if (strcmp(timer->handler, "delayed_work_timer_fn")) change_blame(cpu, timer, LEVEL_TIMER); } else if (strcmp(event->name, "timer_expire_exit") == 0) { class timer *timer = NULL; uint64_t tmr; uint64_t t; ret = pevent_get_field_val(NULL, event, "timer", &rec, &val, 0); if (ret < 0) return; tmr = (uint64_t)val; timer = (class timer *) current_consumer(cpu); if (!timer || strcmp(timer->name(), "timer")) { return; } pop_consumer(cpu); t = timer->done(time, tmr); consumer_child_time(cpu, t); } else if (strcmp(event->name, "hrtimer_expire_entry") == 0) { class timer *timer = NULL; uint64_t function; uint64_t tmr; ret = pevent_get_field_val(NULL, event, "function", &rec, &val, 0); if (ret < 0) return; function = (uint64_t)val; timer = find_create_timer(function); ret = pevent_get_field_val(NULL, event, "hrtimer", &rec, &val, 0); if (ret < 0) return; tmr = (uint64_t)val; push_consumer(cpu, timer); timer->fire(time, tmr); if (strcmp(timer->handler, "delayed_work_timer_fn")) change_blame(cpu, timer, LEVEL_TIMER); } else if (strcmp(event->name, "hrtimer_expire_exit") == 0) { class timer *timer = NULL; uint64_t tmr; uint64_t t; timer = (class timer *) current_consumer(cpu); if (!timer || strcmp(timer->name(), "timer")) { return; } ret = pevent_get_field_val(NULL, event, "hrtimer", &rec, &val, 0); if (ret < 0) return; tmr = (uint64_t)val; pop_consumer(cpu); t = timer->done(time, tmr); consumer_child_time(cpu, t); } else if (strcmp(event->name, "workqueue_execute_start") == 0) { class work *work = NULL; uint64_t function; uint64_t wk; ret = pevent_get_field_val(NULL, event, "function", &rec, &val, 0); if (ret < 0) return; function = (uint64_t)val; ret = pevent_get_field_val(NULL, event, "work", &rec, &val, 0); if (ret < 0) return; wk = (uint64_t)val; work = find_create_work(function); push_consumer(cpu, work); work->fire(time, wk); if (strcmp(work->handler, "do_dbs_timer") != 0 && strcmp(work->handler, "vmstat_update") != 0) change_blame(cpu, work, LEVEL_WORK); } else if (strcmp(event->name, "workqueue_execute_end") == 0) { class work *work = NULL; uint64_t t; uint64_t wk; ret = pevent_get_field_val(NULL, event, "work", &rec, &val, 0); if (ret < 0) return; wk = (uint64_t)val; work = (class work *) current_consumer(cpu); if (!work || strcmp(work->name(), "work")) { return; } pop_consumer(cpu); t = work->done(time, wk); consumer_child_time(cpu, t); } else if (strcmp(event->name, "cpu_idle") == 0) { ret = pevent_get_field_val(NULL, event, "state", &rec, &val, 0); if (val == 4294967295) consume_blame(cpu); else set_wakeup_pending(cpu); } else if (strcmp(event->name, "power_start") == 0) { set_wakeup_pending(cpu); } else if (strcmp(event->name, "power_end") == 0) { consume_blame(cpu); } else if (strcmp(event->name, "i915_gem_ring_dispatch") == 0 || strcmp(event->name, "i915_gem_request_submit") == 0) { /* any kernel contains only one of the these tracepoints, * the latter one got replaced by the former one */ class power_consumer *consumer = NULL; int flags; ret = pevent_get_common_field_val(NULL, event, "common_flags", &rec, &val, 0); if (ret < 0) return; flags = (int)val; consumer = current_consumer(cpu); /* currently we don't count graphic requests submitted from irq contect */ if ( (flags & TRACE_FLAG_HARDIRQ) || (flags & TRACE_FLAG_SOFTIRQ)) { consumer = NULL; } /* if we are X, and someone just woke us, account the GPU op to the guy waking us */ if (consumer && strcmp(consumer->name(), "process")==0) { class process *proc = NULL; proc = (class process *) consumer; if (comm_is_xorg(proc->comm) && proc->last_waker) { consumer = proc->last_waker; } } if (consumer) { consumer->gpu_ops++; } } else if (strcmp(event->name, "writeback_inode_dirty") == 0) { static uint64_t prev_time; class power_consumer *consumer = NULL; int dev; consumer = current_consumer(cpu); ret = pevent_get_field_val(NULL, event, "dev", &rec, &val, 0); if (ret < 0) return; dev = (int)val; if (consumer && strcmp(consumer->name(), "process")==0 && dev > 0) { consumer->disk_hits++; /* if the previous inode dirty was > 1 second ago, it becomes a hard hit */ if ((time - prev_time) > 1000000000) consumer->hard_disk_hits++; prev_time = time; } } }
static void do_trace_hist(struct tracecmd_input *handle) { struct pevent *pevent = tracecmd_get_pevent(handle); struct event_format *event; struct pevent_record *record; int cpus; int cpu; int ret; ret = tracecmd_init_data(handle); if (ret < 0) die("failed to init data"); if (ret > 0) die("trace-cmd hist does not work with latency traces\n"); cpus = tracecmd_cpus(handle); /* Need to get any event */ for (cpu = 0; cpu < cpus; cpu++) { record = tracecmd_peek_data(handle, cpu); if (record) break; } if (!record) die("No records found in file"); ret = pevent_data_type(pevent, record); event = pevent_data_event_from_type(pevent, ret); long_size = tracecmd_long_size(handle); common_type_field = pevent_find_common_field(event, "common_type"); if (!common_type_field) die("Can't find a 'type' field?"); common_pid_field = pevent_find_common_field(event, "common_pid"); if (!common_pid_field) die("Can't find a 'pid' field?"); update_sched_wakeup(pevent); update_sched_wakeup_new(pevent); update_sched_switch(pevent); update_function(pevent); update_function_graph_entry(pevent); update_function_graph_exit(pevent); update_kernel_stack(pevent); for (cpu = 0; cpu < cpus; cpu++) { for (;;) { struct pevent_record *record; record = tracecmd_read_data(handle, cpu); if (!record) break; /* If we missed events, just flush out the current stack */ if (record->missed_events) flush_stack(); process_record(pevent, record); free_record(record); } } if (current_pid >= 0) save_call_chain(current_pid, ips, ips_idx, 0); if (pending_pid >= 0) save_call_chain(pending_pid, pending_ips, pending_ips_idx, 1); save_stored_stacks(); sort_chains(); print_chains(pevent); }