static void do_trace_mem(struct tracecmd_input *handle) { struct pevent *pevent = tracecmd_get_pevent(handle); struct event_format *event; struct pevent_record *record; int missed_events = 0; 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 mem 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); common_type_field = pevent_find_common_field(event, "common_type"); if (!common_type_field) die("Can't find a 'type' field?"); update_kmalloc(pevent); update_kmalloc_node(pevent); update_kfree(pevent); update_kmem_cache_alloc(pevent); update_kmem_cache_alloc_node(pevent); update_kmem_cache_free(pevent); while ((record = tracecmd_read_next_data(handle, &cpu))) { /* record missed event */ if (!missed_events && record->missed_events) missed_events = 1; process_record(pevent, record); free_record(record); } sort_list(); print_list(); }
int tracecmd_ftrace_overrides(struct tracecmd_input *handle, struct tracecmd_ftrace *finfo) { struct tep_handle *pevent; struct tep_event *event; finfo->handle = handle; pevent = tracecmd_get_pevent(handle); tep_register_event_handler(pevent, -1, "ftrace", "function", function_handler, NULL); tep_register_event_handler(pevent, -1, "ftrace", "funcgraph_entry", fgraph_ent_handler, finfo); tep_register_event_handler(pevent, -1, "ftrace", "funcgraph_exit", fgraph_ret_handler, finfo); tep_register_event_handler(pevent, -1, "ftrace", "kernel_stack", trace_stack_handler, finfo); trace_util_add_options("ftrace", trace_ftrace_options); /* Store the func ret id and event for later use */ event = tep_find_event_by_name(pevent, "ftrace", "funcgraph_exit"); if (!event) return 0; finfo->long_size = tracecmd_long_size(handle); finfo->fgraph_ret_id = event->id; finfo->fgraph_ret_event = event; return 0; }
int tracecmd_blk_hack(struct tracecmd_input *handle) { struct pevent *pevent; struct event_format *event; struct format_field *field; char buf[4096]; /* way more than enough! */ int id; int l; int r; pevent = tracecmd_get_pevent(handle); /* * Unfortunately, the TRACE_BLK has changed a bit. * We need to test if various events exist to try * to guess what event id TRACE_BLK would be. */ /* It was originally behind the "power" event */ event = pevent_find_event_by_name(pevent, "ftrace", "power"); if (event) { id = event->id + 1; goto found; } /* * But the power tracer is now in perf. * Then it was after kmem_free */ event = pevent_find_event_by_name(pevent, "ftrace", "kmem_free"); if (event) { id = event->id + 1; goto found; } /* * But that then went away. * Currently it should be behind the user stack. */ event = pevent_find_event_by_name(pevent, "ftrace", "user_stack"); if (event) { id = event->id + 1; goto found; } /* Give up :( */ return -1; found: /* * Blk events are not exported in the events directory. * This is a hack to attempt to create a block event * that we can read. * * We'll make a format file to look like this: * * name: blktrace * ID: 13 * format: * field:unsigned short common_type; offset:0; size:2; * field:unsigned char common_flags; offset:2; size:1; * field:unsigned char common_preempt_count; offset:3; size:1; * field:int common_pid; offset:4; size:4; * field:int common_lock_depth; offset:8; size:4; * * field:u64 sector; offset:16; size:8; * field:int bytes; offset:32; size:4; * field:int action; offset:36; size:4; * field:int pid; offset:40; size:4; * field:int device; offset:44; size:4; * field:int cpu; offset:48; size:4; * field:short error; offset:52; size:2; * field:short pdu_len; offset:54; size:2; * field:void data; offset:60; size:0; * * print fmt: "%d", REC->pid * * Note: the struct blk_io_trace is used directly and * just the first parts of the struct are not used in order * to not write over the ftrace data. */ /* Make sure the common fields exist */ field = pevent_find_common_field(event, "common_type"); if (!field || field->offset != 0 || field->size != 2) goto fail; field = pevent_find_common_field(event, "common_flags"); if (!field || field->offset != 2 || field->size != 1) goto fail; field = pevent_find_common_field(event, "common_preempt_count"); if (!field || field->offset != 3 || field->size != 1) goto fail; field = pevent_find_common_field(event, "common_pid"); if (!field || field->offset != 4 || field->size != 4) goto fail; r = sprintf(buf, blk_event_start, id); l = r; /* lock depth is optional */ field = pevent_find_common_field(event, "common_lock_depth"); if (field) { if (field->offset != 8 || field->size != 4) return -1; r = sprintf(buf+l, "\tfield:int common_lock_depth;\toffset:8;\tsize:4;\n"); l += r; } r = sprintf(buf+l, blk_body); /* Parse this event */ l += r; pevent_parse_event(pevent, buf, l, "ftrace"); return 0; fail: return -1; }
TraceViewStore * trace_view_store_new (struct tracecmd_input *handle) { TraceViewStore *newstore; struct record *data; gint cpu, count, total=0; struct temp { guint64 offset; guint64 ts; struct temp *next; } *list, **next, *rec; newstore = (TraceViewStore*) g_object_new (TRACE_VIEW_STORE_TYPE, NULL); g_assert( newstore != NULL ); newstore->handle = handle; newstore->cpus = tracecmd_cpus(handle); tracecmd_ref(handle); newstore->event_filter = pevent_filter_alloc(tracecmd_get_pevent(handle)); newstore->cpu_list = g_new(TraceViewRecord *, newstore->cpus); g_assert(newstore->cpu_list != NULL); newstore->cpu_items = g_new(gint, newstore->cpus); g_assert(newstore->cpu_items != NULL); newstore->all_cpus = 1; newstore->all_events = 1; newstore->cpu_mask = g_new0(guint64, (newstore->cpus >> 6) + 1); g_assert(newstore->cpu_mask != NULL); mask_set_cpus(newstore, newstore->cpus); for (cpu = 0; cpu < newstore->cpus; cpu++) { count = 0; list = NULL; next = &list; data = tracecmd_read_cpu_first(handle, cpu); while (data) { *next = rec = g_malloc(sizeof(*rec)); g_assert(rec != NULL); rec->offset = data->offset; rec->ts = data->ts; rec->next = NULL; next = &rec->next; free_record(data); count++; data = tracecmd_read_data(handle, cpu); } if (count) { TraceViewRecord *trec; struct temp *t; gint i; rec = list; trec = g_new(TraceViewRecord, count); g_assert(trec != NULL); for (i = 0; i < count; i++) { g_assert(rec != NULL); trec[i].cpu = cpu; trec[i].timestamp = rec->ts; trec[i].offset = rec->offset; trec[i].visible = 1; trec[i].pos = i; t = rec; rec = rec->next; g_free(t); } g_assert(rec == NULL); newstore->cpu_list[cpu] = trec; } else newstore->cpu_list[cpu] = NULL; newstore->cpu_items[cpu] = count; total += count; } newstore->actual_rows = total; newstore->rows = g_malloc(sizeof(*newstore->rows) * total + 1); merge_sort_rows_ts(newstore); return newstore; }
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); } }
static void update_filter_tasks(TraceViewStore *store) { struct tracecmd_input *handle; struct pevent *pevent; struct record *record; gint pid; gint cpu; gint i; handle = store->handle; pevent = tracecmd_get_pevent(store->handle); if (!store->sched_switch_event) { store->sched_switch_event = pevent_find_event_by_name(pevent, "sched", "sched_switch"); if (store->sched_switch_event) store->sched_switch_next_field = pevent_find_any_field(store->sched_switch_event, "next_pid"); store->sched_wakeup_event = pevent_find_event_by_name(pevent, "sched", "sched_wakeup"); if (store->sched_wakeup_event) store->sched_wakeup_pid_field = pevent_find_any_field(store->sched_wakeup_event, "pid"); store->sched_wakeup_new_event = pevent_find_event_by_name(pevent, "sched", "sched_wakeup"); if (store->sched_wakeup_new_event) store->sched_wakeup_new_pid_field = pevent_find_any_field(store->sched_wakeup_new_event, "pid"); } for (cpu = 0; cpu < store->cpus; cpu++) { record = tracecmd_read_cpu_first(handle, cpu); for (i = 0; i < store->cpu_items[cpu]; i++) { g_assert(record->offset == store->cpu_list[cpu][i].offset); /* The record may be filtered by the events */ if (!store->all_events) { int ret; ret = pevent_filter_match(store->event_filter, record); if (ret != FILTER_MATCH) { store->cpu_list[cpu][i].visible = 0; goto skip; } } pid = pevent_data_pid(pevent, record); if (show_task(store, pevent, record, pid)) store->cpu_list[cpu][i].visible = 1; else store->cpu_list[cpu][i].visible = 0; skip: free_record(record); record = tracecmd_read_data(handle, cpu); } g_assert(record == NULL); } merge_sort_rows_ts(store); }
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); }