diff options
Diffstat (limited to 'tools/perf/util/db-export.c')
| -rw-r--r-- | tools/perf/util/db-export.c | 162 | 
1 files changed, 160 insertions, 2 deletions
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c index be128b075a32..c81dae399763 100644 --- a/tools/perf/util/db-export.c +++ b/tools/perf/util/db-export.c @@ -21,16 +21,76 @@  #include "comm.h"  #include "symbol.h"  #include "event.h" +#include "util.h" +#include "thread-stack.h"  #include "db-export.h" +struct deferred_export { +	struct list_head node; +	struct comm *comm; +}; + +static int db_export__deferred(struct db_export *dbe) +{ +	struct deferred_export *de; +	int err; + +	while (!list_empty(&dbe->deferred)) { +		de = list_entry(dbe->deferred.next, struct deferred_export, +				node); +		err = dbe->export_comm(dbe, de->comm); +		list_del(&de->node); +		free(de); +		if (err) +			return err; +	} + +	return 0; +} + +static void db_export__free_deferred(struct db_export *dbe) +{ +	struct deferred_export *de; + +	while (!list_empty(&dbe->deferred)) { +		de = list_entry(dbe->deferred.next, struct deferred_export, +				node); +		list_del(&de->node); +		free(de); +	} +} + +static int db_export__defer_comm(struct db_export *dbe, struct comm *comm) +{ +	struct deferred_export *de; + +	de = zalloc(sizeof(struct deferred_export)); +	if (!de) +		return -ENOMEM; + +	de->comm = comm; +	list_add_tail(&de->node, &dbe->deferred); + +	return 0; +} +  int db_export__init(struct db_export *dbe)  {  	memset(dbe, 0, sizeof(struct db_export)); +	INIT_LIST_HEAD(&dbe->deferred);  	return 0;  } -void db_export__exit(struct db_export *dbe __maybe_unused) +int db_export__flush(struct db_export *dbe) +{ +	return db_export__deferred(dbe); +} + +void db_export__exit(struct db_export *dbe)  { +	db_export__free_deferred(dbe); +	call_return_processor__free(dbe->crp); +	dbe->crp = NULL;  }  int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel) @@ -112,7 +172,10 @@ int db_export__comm(struct db_export *dbe, struct comm *comm,  	comm->db_id = ++dbe->comm_last_db_id;  	if (dbe->export_comm) { -		err = dbe->export_comm(dbe, comm); +		if (main_thread->comm_set) +			err = dbe->export_comm(dbe, comm); +		else +			err = db_export__defer_comm(dbe, comm);  		if (err)  			return err;  	} @@ -208,6 +271,15 @@ static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,  	return 0;  } +int db_export__branch_type(struct db_export *dbe, u32 branch_type, +			   const char *name) +{ +	if (dbe->export_branch_type) +		return dbe->export_branch_type(dbe, branch_type, name); + +	return 0; +} +  int db_export__sample(struct db_export *dbe, union perf_event *event,  		      struct perf_sample *sample, struct perf_evsel *evsel,  		      struct thread *thread, struct addr_location *al) @@ -261,6 +333,13 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,  				     &es.addr_sym_db_id, &es.addr_offset);  		if (err)  			return err; +		if (dbe->crp) { +			err = thread_stack__process(thread, comm, sample, al, +						    &addr_al, es.db_id, +						    dbe->crp); +			if (err) +				return err; +		}  	}  	if (dbe->export_sample) @@ -268,3 +347,82 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,  	return 0;  } + +static struct { +	u32 branch_type; +	const char *name; +} branch_types[] = { +	{0, "no branch"}, +	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"}, +	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"}, +	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "conditional jump"}, +	{PERF_IP_FLAG_BRANCH, "unconditional jump"}, +	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT, +	 "software interrupt"}, +	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT, +	 "return from interrupt"}, +	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET, +	 "system call"}, +	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET, +	 "return from system call"}, +	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "asynchronous branch"}, +	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC | +	 PERF_IP_FLAG_INTERRUPT, "hardware interrupt"}, +	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "transaction abort"}, +	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "trace begin"}, +	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "trace end"}, +	{0, NULL} +}; + +int db_export__branch_types(struct db_export *dbe) +{ +	int i, err = 0; + +	for (i = 0; branch_types[i].name ; i++) { +		err = db_export__branch_type(dbe, branch_types[i].branch_type, +					     branch_types[i].name); +		if (err) +			break; +	} +	return err; +} + +int db_export__call_path(struct db_export *dbe, struct call_path *cp) +{ +	int err; + +	if (cp->db_id) +		return 0; + +	if (cp->parent) { +		err = db_export__call_path(dbe, cp->parent); +		if (err) +			return err; +	} + +	cp->db_id = ++dbe->call_path_last_db_id; + +	if (dbe->export_call_path) +		return dbe->export_call_path(dbe, cp); + +	return 0; +} + +int db_export__call_return(struct db_export *dbe, struct call_return *cr) +{ +	int err; + +	if (cr->db_id) +		return 0; + +	err = db_export__call_path(dbe, cr->cp); +	if (err) +		return err; + +	cr->db_id = ++dbe->call_return_last_db_id; + +	if (dbe->export_call_return) +		return dbe->export_call_return(dbe, cr); + +	return 0; +}  | 
