qsp.c (48008198270e3ebcc9394401d676c54ed5ac139c) qsp.c (d73415a315471ac0b127ed3fad45c8ec5d711de1)
1/*
2 * qsp.c - QEMU Synchronization Profiler
3 *
4 * Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
5 *
6 * License: GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
8 *

--- 231 unchanged lines hidden (view full) ---

240 qht_init(&qsp_ht, qsp_entry_cmp, QSP_INITIAL_SIZE,
241 QHT_MODE_AUTO_RESIZE | QHT_MODE_RAW_MUTEXES);
242 qht_init(&qsp_callsite_ht, qsp_callsite_cmp, QSP_INITIAL_SIZE,
243 QHT_MODE_AUTO_RESIZE | QHT_MODE_RAW_MUTEXES);
244}
245
246static __attribute__((noinline)) void qsp_init__slowpath(void)
247{
1/*
2 * qsp.c - QEMU Synchronization Profiler
3 *
4 * Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
5 *
6 * License: GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
8 *

--- 231 unchanged lines hidden (view full) ---

240 qht_init(&qsp_ht, qsp_entry_cmp, QSP_INITIAL_SIZE,
241 QHT_MODE_AUTO_RESIZE | QHT_MODE_RAW_MUTEXES);
242 qht_init(&qsp_callsite_ht, qsp_callsite_cmp, QSP_INITIAL_SIZE,
243 QHT_MODE_AUTO_RESIZE | QHT_MODE_RAW_MUTEXES);
244}
245
246static __attribute__((noinline)) void qsp_init__slowpath(void)
247{
248 if (atomic_cmpxchg(&qsp_initializing, false, true) == false) {
248 if (qatomic_cmpxchg(&qsp_initializing, false, true) == false) {
249 qsp_do_init();
249 qsp_do_init();
250 atomic_set(&qsp_initialized, true);
250 qatomic_set(&qsp_initialized, true);
251 } else {
251 } else {
252 while (!atomic_read(&qsp_initialized)) {
252 while (!qatomic_read(&qsp_initialized)) {
253 cpu_relax();
254 }
255 }
256}
257
258/* qsp_init() must be called from _all_ exported functions */
259static inline void qsp_init(void)
260{
253 cpu_relax();
254 }
255 }
256}
257
258/* qsp_init() must be called from _all_ exported functions */
259static inline void qsp_init(void)
260{
261 if (likely(atomic_read(&qsp_initialized))) {
261 if (likely(qatomic_read(&qsp_initialized))) {
262 return;
263 }
264 qsp_init__slowpath();
265}
266
267static QSPCallSite *qsp_callsite_find(const QSPCallSite *orig)
268{
269 QSPCallSite *callsite;

--- 71 unchanged lines hidden (view full) ---

341}
342
343/*
344 * @e is in the global hash table; it is only written to by the current thread,
345 * so we write to it atomically (as in "write once") to prevent torn reads.
346 */
347static inline void do_qsp_entry_record(QSPEntry *e, int64_t delta, bool acq)
348{
262 return;
263 }
264 qsp_init__slowpath();
265}
266
267static QSPCallSite *qsp_callsite_find(const QSPCallSite *orig)
268{
269 QSPCallSite *callsite;

--- 71 unchanged lines hidden (view full) ---

341}
342
343/*
344 * @e is in the global hash table; it is only written to by the current thread,
345 * so we write to it atomically (as in "write once") to prevent torn reads.
346 */
347static inline void do_qsp_entry_record(QSPEntry *e, int64_t delta, bool acq)
348{
349 atomic_set_u64(&e->ns, e->ns + delta);
349 qatomic_set_u64(&e->ns, e->ns + delta);
350 if (acq) {
350 if (acq) {
351 atomic_set_u64(&e->n_acqs, e->n_acqs + 1);
351 qatomic_set_u64(&e->n_acqs, e->n_acqs + 1);
352 }
353}
354
355static inline void qsp_entry_record(QSPEntry *e, int64_t delta)
356{
357 do_qsp_entry_record(e, delta, true);
358}
359

--- 67 unchanged lines hidden (view full) ---

427
428 e = qsp_entry_get(cond, file, line, QSP_CONDVAR);
429 qsp_entry_record(e, t1 - t0);
430 return ret;
431}
432
433bool qsp_is_enabled(void)
434{
352 }
353}
354
355static inline void qsp_entry_record(QSPEntry *e, int64_t delta)
356{
357 do_qsp_entry_record(e, delta, true);
358}
359

