Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1f0ac718 authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge branch 'perf/test' of...

parents 232a5c94 76ba7e84
Loading
Loading
Loading
Loading
+17 −38
Original line number Diff line number Diff line
@@ -35,11 +35,11 @@ TRACE_EVENT(lock_acquire,
		  __get_str(name))
);

TRACE_EVENT(lock_release,
DECLARE_EVENT_CLASS(lock,

	TP_PROTO(struct lockdep_map *lock, int nested, unsigned long ip),
	TP_PROTO(struct lockdep_map *lock, unsigned long ip),

	TP_ARGS(lock, nested, ip),
	TP_ARGS(lock, ip),

	TP_STRUCT__entry(
		__string(	name, 	lock->name	)
@@ -51,51 +51,30 @@ TRACE_EVENT(lock_release,
		__entry->lockdep_addr = lock;
	),

	TP_printk("%p %s",
		  __entry->lockdep_addr, __get_str(name))
	TP_printk("%p %s",  __entry->lockdep_addr, __get_str(name))
);

#ifdef CONFIG_LOCK_STAT

TRACE_EVENT(lock_contended,
DEFINE_EVENT(lock, lock_release,

	TP_PROTO(struct lockdep_map *lock, unsigned long ip),

	TP_ARGS(lock, ip),
	TP_ARGS(lock, ip)
);

	TP_STRUCT__entry(
		__string(name, lock->name)
		__field(void *, lockdep_addr)
	),
#ifdef CONFIG_LOCK_STAT

	TP_fast_assign(
		__assign_str(name, lock->name);
		__entry->lockdep_addr = lock;
	),
DEFINE_EVENT(lock, lock_contended,

	TP_printk("%p %s",
		  __entry->lockdep_addr, __get_str(name))
);
	TP_PROTO(struct lockdep_map *lock, unsigned long ip),

TRACE_EVENT(lock_acquired,
	TP_PROTO(struct lockdep_map *lock, unsigned long ip, s64 waittime),
	TP_ARGS(lock, ip)
);

	TP_ARGS(lock, ip, waittime),
DEFINE_EVENT(lock, lock_acquired,

	TP_STRUCT__entry(
		__string(name, lock->name)
		__field(s64, wait_nsec)
		__field(void *, lockdep_addr)
	),
	TP_PROTO(struct lockdep_map *lock, unsigned long ip),

	TP_fast_assign(
		__assign_str(name, lock->name);
		__entry->wait_nsec = waittime;
		__entry->lockdep_addr = lock;
	),
	TP_printk("%p %s (%llu ns)", __entry->lockdep_addr,
		  __get_str(name),
		  __entry->wait_nsec)
	TP_ARGS(lock, ip)
);

#endif
+2 −2
Original line number Diff line number Diff line
@@ -3227,7 +3227,7 @@ void lock_release(struct lockdep_map *lock, int nested,
	raw_local_irq_save(flags);
	check_flags(flags);
	current->lockdep_recursion = 1;
	trace_lock_release(lock, nested, ip);
	trace_lock_release(lock, ip);
	__lock_release(lock, nested, ip);
	current->lockdep_recursion = 0;
	raw_local_irq_restore(flags);
@@ -3380,7 +3380,7 @@ __lock_acquired(struct lockdep_map *lock, unsigned long ip)
		hlock->holdtime_stamp = now;
	}

	trace_lock_acquired(lock, ip, waittime);
	trace_lock_acquired(lock, ip);

	stats = get_lock_stats(hlock_class(hlock));
	if (waittime) {
+104 −41
Original line number Diff line number Diff line
@@ -387,7 +387,20 @@ static struct lock_seq_stat *get_seq(struct thread_stat *ts, void *addr)
	return seq;
}

static int bad_hist[4];
enum broken_state {
	BROKEN_ACQUIRE,
	BROKEN_ACQUIRED,
	BROKEN_CONTENDED,
	BROKEN_RELEASE,
	BROKEN_MAX,
};

static int bad_hist[BROKEN_MAX];

enum acquire_flags {
	TRY_LOCK = 1,
	READ_LOCK = 2,
};

static void
report_lock_acquire_event(struct trace_acquire_event *acquire_event,
@@ -413,9 +426,9 @@ report_lock_acquire_event(struct trace_acquire_event *acquire_event,
		if (!acquire_event->flag) {
			seq->state = SEQ_STATE_ACQUIRING;
		} else {
			if (acquire_event->flag & 1)
			if (acquire_event->flag & TRY_LOCK)
				ls->nr_trylock++;
			if (acquire_event->flag & 2)
			if (acquire_event->flag & READ_LOCK)
				ls->nr_readlock++;
			seq->state = SEQ_STATE_READ_ACQUIRED;
			seq->read_count = 1;
@@ -423,7 +436,7 @@ report_lock_acquire_event(struct trace_acquire_event *acquire_event,
		}
		break;
	case SEQ_STATE_READ_ACQUIRED:
		if (acquire_event->flag & 2) {
		if (acquire_event->flag & READ_LOCK) {
			seq->read_count++;
			ls->nr_acquired++;
			goto end;
@@ -437,7 +450,7 @@ report_lock_acquire_event(struct trace_acquire_event *acquire_event,
broken:
		/* broken lock sequence, discard it */
		ls->discard = 1;
		bad_hist[0]++;
		bad_hist[BROKEN_ACQUIRE]++;
		list_del(&seq->list);
		free(seq);
		goto end;
@@ -481,10 +494,9 @@ report_lock_acquired_event(struct trace_acquired_event *acquired_event,
	case SEQ_STATE_CONTENDED:
		contended_term = timestamp - seq->prev_event_time;
		ls->wait_time_total += contended_term;

		if (contended_term < ls->wait_time_min)
			ls->wait_time_min = contended_term;
		else if (ls->wait_time_max < contended_term)
		if (ls->wait_time_max < contended_term)
			ls->wait_time_max = contended_term;
		break;
	case SEQ_STATE_RELEASED:
@@ -492,7 +504,7 @@ report_lock_acquired_event(struct trace_acquired_event *acquired_event,
	case SEQ_STATE_READ_ACQUIRED:
		/* broken lock sequence, discard it */
		ls->discard = 1;
		bad_hist[1]++;
		bad_hist[BROKEN_ACQUIRED]++;
		list_del(&seq->list);
		free(seq);
		goto end;
@@ -540,7 +552,7 @@ report_lock_contended_event(struct trace_contended_event *contended_event,
	case SEQ_STATE_CONTENDED:
		/* broken lock sequence, discard it */
		ls->discard = 1;
		bad_hist[2]++;
		bad_hist[BROKEN_CONTENDED]++;
		list_del(&seq->list);
		free(seq);
		goto end;
@@ -594,7 +606,7 @@ report_lock_release_event(struct trace_release_event *release_event,
	case SEQ_STATE_RELEASED:
		/* broken lock sequence, discard it */
		ls->discard = 1;
		bad_hist[3]++;
		bad_hist[BROKEN_RELEASE]++;
		goto free_seq;
		break;
	default:
@@ -713,6 +725,21 @@ process_raw_event(void *data, int cpu, u64 timestamp, struct thread *thread)
		process_lock_release_event(data, event, cpu, timestamp, thread);
}

static void print_bad_events(int bad, int total)
{
	/* Output for debug, this have to be removed */
	int i;
	const char *name[4] =
		{ "acquire", "acquired", "contended", "release" };

	pr_info("\n=== output for debug===\n\n");
	pr_info("bad: %d, total: %d\n", bad, total);
	pr_info("bad rate: %f %%\n", (double)bad / (double)total * 100);
	pr_info("histogram of events caused bad sequence\n");
	for (i = 0; i < BROKEN_MAX; i++)
		pr_info(" %10s: %d\n", name[i], bad_hist[i]);
}

/* TODO: various way to print, coloring, nano or milli sec */
static void print_result(void)
{
@@ -720,15 +747,15 @@ static void print_result(void)
	char cut_name[20];
	int bad, total;

	printf("%20s ", "Name");
	printf("%10s ", "acquired");
	printf("%10s ", "contended");
	pr_info("%20s ", "Name");
	pr_info("%10s ", "acquired");
	pr_info("%10s ", "contended");

	printf("%15s ", "total wait (ns)");
	printf("%15s ", "max wait (ns)");
	printf("%15s ", "min wait (ns)");
	pr_info("%15s ", "total wait (ns)");
	pr_info("%15s ", "max wait (ns)");
	pr_info("%15s ", "min wait (ns)");

	printf("\n\n");
	pr_info("\n\n");

	bad = total = 0;
	while ((st = pop_from_result())) {
@@ -741,7 +768,7 @@ static void print_result(void)

		if (strlen(st->name) < 16) {
			/* output raw name */
			printf("%20s ", st->name);
			pr_info("%20s ", st->name);
		} else {
			strncpy(cut_name, st->name, 16);
			cut_name[16] = '.';
@@ -749,33 +776,40 @@ static void print_result(void)
			cut_name[18] = '.';
			cut_name[19] = '\0';
			/* cut off name for saving output style */
			printf("%20s ", cut_name);
			pr_info("%20s ", cut_name);
		}

		printf("%10u ", st->nr_acquired);
		printf("%10u ", st->nr_contended);
		pr_info("%10u ", st->nr_acquired);
		pr_info("%10u ", st->nr_contended);

		printf("%15llu ", st->wait_time_total);
		printf("%15llu ", st->wait_time_max);
		printf("%15llu ", st->wait_time_min == ULLONG_MAX ?
		pr_info("%15llu ", st->wait_time_total);
		pr_info("%15llu ", st->wait_time_max);
		pr_info("%15llu ", st->wait_time_min == ULLONG_MAX ?
		       0 : st->wait_time_min);
		printf("\n");
		pr_info("\n");
	}

	print_bad_events(bad, total);
}

static int			info_threads;
static int			info_map;

static void dump_threads(void)
{
		/* Output for debug, this have to be removed */
		int i;
		const char *name[4] =
			{ "acquire", "acquired", "contended", "release" };
	struct thread_stat *st;
	struct rb_node *node;
	struct thread *t;

		printf("\n=== output for debug===\n\n");
		printf("bad:%d, total:%d\n", bad, total);
		printf("bad rate:%f\n", (double)(bad / total));
	pr_info("%10s: comm\n", "Thread ID");

		printf("histogram of events caused bad sequence\n");
		for (i = 0; i < 4; i++)
			printf(" %10s: %d\n", name[i], bad_hist[i]);
	}
	node = rb_first(&thread_stats);
	while (node) {
		st = container_of(node, struct thread_stat, rb);
		t = perf_session__findnew(session, st->tid);
		pr_info("%10d: %s\n", st->tid, t->comm);
		node = rb_next(node);
	};
}

static void dump_map(void)
@@ -783,13 +817,24 @@ static void dump_map(void)
	unsigned int i;
	struct lock_stat *st;

	pr_info("Address of instance: name of class\n");
	for (i = 0; i < LOCKHASH_SIZE; i++) {
		list_for_each_entry(st, &lockhash_table[i], hash_entry) {
			printf("%p: %s\n", st->addr, st->name);
			pr_info(" %p: %s\n", st->addr, st->name);
		}
	}
}

static void dump_info(void)
{
	if (info_threads)
		dump_threads();
	else if (info_map)
		dump_map();
	else
		die("Unknown type of information\n");
}

static int process_sample_event(event_t *self, struct perf_session *s)
{
	struct sample_data data;
@@ -858,6 +903,19 @@ static const struct option report_options[] = {
	OPT_END()
};

static const char * const info_usage[] = {
	"perf lock info [<options>]",
	NULL
};

static const struct option info_options[] = {
	OPT_BOOLEAN('t', "threads", &info_threads,
		    "dump thread list in perf.data"),
	OPT_BOOLEAN('m', "map", &info_map,
		    "map of lock instances (name:address table)"),
	OPT_END()
};

static const char * const lock_usage[] = {
	"perf lock [<options>] {record|trace|report}",
	NULL
@@ -872,7 +930,6 @@ static const struct option lock_options[] = {

static const char *record_args[] = {
	"record",
	"-a",
	"-R",
	"-f",
	"-m", "1024",
@@ -929,12 +986,18 @@ int cmd_lock(int argc, const char **argv, const char *prefix __used)
	} else if (!strcmp(argv[0], "trace")) {
		/* Aliased to 'perf trace' */
		return cmd_trace(argc, argv, prefix);
	} else if (!strcmp(argv[0], "map")) {
	} else if (!strcmp(argv[0], "info")) {
		if (argc) {
			argc = parse_options(argc, argv,
					     info_options, info_usage, 0);
			if (argc)
				usage_with_options(info_usage, info_options);
		}
		/* recycling report_lock_ops */
		trace_handler = &report_lock_ops;
		setup_pager();
		read_events();
		dump_map();
		dump_info();
	} else {
		usage_with_options(lock_usage, lock_options);
	}
+24 −10
Original line number Diff line number Diff line
@@ -494,6 +494,29 @@ static void event__synthesize_guest_os(struct machine *machine, void *data)
		       " relocation symbol.\n", machine->pid);
}

static struct perf_event_header finished_round_event = {
	.size = sizeof(struct perf_event_header),
	.type = PERF_RECORD_FINISHED_ROUND,
};

static void mmap_read_all(void)
{
	int i, counter, thread;

	for (i = 0; i < nr_cpu; i++) {
		for (counter = 0; counter < nr_counters; counter++) {
			for (thread = 0; thread < thread_num; thread++) {
				if (mmap_array[i][counter][thread].base)
					mmap_read(&mmap_array[i][counter][thread]);
			}

		}
	}

	if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
		write_output(&finished_round_event, sizeof(finished_round_event));
}

static int __cmd_record(int argc, const char **argv)
{
	int i, counter;
@@ -726,16 +749,7 @@ static int __cmd_record(int argc, const char **argv)
		int hits = samples;
		int thread;

		for (i = 0; i < nr_cpu; i++) {
			for (counter = 0; counter < nr_counters; counter++) {
				for (thread = 0;
					thread < thread_num; thread++) {
					if (mmap_array[i][counter][thread].base)
						mmap_read(&mmap_array[i][counter][thread]);
				}

			}
		}
		mmap_read_all();

		if (hits == samples) {
			if (done)
+2 −1
Original line number Diff line number Diff line
@@ -84,11 +84,12 @@ struct build_id_event {
	char			 filename[];
};

enum perf_header_event_type { /* above any possible kernel type */
enum perf_user_event_type { /* above any possible kernel type */
	PERF_RECORD_HEADER_ATTR			= 64,
	PERF_RECORD_HEADER_EVENT_TYPE		= 65,
	PERF_RECORD_HEADER_TRACING_DATA		= 66,
	PERF_RECORD_HEADER_BUILD_ID		= 67,
	PERF_RECORD_FINISHED_ROUND		= 68,
	PERF_RECORD_HEADER_MAX
};

Loading