Lines Matching +full:- +full:e

2  * qsp.c - QEMU Synchronization Profiler
7 * See the COPYING file in the top-level directory.
10 * help diagnose performance problems, e.g. scalability issues when
16 * either due to blocking (e.g. cond_wait, mutex_lock) or cache line
17 * contention (e.g. mutex_lock, mutex_trylock).
20 * by having threads do their profiling entirely on thread-local data.
21 * The appropriate thread-local data is found via a QHT, i.e. a concurrent hash
25 * very rarely called -- reports are generated only when requested by users.
29 * as well as the address of the "object" (i.e. mutex, rec. mutex or condvar)
32 * profiling dynamically-allocated objects.
36 * - Use an off-the-shelf profiler such as mutrace. This is not a viable option
40 * - Use a glib HT for each thread, protecting each HT with its own lock.
42 * atomic_add-bench microbenchmark (-m option).
44 * - For reports, just use a binary tree as we aggregate data, instead of having
48 * - Wrap operations on qsp entries with RCU read-side critical sections, so
50 * rcu_read_lock/unlock slows down atomic_add-bench -m by 24%. Having
54 * - Lennart Poettering's mutrace: http://0pointer.de/blog/projects/mutrace.html
55 * - Lozi, David, Thomas, Lawall and Muller. "Remote Core Locking: Migrating
56 * Critical-Section Execution to Improve the Performance of Multithreaded
61 #include "qemu/qemu-print.h"
77 const char *file; /* i.e. __FILE__; shortened later */
137 * It pays off to _not_ hash callsite->file; hashing a string is slow, and
143 uint64_t cd = (uint64_t)(uintptr_t)callsite->obj; in do_qsp_callsite_hash()
144 uint32_t e = callsite->line; in do_qsp_callsite_hash() local
145 uint32_t f = callsite->type; in do_qsp_callsite_hash()
147 return qemu_xxhash8(ab, cd, 0, e, f); in do_qsp_callsite_hash()
158 return do_qsp_callsite_hash(entry->callsite, a); in do_qsp_entry_hash()
163 return do_qsp_entry_hash(entry, (uint64_t)(uintptr_t)entry->thread_ptr); in qsp_entry_hash()
174 const QSPCallSite *callsite = entry->callsite; in qsp_entry_no_thread_obj_hash()
175 uint64_t ab = g_str_hash(callsite->file); in qsp_entry_no_thread_obj_hash()
176 uint64_t cd = callsite->line; in qsp_entry_no_thread_obj_hash()
177 uint32_t e = callsite->type; in qsp_entry_no_thread_obj_hash() local
179 return qemu_xxhash5(ab, cd, e); in qsp_entry_no_thread_obj_hash()
188 (a->obj == b->obj && in qsp_callsite_cmp()
189 a->line == b->line && in qsp_callsite_cmp()
190 a->type == b->type && in qsp_callsite_cmp()
191 (a->file == b->file || !strcmp(a->file, b->file))); in qsp_callsite_cmp()
200 (a->line == b->line && in qsp_callsite_no_obj_cmp()
201 a->type == b->type && in qsp_callsite_no_obj_cmp()
202 (a->file == b->file || !strcmp(a->file, b->file))); in qsp_callsite_no_obj_cmp()
210 return qsp_callsite_cmp(a->callsite, b->callsite); in qsp_entry_no_thread_cmp()
218 return qsp_callsite_no_obj_cmp(a->callsite, b->callsite); in qsp_entry_no_thread_obj_cmp()
226 return a->thread_ptr == b->thread_ptr && in qsp_entry_cmp()
227 qsp_callsite_cmp(a->callsite, b->callsite); in qsp_entry_cmp()
238 qsp_qemu_path_len = strlen(__FILE__) - strlen(QSP_REL_PATH); in qsp_do_init()
291 QSPEntry *e; in qsp_entry_create() local
294 e = g_new0(QSPEntry, 1); in qsp_entry_create()
295 e->thread_ptr = entry->thread_ptr; in qsp_entry_create()
296 e->callsite = qsp_callsite_find(entry->callsite); in qsp_entry_create()
298 qht_insert(ht, e, hash, &existing); in qsp_entry_create()
300 g_free(e); in qsp_entry_create()
301 e = existing; in qsp_entry_create()
303 return e; in qsp_entry_create()
309 QSPEntry *e; in qsp_entry_find() local
311 e = qht_lookup(ht, entry, hash); in qsp_entry_find()
312 if (e == NULL) { in qsp_entry_find()
313 e = qsp_entry_create(ht, entry, hash); in qsp_entry_find()
315 return e; in qsp_entry_find()
320 * read-side critical section.
344 * @e is in the global hash table; it is only written to by the current thread,
347 static inline void do_qsp_entry_record(QSPEntry *e, int64_t delta, bool acq) in do_qsp_entry_record() argument
349 qatomic_set_u64(&e->ns, e->ns + delta); in do_qsp_entry_record()
351 qatomic_set_u64(&e->n_acqs, e->n_acqs + 1); in do_qsp_entry_record()
355 static inline void qsp_entry_record(QSPEntry *e, int64_t delta) in qsp_entry_record() argument
357 do_qsp_entry_record(e, delta, true); in qsp_entry_record()
363 QSPEntry *e; \
370 e = qsp_entry_get(obj, file, line, qsp_t_); \
371 qsp_entry_record(e, t1 - t0); \
377 QSPEntry *e; \
385 e = qsp_entry_get(obj, file, line, qsp_t_); \
386 do_qsp_entry_record(e, t1 - t0, !err); \
405 QSPEntry *e; in QSP_GEN_VOID() local
412 e = qsp_entry_get(cond, file, line, QSP_CONDVAR); in QSP_GEN_VOID()
413 qsp_entry_record(e, t1 - t0); in QSP_GEN_VOID()
420 QSPEntry *e; in qsp_cond_timedwait() local
428 e = qsp_entry_get(cond, file, line, QSP_CONDVAR); in qsp_cond_timedwait()
429 qsp_entry_record(e, t1 - t0); in qsp_cond_timedwait()
470 if (a->ns > b->ns) { in qsp_tree_cmp()
471 return -1; in qsp_tree_cmp()
472 } else if (a->ns < b->ns) { in qsp_tree_cmp()
478 double avg_a = a->n_acqs ? a->ns / a->n_acqs : 0; in qsp_tree_cmp()
479 double avg_b = b->n_acqs ? b->ns / b->n_acqs : 0; in qsp_tree_cmp()
482 return -1; in qsp_tree_cmp()
492 ca = a->callsite; in qsp_tree_cmp()
493 cb = b->callsite; in qsp_tree_cmp()
495 if (ca->obj < cb->obj) { in qsp_tree_cmp()
496 return -1; in qsp_tree_cmp()
497 } else if (ca->obj > cb->obj) { in qsp_tree_cmp()
503 cmp = strcmp(ca->file, cb->file); in qsp_tree_cmp()
508 g_assert(ca->line != cb->line); in qsp_tree_cmp()
509 if (ca->line < cb->line) { in qsp_tree_cmp()
510 return -1; in qsp_tree_cmp()
511 } else if (ca->line > cb->line) { in qsp_tree_cmp()
515 return cb->type - ca->type; in qsp_tree_cmp()
522 QSPEntry *e = p; in qsp_sort() local
525 g_tree_insert(tree, e, NULL); in qsp_sort()
531 const QSPEntry *e = p; in qsp_aggregate() local
535 hash = qsp_entry_no_thread_hash(e); in qsp_aggregate()
536 agg = qsp_entry_find(ht, e, hash); in qsp_aggregate()
541 agg->ns += qatomic_read_u64(&e->ns); in qsp_aggregate()
542 agg->n_acqs += qatomic_read_u64(&e->n_acqs); in qsp_aggregate()
555 g_assert(new->n_acqs >= old->n_acqs); in qsp_iter_diff()
556 g_assert(new->ns >= old->ns); in qsp_iter_diff()
558 new->n_acqs -= old->n_acqs; in qsp_iter_diff()
559 new->ns -= old->ns; in qsp_iter_diff()
562 if (new->n_acqs == 0 && new->ns == 0) { in qsp_iter_diff()
579 QSPEntry *e; in qsp_iter_callsite_coalesce() local
583 e = qht_lookup(ht, old, hash); in qsp_iter_callsite_coalesce()
584 if (e == NULL) { in qsp_iter_callsite_coalesce()
585 e = qsp_entry_create(ht, old, hash); in qsp_iter_callsite_coalesce()
586 e->n_objs = 1; in qsp_iter_callsite_coalesce()
587 } else if (e->callsite->obj != old->callsite->obj) { in qsp_iter_callsite_coalesce()
588 e->n_objs++; in qsp_iter_callsite_coalesce()
590 e->ns += old->ns; in qsp_iter_callsite_coalesce()
591 e->n_acqs += old->n_acqs; in qsp_iter_callsite_coalesce()
609 * We must remain in an RCU read-side critical section until we're done in qsp_mktree()
622 qsp_diff(&snap->ht, &ht); in qsp_mktree()
652 if (unlikely(strlen(callsite->file) < qsp_qemu_path_len)) { in qsp_at()
653 shortened = callsite->file; in qsp_at()
655 shortened = callsite->file + qsp_qemu_path_len; in qsp_at()
657 g_string_append_printf(s, "%s:%u", shortened, callsite->line); in qsp_at()
681 const QSPEntry *e = key; in qsp_tree_report() local
685 if (report->n_entries == report->max_n_entries) { in qsp_tree_report()
688 entry = &report->entries[report->n_entries]; in qsp_tree_report()
689 report->n_entries++; in qsp_tree_report()
691 entry->obj = e->callsite->obj; in qsp_tree_report()
692 entry->n_objs = e->n_objs; in qsp_tree_report()
693 entry->callsite_at = qsp_at(e->callsite); in qsp_tree_report()
694 entry->typename = qsp_typenames[e->callsite->type]; in qsp_tree_report()
695 entry->time_s = e->ns * 1e-9; in qsp_tree_report()
696 entry->n_acqs = e->n_acqs; in qsp_tree_report()
697 entry->ns_avg = e->n_acqs ? e->ns / e->n_acqs : 0; in qsp_tree_report()
711 for (i = 0; i < rep->n_entries; i++) { in pr_report()
712 const QSPReportEntry *e = &rep->entries[i]; in pr_report() local
713 size_t len = strlen(e->callsite_at); in pr_report()
722 callsite_rspace = callsite_len - strlen("Call site"); in pr_report()
730 memset(dashes, '-', n_dashes); in pr_report()
734 for (i = 0; i < rep->n_entries; i++) { in pr_report()
735 const QSPReportEntry *e = &rep->entries[i]; in pr_report() local
738 g_string_append_printf(s, "%-9s ", e->typename); in pr_report()
739 if (e->n_objs > 1) { in pr_report()
740 g_string_append_printf(s, "[%12u]", e->n_objs); in pr_report()
742 g_string_append_printf(s, "%14p", e->obj); in pr_report()
745 e->callsite_at, in pr_report()
746 callsite_len - (int)strlen(e->callsite_at), "", in pr_report()
747 e->time_s, e->n_acqs, e->ns_avg * 1e-3); in pr_report()
748 qemu_printf("%s", s->str); in pr_report()
760 for (i = 0; i < rep->n_entries; i++) { in report_destroy()
761 QSPReportEntry *e = &rep->entries[i]; in report_destroy() local
763 g_free(e->callsite_at); in report_destroy()
765 g_free(rep->entries); in report_destroy()
790 qht_iter(&snap->ht, qsp_ht_delete, NULL); in qsp_snapshot_destroy()
791 qht_destroy(&snap->ht); in qsp_snapshot_destroy()
802 qht_init(&new->ht, qsp_entry_cmp, QSP_INITIAL_SIZE, in qsp_reset()
806 qht_iter(&qsp_ht, qsp_aggregate, &new->ht); in qsp_reset()