xref: /freebsd/sys/kern/subr_lock.c (revision 83b72e3e25f7ea7a6158e9cf5933b280491a1d4c)
183a81bcbSJohn Baldwin /*-
283a81bcbSJohn Baldwin  * Copyright (c) 2006 John Baldwin <jhb@FreeBSD.org>
383a81bcbSJohn Baldwin  * All rights reserved.
483a81bcbSJohn Baldwin  *
583a81bcbSJohn Baldwin  * Redistribution and use in source and binary forms, with or without
683a81bcbSJohn Baldwin  * modification, are permitted provided that the following conditions
783a81bcbSJohn Baldwin  * are met:
883a81bcbSJohn Baldwin  * 1. Redistributions of source code must retain the above copyright
983a81bcbSJohn Baldwin  *    notice, this list of conditions and the following disclaimer.
1083a81bcbSJohn Baldwin  * 2. Redistributions in binary form must reproduce the above copyright
1183a81bcbSJohn Baldwin  *    notice, this list of conditions and the following disclaimer in the
1283a81bcbSJohn Baldwin  *    documentation and/or other materials provided with the distribution.
1383a81bcbSJohn Baldwin  * 3. Neither the name of the author nor the names of any co-contributors
1483a81bcbSJohn Baldwin  *    may be used to endorse or promote products derived from this software
1583a81bcbSJohn Baldwin  *    without specific prior written permission.
1683a81bcbSJohn Baldwin  *
1783a81bcbSJohn Baldwin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1883a81bcbSJohn Baldwin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1983a81bcbSJohn Baldwin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2083a81bcbSJohn Baldwin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2183a81bcbSJohn Baldwin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2283a81bcbSJohn Baldwin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2383a81bcbSJohn Baldwin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2483a81bcbSJohn Baldwin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2583a81bcbSJohn Baldwin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2683a81bcbSJohn Baldwin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2783a81bcbSJohn Baldwin  * SUCH DAMAGE.
2883a81bcbSJohn Baldwin  */
2983a81bcbSJohn Baldwin 
3083a81bcbSJohn Baldwin /*
3183a81bcbSJohn Baldwin  * This module holds the global variables and functions used to maintain
3283a81bcbSJohn Baldwin  * lock_object structures.
3383a81bcbSJohn Baldwin  */
3483a81bcbSJohn Baldwin 
3583a81bcbSJohn Baldwin #include <sys/cdefs.h>
3683a81bcbSJohn Baldwin __FBSDID("$FreeBSD$");
3783a81bcbSJohn Baldwin 
386ef970a9SJohn Baldwin #include "opt_ddb.h"
397c0435b9SKip Macy #include "opt_mprof.h"
406ef970a9SJohn Baldwin 
4183a81bcbSJohn Baldwin #include <sys/param.h>
4283a81bcbSJohn Baldwin #include <sys/systm.h>
4383a81bcbSJohn Baldwin #include <sys/ktr.h>
446ef970a9SJohn Baldwin #include <sys/linker_set.h>
4583a81bcbSJohn Baldwin #include <sys/lock.h>
467c0435b9SKip Macy #include <sys/sbuf.h>
477c0435b9SKip Macy #include <sys/sysctl.h>
487c0435b9SKip Macy #include <sys/lock_profile.h>
4983a81bcbSJohn Baldwin 
5083a81bcbSJohn Baldwin #ifdef DDB
5183a81bcbSJohn Baldwin #include <ddb/ddb.h>
5283a81bcbSJohn Baldwin #endif
5383a81bcbSJohn Baldwin 
5483a81bcbSJohn Baldwin CTASSERT(LOCK_CLASS_MAX == 15);
5583a81bcbSJohn Baldwin 
5683a81bcbSJohn Baldwin struct lock_class *lock_classes[LOCK_CLASS_MAX + 1] = {
5783a81bcbSJohn Baldwin 	&lock_class_mtx_spin,
5883a81bcbSJohn Baldwin 	&lock_class_mtx_sleep,
5983a81bcbSJohn Baldwin 	&lock_class_sx,
603f08bd8bSJohn Baldwin 	&lock_class_rw,
6183a81bcbSJohn Baldwin };
6283a81bcbSJohn Baldwin 
637c0435b9SKip Macy #ifdef LOCK_PROFILING
647c0435b9SKip Macy #include <machine/cpufunc.h>
657c0435b9SKip Macy 
667c0435b9SKip Macy SYSCTL_NODE(_debug, OID_AUTO, lock, CTLFLAG_RD, NULL, "lock debugging");
677c0435b9SKip Macy SYSCTL_NODE(_debug_lock, OID_AUTO, prof, CTLFLAG_RD, NULL, "lock profiling");
687c0435b9SKip Macy int lock_prof_enable = 0;
697c0435b9SKip Macy SYSCTL_INT(_debug_lock_prof, OID_AUTO, enable, CTLFLAG_RW,
707c0435b9SKip Macy     &lock_prof_enable, 0, "Enable lock profiling");
717c0435b9SKip Macy 
727c0435b9SKip Macy /*
737c0435b9SKip Macy  * lprof_buf is a static pool of profiling records to avoid possible
747c0435b9SKip Macy  * reentrance of the memory allocation functions.
757c0435b9SKip Macy  *
767c0435b9SKip Macy  * Note: NUM_LPROF_BUFFERS must be smaller than LPROF_HASH_SIZE.
777c0435b9SKip Macy  */
787c0435b9SKip Macy struct lock_prof lprof_buf[LPROF_HASH_SIZE];
797c0435b9SKip Macy static int allocated_lprof_buf;
807c0435b9SKip Macy struct mtx lprof_locks[LPROF_LOCK_SIZE];
817c0435b9SKip Macy 
827c0435b9SKip Macy 
837c0435b9SKip Macy /* SWAG: sbuf size = avg stat. line size * number of locks */
847c0435b9SKip Macy #define LPROF_SBUF_SIZE		256 * 400
857c0435b9SKip Macy 
867c0435b9SKip Macy static int lock_prof_acquisitions;
877c0435b9SKip Macy SYSCTL_INT(_debug_lock_prof, OID_AUTO, acquisitions, CTLFLAG_RD,
8883b72e3eSKip Macy     &lock_prof_acquisitions, 0, "Number of lock acquistions recorded");
897c0435b9SKip Macy static int lock_prof_records;
907c0435b9SKip Macy SYSCTL_INT(_debug_lock_prof, OID_AUTO, records, CTLFLAG_RD,
917c0435b9SKip Macy     &lock_prof_records, 0, "Number of profiling records");
927c0435b9SKip Macy static int lock_prof_maxrecords = LPROF_HASH_SIZE;
937c0435b9SKip Macy SYSCTL_INT(_debug_lock_prof, OID_AUTO, maxrecords, CTLFLAG_RD,
947c0435b9SKip Macy     &lock_prof_maxrecords, 0, "Maximum number of profiling records");
957c0435b9SKip Macy static int lock_prof_rejected;
967c0435b9SKip Macy SYSCTL_INT(_debug_lock_prof, OID_AUTO, rejected, CTLFLAG_RD,
977c0435b9SKip Macy     &lock_prof_rejected, 0, "Number of rejected profiling records");
987c0435b9SKip Macy static int lock_prof_hashsize = LPROF_HASH_SIZE;
997c0435b9SKip Macy SYSCTL_INT(_debug_lock_prof, OID_AUTO, hashsize, CTLFLAG_RD,
1007c0435b9SKip Macy     &lock_prof_hashsize, 0, "Hash size");
1017c0435b9SKip Macy static int lock_prof_collisions = 0;
1027c0435b9SKip Macy SYSCTL_INT(_debug_lock_prof, OID_AUTO, collisions, CTLFLAG_RD,
1037c0435b9SKip Macy     &lock_prof_collisions, 0, "Number of hash collisions");
1047c0435b9SKip Macy 
1057c0435b9SKip Macy #ifndef USE_CPU_NANOSECONDS
1067c0435b9SKip Macy static u_int64_t
1077c0435b9SKip Macy nanoseconds(void)
1087c0435b9SKip Macy {
1097c0435b9SKip Macy 	struct timespec tv;
1107c0435b9SKip Macy 
1117c0435b9SKip Macy 	nanotime(&tv);
1127c0435b9SKip Macy 	return (tv.tv_sec * (u_int64_t)1000000000 + tv.tv_nsec);
1137c0435b9SKip Macy }
1147c0435b9SKip Macy #endif
1157c0435b9SKip Macy 
1167c0435b9SKip Macy static int
1177c0435b9SKip Macy dump_lock_prof_stats(SYSCTL_HANDLER_ARGS)
1187c0435b9SKip Macy {
1197c0435b9SKip Macy         struct sbuf *sb;
1207c0435b9SKip Macy         int error, i;
1217c0435b9SKip Macy         static int multiplier = 1;
1227c0435b9SKip Macy         const char *p;
1237c0435b9SKip Macy 
1247c0435b9SKip Macy         if (allocated_lprof_buf == 0)
1257c0435b9SKip Macy                 return (SYSCTL_OUT(req, "No locking recorded",
1267c0435b9SKip Macy                     sizeof("No locking recorded")));
1277c0435b9SKip Macy 
1287c0435b9SKip Macy retry_sbufops:
1297c0435b9SKip Macy         sb = sbuf_new(NULL, NULL, LPROF_SBUF_SIZE * multiplier, SBUF_FIXEDLEN);
1307c0435b9SKip Macy         sbuf_printf(sb, "\n%6s %12s %12s %11s %5s %5s %12s %12s %s\n",
1317c0435b9SKip Macy             "max", "total", "wait_total", "count", "avg", "wait_avg", "cnt_hold", "cn\
1327c0435b9SKip Macy t_lock", "name");
1337c0435b9SKip Macy         for (i = 0; i < LPROF_HASH_SIZE; ++i) {
1347c0435b9SKip Macy                 if (lprof_buf[i].name == NULL)
1357c0435b9SKip Macy                         continue;
1367c0435b9SKip Macy                 for (p = lprof_buf[i].file;
1377c0435b9SKip Macy                         p != NULL && strncmp(p, "../", 3) == 0; p += 3)
1387c0435b9SKip Macy                                 /* nothing */ ;
1397c0435b9SKip Macy                 sbuf_printf(sb, "%6ju %12ju %12ju %11ju %5ju %5ju %12ju %12ju %s:%d (\
1407c0435b9SKip Macy %s)\n",
1417c0435b9SKip Macy                     lprof_buf[i].cnt_max / 1000,
1427c0435b9SKip Macy                     lprof_buf[i].cnt_tot / 1000,
1437c0435b9SKip Macy                     lprof_buf[i].cnt_wait / 1000,
1447c0435b9SKip Macy                     lprof_buf[i].cnt_cur,
1457c0435b9SKip Macy                     lprof_buf[i].cnt_cur == 0 ? (uintmax_t)0 :
1467c0435b9SKip Macy                         lprof_buf[i].cnt_tot / (lprof_buf[i].cnt_cur * 1000),
1477c0435b9SKip Macy                     lprof_buf[i].cnt_cur == 0 ? (uintmax_t)0 :
1487c0435b9SKip Macy                         lprof_buf[i].cnt_wait / (lprof_buf[i].cnt_cur * 1000),
1497c0435b9SKip Macy                     lprof_buf[i].cnt_contest_holding,
1507c0435b9SKip Macy                     lprof_buf[i].cnt_contest_locking,
1517c0435b9SKip Macy                     p, lprof_buf[i].line, lprof_buf[i].name);
1527c0435b9SKip Macy                 if (sbuf_overflowed(sb)) {
1537c0435b9SKip Macy                         sbuf_delete(sb);
1547c0435b9SKip Macy                         multiplier++;
1557c0435b9SKip Macy                         goto retry_sbufops;
1567c0435b9SKip Macy                 }
1577c0435b9SKip Macy         }
1587c0435b9SKip Macy 
1597c0435b9SKip Macy         sbuf_finish(sb);
1607c0435b9SKip Macy         error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1);
1617c0435b9SKip Macy         sbuf_delete(sb);
1627c0435b9SKip Macy         return (error);
1637c0435b9SKip Macy }
1647c0435b9SKip Macy static int
1657c0435b9SKip Macy reset_lock_prof_stats(SYSCTL_HANDLER_ARGS)
1667c0435b9SKip Macy {
1677c0435b9SKip Macy         int error, v;
1687c0435b9SKip Macy 
1697c0435b9SKip Macy         if (allocated_lprof_buf == 0)
1707c0435b9SKip Macy                 return (0);
1717c0435b9SKip Macy 
1727c0435b9SKip Macy         v = 0;
1737c0435b9SKip Macy         error = sysctl_handle_int(oidp, &v, 0, req);
1747c0435b9SKip Macy         if (error)
1757c0435b9SKip Macy                 return (error);
1767c0435b9SKip Macy         if (req->newptr == NULL)
1777c0435b9SKip Macy                 return (error);
1787c0435b9SKip Macy         if (v == 0)
1797c0435b9SKip Macy                 return (0);
1807c0435b9SKip Macy 
1817c0435b9SKip Macy         bzero(lprof_buf, LPROF_HASH_SIZE*sizeof(*lprof_buf));
1827c0435b9SKip Macy         allocated_lprof_buf = 0;
1837c0435b9SKip Macy         return (0);
1847c0435b9SKip Macy }
1857c0435b9SKip Macy 
1867c0435b9SKip Macy SYSCTL_PROC(_debug_lock_prof, OID_AUTO, stats, CTLTYPE_STRING | CTLFLAG_RD,
18783b72e3eSKip Macy     NULL, 0, dump_lock_prof_stats, "A", "Lock profiling statistics");
1887c0435b9SKip Macy 
1897c0435b9SKip Macy SYSCTL_PROC(_debug_lock_prof, OID_AUTO, reset, CTLTYPE_INT | CTLFLAG_RW,
19083b72e3eSKip Macy     NULL, 0, reset_lock_prof_stats, "I", "Reset lock profiling statistics");
1917c0435b9SKip Macy #endif
1927c0435b9SKip Macy 
19383a81bcbSJohn Baldwin void
19483a81bcbSJohn Baldwin lock_init(struct lock_object *lock, struct lock_class *class, const char *name,
19583a81bcbSJohn Baldwin     const char *type, int flags)
19683a81bcbSJohn Baldwin {
19783a81bcbSJohn Baldwin 	int i;
19883a81bcbSJohn Baldwin 
19983a81bcbSJohn Baldwin 	/* Check for double-init and zero object. */
20083a81bcbSJohn Baldwin 	KASSERT(!lock_initalized(lock), ("lock \"%s\" %p already initialized",
20183a81bcbSJohn Baldwin 	    name, lock));
20283a81bcbSJohn Baldwin 
20383a81bcbSJohn Baldwin 	/* Look up lock class to find its index. */
20483a81bcbSJohn Baldwin 	for (i = 0; i < LOCK_CLASS_MAX; i++)
20583a81bcbSJohn Baldwin 		if (lock_classes[i] == class) {
20683a81bcbSJohn Baldwin 			lock->lo_flags = i << LO_CLASSSHIFT;
20783a81bcbSJohn Baldwin 			break;
20883a81bcbSJohn Baldwin 		}
20983a81bcbSJohn Baldwin 	KASSERT(i < LOCK_CLASS_MAX, ("unknown lock class %p", class));
21083a81bcbSJohn Baldwin 
21183a81bcbSJohn Baldwin 	/* Initialize the lock object. */
21283a81bcbSJohn Baldwin 	lock->lo_name = name;
21383a81bcbSJohn Baldwin 	lock->lo_type = type != NULL ? type : name;
21483a81bcbSJohn Baldwin 	lock->lo_flags |= flags | LO_INITIALIZED;
21583a81bcbSJohn Baldwin 	LOCK_LOG_INIT(lock, 0);
21683a81bcbSJohn Baldwin 	WITNESS_INIT(lock);
21783a81bcbSJohn Baldwin }
21883a81bcbSJohn Baldwin 
21983a81bcbSJohn Baldwin void
22083a81bcbSJohn Baldwin lock_destroy(struct lock_object *lock)
22183a81bcbSJohn Baldwin {
22283a81bcbSJohn Baldwin 
22383a81bcbSJohn Baldwin 	KASSERT(lock_initalized(lock), ("lock %p is not initialized", lock));
22483a81bcbSJohn Baldwin 	WITNESS_DESTROY(lock);
22583a81bcbSJohn Baldwin 	LOCK_LOG_DESTROY(lock, 0);
22683a81bcbSJohn Baldwin 	lock->lo_flags &= ~LO_INITIALIZED;
22783a81bcbSJohn Baldwin }
22883a81bcbSJohn Baldwin 
22983a81bcbSJohn Baldwin #ifdef DDB
23083a81bcbSJohn Baldwin DB_SHOW_COMMAND(lock, db_show_lock)
23183a81bcbSJohn Baldwin {
23283a81bcbSJohn Baldwin 	struct lock_object *lock;
23383a81bcbSJohn Baldwin 	struct lock_class *class;
23483a81bcbSJohn Baldwin 
23583a81bcbSJohn Baldwin 	if (!have_addr)
23683a81bcbSJohn Baldwin 		return;
23783a81bcbSJohn Baldwin 	lock = (struct lock_object *)addr;
23883a81bcbSJohn Baldwin 	if (LO_CLASSINDEX(lock) > LOCK_CLASS_MAX) {
23983a81bcbSJohn Baldwin 		db_printf("Unknown lock class: %d\n", LO_CLASSINDEX(lock));
24083a81bcbSJohn Baldwin 		return;
24183a81bcbSJohn Baldwin 	}
24283a81bcbSJohn Baldwin 	class = LOCK_CLASS(lock);
24383a81bcbSJohn Baldwin 	db_printf(" class: %s\n", class->lc_name);
24483a81bcbSJohn Baldwin 	db_printf(" name: %s\n", lock->lo_name);
24583a81bcbSJohn Baldwin 	if (lock->lo_type && lock->lo_type != lock->lo_name)
24683a81bcbSJohn Baldwin 		db_printf(" type: %s\n", lock->lo_type);
24783a81bcbSJohn Baldwin 	class->lc_ddb_show(lock);
24883a81bcbSJohn Baldwin }
24983a81bcbSJohn Baldwin #endif
2507c0435b9SKip Macy 
2517c0435b9SKip Macy #ifdef LOCK_PROFILING
2527c0435b9SKip Macy void _lock_profile_obtain_lock_success(struct lock_object *lo, uint64_t waittime, con\
2537c0435b9SKip Macy st char *file, int line)
2547c0435b9SKip Macy {
2557c0435b9SKip Macy         struct lock_profile_object *l = &lo->lo_profile_obj;
2567c0435b9SKip Macy 
2577c0435b9SKip Macy         /* don't reset the timer when/if recursing */
2587c0435b9SKip Macy         if (l->lpo_acqtime == 0) {
2597c0435b9SKip Macy                 l->lpo_filename = file;
2607c0435b9SKip Macy                 l->lpo_lineno = line;
2617c0435b9SKip Macy                 l->lpo_acqtime = nanoseconds();
2627c0435b9SKip Macy                 if (waittime) {
2637c0435b9SKip Macy                         if (l->lpo_acqtime > waittime)
2647c0435b9SKip Macy                                 l->lpo_waittime = l->lpo_acqtime - waittime;
2657c0435b9SKip Macy                 }
2667c0435b9SKip Macy         }
2677c0435b9SKip Macy }
2687c0435b9SKip Macy 
2697c0435b9SKip Macy void _lock_profile_update_wait(struct lock_object *lo, uint64_t waitstart)
2707c0435b9SKip Macy {
2717c0435b9SKip Macy         struct lock_profile_object *l = &lo->lo_profile_obj;
2727c0435b9SKip Macy 
2737c0435b9SKip Macy         if (lock_prof_enable && waitstart) {
2747c0435b9SKip Macy                 uint64_t now, waittime;
2757c0435b9SKip Macy                 struct lock_prof *mpp;
2767c0435b9SKip Macy                 u_int hash;
2777c0435b9SKip Macy                 const char *p = l->lpo_filename;
2787c0435b9SKip Macy                 int collision = 0;
2797c0435b9SKip Macy                 now = nanoseconds();
2807c0435b9SKip Macy                 if (now < waitstart)
2817c0435b9SKip Macy                         return;
2827c0435b9SKip Macy                 waittime = now - waitstart;
2837c0435b9SKip Macy                 hash = (l->lpo_namehash * 31 * 31 + (uintptr_t)p * 31 + l->lpo_lineno) & LPROF_HASH_MASK;
2847c0435b9SKip Macy 
2857c0435b9SKip Macy                 mpp = &lprof_buf[hash];
2867c0435b9SKip Macy                 while (mpp->name != NULL) {
2877c0435b9SKip Macy                         if (mpp->line == l->lpo_lineno &&
2887c0435b9SKip Macy                           mpp->file == p &&
2897c0435b9SKip Macy                           mpp->namehash == l->lpo_namehash)
2907c0435b9SKip Macy                                 break;
2917c0435b9SKip Macy                         /* If the lprof_hash entry is allocated to someone else, try the next one */
2927c0435b9SKip Macy                         collision = 1;
2937c0435b9SKip Macy                         CTR4(KTR_SPARE1, "Hash collision, %s:%d %s(%x)", mpp->file, mpp->line, mpp->name, mpp->namehash);
2947c0435b9SKip Macy                         hash = (hash + 1) & LPROF_HASH_MASK;
2957c0435b9SKip Macy                         mpp = &lprof_buf[hash];
2967c0435b9SKip Macy                 }
2977c0435b9SKip Macy                 if (mpp->name == NULL) {
2987c0435b9SKip Macy                         int buf;
2997c0435b9SKip Macy 
3007c0435b9SKip Macy                         buf = atomic_fetchadd_int(&allocated_lprof_buf, 1);
3017c0435b9SKip Macy                         /* Just exit if we cannot get a trace buffer */
3027c0435b9SKip Macy                         if (buf >= LPROF_HASH_SIZE) {
3037c0435b9SKip Macy                                 ++lock_prof_rejected;
3047c0435b9SKip Macy                                 return;
3057c0435b9SKip Macy                         }
3067c0435b9SKip Macy                         mpp->file = p;
3077c0435b9SKip Macy                         mpp->line = l->lpo_lineno;
3087c0435b9SKip Macy                         mpp->name = lo->lo_name;
3097c0435b9SKip Macy                         mpp->namehash = l->lpo_namehash;
3107c0435b9SKip Macy                         if (collision)
3117c0435b9SKip Macy                                 ++lock_prof_collisions;
3127c0435b9SKip Macy                         /* We might have raced someone else but who cares, they'll try again next time */
3137c0435b9SKip Macy                         ++lock_prof_records;
3147c0435b9SKip Macy                 }
3157c0435b9SKip Macy                 LPROF_LOCK(hash);
3167c0435b9SKip Macy                 mpp->cnt_wait += waittime;
3177c0435b9SKip Macy                 LPROF_UNLOCK(hash);
3187c0435b9SKip Macy         }
3197c0435b9SKip Macy }
3207c0435b9SKip Macy 
3217c0435b9SKip Macy void _lock_profile_release_lock(struct lock_object *lo)
3227c0435b9SKip Macy {
3237c0435b9SKip Macy         struct lock_profile_object *l = &lo->lo_profile_obj;
3247c0435b9SKip Macy 
3257c0435b9SKip Macy         if (l->lpo_acqtime && !(lo->lo_flags & LO_NOPROFILE)) {
3267c0435b9SKip Macy                 const char *unknown = "(unknown)";
3277c0435b9SKip Macy                 u_int64_t acqtime, now, waittime;
3287c0435b9SKip Macy                 struct lock_prof *mpp;
3297c0435b9SKip Macy                 u_int hash;
3307c0435b9SKip Macy                 const char *p = l->lpo_filename;
3317c0435b9SKip Macy                 int collision = 0;
3327c0435b9SKip Macy 
3337c0435b9SKip Macy                 now = nanoseconds();
3347c0435b9SKip Macy                 acqtime = l->lpo_acqtime;
3357c0435b9SKip Macy                 waittime = l->lpo_waittime;
3367c0435b9SKip Macy                 if (now <= acqtime)
3377c0435b9SKip Macy                         return;
3387c0435b9SKip Macy                 if (p == NULL || *p == '\0')
3397c0435b9SKip Macy                         p = unknown;
3407c0435b9SKip Macy                 hash = (l->lpo_namehash * 31 * 31 + (uintptr_t)p * 31 + l->lpo_lineno) & LPROF_HASH_MASK;
3417c0435b9SKip Macy                 CTR5(KTR_SPARE1, "Hashing %s(%x) %s:%d to %d", l->lpo_name,
3427c0435b9SKip Macy 		     l->lpo_namehash, p, l->lpo_lineno, hash);
3437c0435b9SKip Macy                 mpp = &lprof_buf[hash];
3447c0435b9SKip Macy                 while (mpp->name != NULL) {
3457c0435b9SKip Macy                         if (mpp->line == l->lpo_lineno &&
3467c0435b9SKip Macy                           mpp->file == p &&
3477c0435b9SKip Macy                           mpp->namehash == l->lpo_namehash)
3487c0435b9SKip Macy                                 break;
3497c0435b9SKip Macy                         /* If the lprof_hash entry is allocated to someone
3507c0435b9SKip Macy 			 * else, try the next one
3517c0435b9SKip Macy 			 */
3527c0435b9SKip Macy                         collision = 1;
3537c0435b9SKip Macy                         CTR4(KTR_SPARE1, "Hash collision, %s:%d %s(%x)", mpp->file,
3547c0435b9SKip Macy 			     mpp->line, mpp->name, mpp->namehash);
3557c0435b9SKip Macy                         hash = (hash + 1) & LPROF_HASH_MASK;
3567c0435b9SKip Macy                         mpp = &lprof_buf[hash];
3577c0435b9SKip Macy                 }
3587c0435b9SKip Macy                 if (mpp->name == NULL) {
3597c0435b9SKip Macy                         int buf;
3607c0435b9SKip Macy 
3617c0435b9SKip Macy                         buf = atomic_fetchadd_int(&allocated_lprof_buf, 1);
3627c0435b9SKip Macy                         /* Just exit if we cannot get a trace buffer */
3637c0435b9SKip Macy                         if (buf >= LPROF_HASH_SIZE) {
3647c0435b9SKip Macy                                 ++lock_prof_rejected;
3657c0435b9SKip Macy                                 return;
3667c0435b9SKip Macy                         }
3677c0435b9SKip Macy                         mpp->file = p;
3687c0435b9SKip Macy                         mpp->line = l->lpo_lineno;
3697c0435b9SKip Macy                         mpp->name = lo->lo_name;
3707c0435b9SKip Macy                         mpp->namehash = l->lpo_namehash;
3717c0435b9SKip Macy                         if (collision)
3727c0435b9SKip Macy                                 ++lock_prof_collisions;
3737c0435b9SKip Macy 
3747c0435b9SKip Macy                         /*
3757c0435b9SKip Macy 			 * We might have raced someone else but who cares,
3767c0435b9SKip Macy 			 * they'll try again next time
3777c0435b9SKip Macy 			 */
3787c0435b9SKip Macy                         ++lock_prof_records;
3797c0435b9SKip Macy                 }
3807c0435b9SKip Macy                 LPROF_LOCK(hash);
3817c0435b9SKip Macy                 /*
38283b72e3eSKip Macy                  * Record if the lock has been held longer now than ever
3837c0435b9SKip Macy                  * before.
3847c0435b9SKip Macy                  */
3857c0435b9SKip Macy                 if (now - acqtime > mpp->cnt_max)
3867c0435b9SKip Macy                         mpp->cnt_max = now - acqtime;
3877c0435b9SKip Macy                 mpp->cnt_tot += now - acqtime;
3887c0435b9SKip Macy                 mpp->cnt_wait += waittime;
3897c0435b9SKip Macy                 mpp->cnt_cur++;
3907c0435b9SKip Macy                 /*
3917c0435b9SKip Macy                  * There's a small race, really we should cmpxchg
3927c0435b9SKip Macy                  * 0 with the current value, but that would bill
3937c0435b9SKip Macy                  * the contention to the wrong lock instance if
3947c0435b9SKip Macy                  * it followed this also.
3957c0435b9SKip Macy                  */
3967c0435b9SKip Macy                 mpp->cnt_contest_holding += l->lpo_contest_holding;
3977c0435b9SKip Macy                 mpp->cnt_contest_locking += l->lpo_contest_locking;
3987c0435b9SKip Macy                 LPROF_UNLOCK(hash);
3997c0435b9SKip Macy 
4007c0435b9SKip Macy         }
4017c0435b9SKip Macy         l->lpo_acqtime = 0;
4027c0435b9SKip Macy         l->lpo_waittime = 0;
4037c0435b9SKip Macy         l->lpo_contest_locking = 0;
4047c0435b9SKip Macy         l->lpo_contest_holding = 0;
4057c0435b9SKip Macy }
4067c0435b9SKip Macy #endif
407