--- 67 unchanged lines hidden (view full) ---

427
428 e = qsp_entry_get(cond, file, line, QSP_CONDVAR);
429 qsp_entry_record(e, t1 - t0);
430 return ret;
431}
432
433bool qsp_is_enabled(void)
434{
435 return atomic_read(&qemu_mutex_lock_func) == qsp_mutex_lock;
435 return qatomic_read(&qemu_mutex_lock_func) == qsp_mutex_lock;
436}
437
438void qsp_enable(void)
439{
436}
437
438void qsp_enable(void)
439{
440 atomic_set(&qemu_mutex_lock_func, qsp_mutex_lock);
441 atomic_set(&qemu_mutex_trylock_func, qsp_mutex_trylock);
442 atomic_set(&qemu_bql_mutex_lock_func, qsp_bql_mutex_lock);
443 atomic_set(&qemu_rec_mutex_lock_func, qsp_rec_mutex_lock);
444 atomic_set(&qemu_rec_mutex_trylock_func, qsp_rec_mutex_trylock);
445 atomic_set(&qemu_cond_wait_func, qsp_cond_wait);
446 atomic_set(&qemu_cond_timedwait_func, qsp_cond_timedwait);
440 qatomic_set(&qemu_mutex_lock_func, qsp_mutex_lock);
441 qatomic_set(&qemu_mutex_trylock_func, qsp_mutex_trylock);
442 qatomic_set(&qemu_bql_mutex_lock_func, qsp_bql_mutex_lock);
443 qatomic_set(&qemu_rec_mutex_lock_func, qsp_rec_mutex_lock);
444 qatomic_set(&qemu_rec_mutex_trylock_func, qsp_rec_mutex_trylock);
445 qatomic_set(&qemu_cond_wait_func, qsp_cond_wait);
446 qatomic_set(&qemu_cond_timedwait_func, qsp_cond_timedwait);
447}
448
449void qsp_disable(void)
450{
447}
448
449void qsp_disable(void)
450{
451 atomic_set(&qemu_mutex_lock_func, qemu_mutex_lock_impl);
452 atomic_set(&qemu_mutex_trylock_func, qemu_mutex_trylock_impl);
453 atomic_set(&qemu_bql_mutex_lock_func, qemu_mutex_lock_impl);
454 atomic_set(&qemu_rec_mutex_lock_func, qemu_rec_mutex_lock_impl);
455 atomic_set(&qemu_rec_mutex_trylock_func, qemu_rec_mutex_trylock_impl);
456 atomic_set(&qemu_cond_wait_func, qemu_cond_wait_impl);
457 atomic_set(&qemu_cond_timedwait_func, qemu_cond_timedwait_impl);
451 qatomic_set(&qemu_mutex_lock_func, qemu_mutex_lock_impl);
452 qatomic_set(&qemu_mutex_trylock_func, qemu_mutex_trylock_impl);
453 qatomic_set(&qemu_bql_mutex_lock_func, qemu_mutex_lock_impl);
454 qatomic_set(&qemu_rec_mutex_lock_func, qemu_rec_mutex_lock_impl);
455 qatomic_set(&qemu_rec_mutex_trylock_func, qemu_rec_mutex_trylock_impl);
456 qatomic_set(&qemu_cond_wait_func, qemu_cond_wait_impl);
457 qatomic_set(&qemu_cond_timedwait_func, qemu_cond_timedwait_impl);
458}
459
460static gint qsp_tree_cmp(gconstpointer ap, gconstpointer bp, gpointer up)
461{
462 const QSPEntry *a = ap;
463 const QSPEntry *b = bp;
464 enum QSPSortBy sort_by = *(enum QSPSortBy *)up;
465 const QSPCallSite *ca;

--- 67 unchanged lines hidden (view full) ---

533 uint32_t hash;
534
535 hash = qsp_entry_no_thread_hash(e);
536 agg = qsp_entry_find(ht, e, hash);
537 /*
538 * The entry is in the global hash table; read from it atomically (as in
539 * "read once").
540 */
458}
459
460static gint qsp_tree_cmp(gconstpointer ap, gconstpointer bp, gpointer up)
461{
462 const QSPEntry *a = ap;
463 const QSPEntry *b = bp;
464 enum QSPSortBy sort_by = *(enum QSPSortBy *)up;
465 const QSPCallSite *ca;

--- 67 unchanged lines hidden (view full) ---

533 uint32_t hash;
534
535 hash = qsp_entry_no_thread_hash(e);
536 agg = qsp_entry_find(ht, e, hash);
537 /*
538 * The entry is in the global hash table; read from it atomically (as in
539 * "read once").
540 */
541 agg->ns += atomic_read_u64(&e->ns);
542 agg->n_acqs += atomic_read_u64(&e->n_acqs);
541 agg->ns += qatomic_read_u64(&e->ns);
542 agg->n_acqs += qatomic_read_u64(&e->n_acqs);
543}
544
545static void qsp_iter_diff(void *p, uint32_t hash, void *htp)
546{
547 struct qht *ht = htp;
548 QSPEntry *old = p;
549 QSPEntry *new;
550

--- 54 unchanged lines hidden (view full) ---

605 * First, see if there's a prior snapshot, so that we read the global hash
606 * table _after_ the snapshot has been created, which guarantees that
607 * the entries we'll read will be a superset of the snapshot's entries.
608 *
609 * We must remain in an RCU read-side critical section until we're done
610 * with the snapshot.
611 */
612 WITH_RCU_READ_LOCK_GUARD() {
543}
544
545static void qsp_iter_diff(void *p, uint32_t hash, void *htp)
546{
547 struct qht *ht = htp;
548 QSPEntry *old = p;
549 QSPEntry *new;
550

--- 54 unchanged lines hidden (view full) ---

605 * First, see if there's a prior snapshot, so that we read the global hash
606 * table _after_ the snapshot has been created, which guarantees that
607 * the entries we'll read will be a superset of the snapshot's entries.
608 *
609 * We must remain in an RCU read-side critical section until we're done
610 * with the snapshot.
611 */
612 WITH_RCU_READ_LOCK_GUARD() {
613 QSPSnapshot *snap = atomic_rcu_read(&qsp_snapshot);
613 QSPSnapshot *snap = qatomic_rcu_read(&qsp_snapshot);
614
615 /* Aggregate all results from the global hash table into a local one */
616 qht_init(&ht, qsp_entry_no_thread_cmp, QSP_INITIAL_SIZE,
617 QHT_MODE_AUTO_RESIZE | QHT_MODE_RAW_MUTEXES);
618 qht_iter(&qsp_ht, qsp_aggregate, &ht);
619
620 /* compute the difference wrt the snapshot, if any */
621 if (snap) {

--- 179 unchanged lines hidden (view full) ---

801
802 qht_init(&new->ht, qsp_entry_cmp, QSP_INITIAL_SIZE,
803 QHT_MODE_AUTO_RESIZE | QHT_MODE_RAW_MUTEXES);
804
805 /* take a snapshot of the current state */
806 qht_iter(&qsp_ht, qsp_aggregate, &new->ht);
807
808 /* replace the previous snapshot, if any */
614
615 /* Aggregate all results from the global hash table into a local one */
616 qht_init(&ht, qsp_entry_no_thread_cmp, QSP_INITIAL_SIZE,
617 QHT_MODE_AUTO_RESIZE | QHT_MODE_RAW_MUTEXES);
618 qht_iter(&qsp_ht, qsp_aggregate, &ht);
619
620 /* compute the difference wrt the snapshot, if any */
621 if (snap) {

--- 179 unchanged lines hidden (view full) ---

801
802 qht_init(&new->ht, qsp_entry_cmp, QSP_INITIAL_SIZE,
803 QHT_MODE_AUTO_RESIZE | QHT_MODE_RAW_MUTEXES);
804
805 /* take a snapshot of the current state */
806 qht_iter(&qsp_ht, qsp_aggregate, &new->ht);
807
808 /* replace the previous snapshot, if any */
809 old = atomic_xchg(&qsp_snapshot, new);
809 old = qatomic_xchg(&qsp_snapshot, new);
810 if (old) {
811 call_rcu(old, qsp_snapshot_destroy, rcu);
812 }
813}
810 if (old) {
811 call_rcu(old, qsp_snapshot_destroy, rcu);
812 }
813}