Exemplo n.º 1
0
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);
	}
}
Exemplo n.º 2
0
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;
		}
	}
}
Exemplo n.º 3
0
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);
}