1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996,2008 Oracle. All rights reserved. 5 * 6 * $Id: mut_stat.c,v 12.30 2008/01/08 20:58:43 bostic Exp $ 7 */ 8 9#include "db_config.h" 10 11#include "db_int.h" 12#include "dbinc/db_page.h" 13#include "dbinc/db_am.h" 14#include "dbinc/mutex_int.h" 15 16#ifdef HAVE_STATISTICS 17static int __mutex_print_all __P((ENV *, u_int32_t)); 18static const char *__mutex_print_id __P((int)); 19static int __mutex_print_stats __P((ENV *, u_int32_t)); 20static void __mutex_print_summary __P((ENV *)); 21static int __mutex_stat __P((ENV *, DB_MUTEX_STAT **, u_int32_t)); 22 23/* 24 * __mutex_stat_pp -- 25 * ENV->mutex_stat pre/post processing. 26 * 27 * PUBLIC: int __mutex_stat_pp __P((DB_ENV *, DB_MUTEX_STAT **, u_int32_t)); 28 */ 29int 30__mutex_stat_pp(dbenv, statp, flags) 31 DB_ENV *dbenv; 32 DB_MUTEX_STAT **statp; 33 u_int32_t flags; 34{ 35 DB_THREAD_INFO *ip; 36 ENV *env; 37 int ret; 38 39 env = dbenv->env; 40 41 if ((ret = __db_fchk(env, 42 "DB_ENV->mutex_stat", flags, DB_STAT_CLEAR)) != 0) 43 return (ret); 44 45 ENV_ENTER(env, ip); 46 REPLICATION_WRAP(env, (__mutex_stat(env, statp, flags)), 0, ret); 47 ENV_LEAVE(env, ip); 48 return (ret); 49} 50 51/* 52 * __mutex_stat -- 53 * ENV->mutex_stat. 54 */ 55static int 56__mutex_stat(env, statp, flags) 57 ENV *env; 58 DB_MUTEX_STAT **statp; 59 u_int32_t flags; 60{ 61 DB_MUTEXMGR *mtxmgr; 62 DB_MUTEXREGION *mtxregion; 63 DB_MUTEX_STAT *stats; 64 int ret; 65 66 *statp = NULL; 67 mtxmgr = env->mutex_handle; 68 mtxregion = mtxmgr->reginfo.primary; 69 70 if ((ret = __os_umalloc(env, sizeof(DB_MUTEX_STAT), &stats)) != 0) 71 return (ret); 72 73 MUTEX_SYSTEM_LOCK(env); 74 75 /* 76 * Most fields are maintained in the underlying region structure. 77 * Region size and region mutex are not. 78 */ 79 *stats = mtxregion->stat; 80 stats->st_regsize = mtxmgr->reginfo.rp->size; 81 __mutex_set_wait_info(env, mtxregion->mtx_region, 82 &stats->st_region_wait, &stats->st_region_nowait); 83 if (LF_ISSET(DB_STAT_CLEAR)) 84 __mutex_clear(env, mtxregion->mtx_region); 85 86 MUTEX_SYSTEM_UNLOCK(env); 87 88 *statp = stats; 89 return (0); 90} 91 92/* 93 * __mutex_stat_print_pp -- 94 * ENV->mutex_stat_print pre/post processing. 95 * 96 * PUBLIC: int __mutex_stat_print_pp __P((DB_ENV *, u_int32_t)); 97 */ 98int 99__mutex_stat_print_pp(dbenv, flags) 100 DB_ENV *dbenv; 101 u_int32_t flags; 102{ 103 DB_THREAD_INFO *ip; 104 ENV *env; 105 int ret; 106 107 env = dbenv->env; 108 109 if ((ret = __db_fchk(env, "DB_ENV->mutex_stat_print", 110 flags, DB_STAT_ALL | DB_STAT_CLEAR)) != 0) 111 return (ret); 112 113 ENV_ENTER(env, ip); 114 REPLICATION_WRAP(env, (__mutex_stat_print(env, flags)), 0, ret); 115 ENV_LEAVE(env, ip); 116 return (ret); 117} 118 119/* 120 * __mutex_stat_print 121 * ENV->mutex_stat_print method. 122 * 123 * PUBLIC: int __mutex_stat_print __P((ENV *, u_int32_t)); 124 */ 125int 126__mutex_stat_print(env, flags) 127 ENV *env; 128 u_int32_t flags; 129{ 130 u_int32_t orig_flags; 131 int ret; 132 133 orig_flags = flags; 134 LF_CLR(DB_STAT_CLEAR | DB_STAT_SUBSYSTEM); 135 if (flags == 0 || LF_ISSET(DB_STAT_ALL)) { 136 ret = __mutex_print_stats(env, orig_flags); 137 __mutex_print_summary(env); 138 if (flags == 0 || ret != 0) 139 return (ret); 140 } 141 142 if (LF_ISSET(DB_STAT_ALL)) 143 ret = __mutex_print_all(env, orig_flags); 144 145 return (0); 146} 147 148static void 149__mutex_print_summary(env) 150 ENV *env; 151{ 152 DB_MUTEX *mutexp; 153 DB_MUTEXMGR *mtxmgr; 154 DB_MUTEXREGION *mtxregion; 155 db_mutex_t i; 156 u_int32_t counts[MTX_MAX_ENTRY + 2]; 157 int alloc_id; 158 159 mtxmgr = env->mutex_handle; 160 mtxregion = mtxmgr->reginfo.primary; 161 memset(counts, 0, sizeof(counts)); 162 163 for (i = 1; i <= mtxregion->stat.st_mutex_cnt; ++i, ++mutexp) { 164 mutexp = MUTEXP_SET(i); 165 166 if (!F_ISSET(mutexp, DB_MUTEX_ALLOCATED)) 167 counts[0]++; 168 else if (mutexp->alloc_id > MTX_MAX_ENTRY) 169 counts[MTX_MAX_ENTRY + 1]++; 170 else 171 counts[mutexp->alloc_id]++; 172 } 173 __db_msg(env, "Mutex counts"); 174 __db_msg(env, "%d\tUnallocated", counts[0]); 175 for (alloc_id = 1; alloc_id <= MTX_TXN_REGION + 1; alloc_id++) 176 if (counts[alloc_id] != 0) 177 __db_msg(env, "%lu\t%s", 178 (u_long)counts[alloc_id], 179 __mutex_print_id(alloc_id)); 180 181} 182 183/* 184 * __mutex_print_stats -- 185 * Display default mutex region statistics. 186 */ 187static int 188__mutex_print_stats(env, flags) 189 ENV *env; 190 u_int32_t flags; 191{ 192 DB_MUTEX_STAT *sp; 193 int ret; 194 195 if ((ret = __mutex_stat(env, &sp, LF_ISSET(DB_STAT_CLEAR))) != 0) 196 return (ret); 197 198 if (LF_ISSET(DB_STAT_ALL)) 199 __db_msg(env, "Default mutex region information:"); 200 201 __db_dlbytes(env, "Mutex region size", 202 (u_long)0, (u_long)0, (u_long)sp->st_regsize); 203 __db_dl_pct(env, 204 "The number of region locks that required waiting", 205 (u_long)sp->st_region_wait, DB_PCT(sp->st_region_wait, 206 sp->st_region_wait + sp->st_region_nowait), NULL); 207 STAT_ULONG("Mutex alignment", sp->st_mutex_align); 208 STAT_ULONG("Mutex test-and-set spins", sp->st_mutex_tas_spins); 209 STAT_ULONG("Mutex total count", sp->st_mutex_cnt); 210 STAT_ULONG("Mutex free count", sp->st_mutex_free); 211 STAT_ULONG("Mutex in-use count", sp->st_mutex_inuse); 212 STAT_ULONG("Mutex maximum in-use count", sp->st_mutex_inuse_max); 213 214 __os_ufree(env, sp); 215 216 return (0); 217} 218 219/* 220 * __mutex_print_all -- 221 * Display debugging mutex region statistics. 222 */ 223static int 224__mutex_print_all(env, flags) 225 ENV *env; 226 u_int32_t flags; 227{ 228 static const FN fn[] = { 229 { DB_MUTEX_ALLOCATED, "alloc" }, 230 { DB_MUTEX_LOCKED, "locked" }, 231 { DB_MUTEX_LOGICAL_LOCK, "logical" }, 232 { DB_MUTEX_PROCESS_ONLY, "process-private" }, 233 { DB_MUTEX_SELF_BLOCK, "self-block" }, 234 { 0, NULL } 235 }; 236 DB_MSGBUF mb, *mbp; 237 DB_MUTEX *mutexp; 238 DB_MUTEXMGR *mtxmgr; 239 DB_MUTEXREGION *mtxregion; 240 db_mutex_t i; 241 242 DB_MSGBUF_INIT(&mb); 243 mbp = &mb; 244 245 mtxmgr = env->mutex_handle; 246 mtxregion = mtxmgr->reginfo.primary; 247 248 __db_print_reginfo(env, &mtxmgr->reginfo, "Mutex", flags); 249 __db_msg(env, "%s", DB_GLOBAL(db_line)); 250 251 __db_msg(env, "DB_MUTEXREGION structure:"); 252 __mutex_print_debug_single(env, 253 "DB_MUTEXREGION region mutex", mtxregion->mtx_region, flags); 254 STAT_ULONG("Size of the aligned mutex", mtxregion->mutex_size); 255 STAT_ULONG("Next free mutex", mtxregion->mutex_next); 256 257 /* 258 * The OOB mutex (MUTEX_INVALID) is 0, skip it. 259 * 260 * We're not holding the mutex region lock, so we're racing threads of 261 * control allocating mutexes. That's OK, it just means we display or 262 * clear statistics while mutexes are moving. 263 */ 264 __db_msg(env, "%s", DB_GLOBAL(db_line)); 265 __db_msg(env, "mutex\twait/nowait, pct wait, holder, flags"); 266 for (i = 1; i <= mtxregion->stat.st_mutex_cnt; ++i, ++mutexp) { 267 mutexp = MUTEXP_SET(i); 268 269 if (!F_ISSET(mutexp, DB_MUTEX_ALLOCATED)) 270 continue; 271 272 __db_msgadd(env, mbp, "%5lu\t", (u_long)i); 273 274 __mutex_print_debug_stats(env, mbp, i, flags); 275 276 if (mutexp->alloc_id != 0) 277 __db_msgadd(env, 278 mbp, ", %s", __mutex_print_id(mutexp->alloc_id)); 279 280 __db_prflags(env, mbp, mutexp->flags, fn, " (", ")"); 281 282 DB_MSGBUF_FLUSH(env, mbp); 283 } 284 285 return (0); 286} 287 288/* 289 * __mutex_print_debug_single -- 290 * Print mutex internal debugging statistics for a single mutex on a 291 * single output line. 292 * 293 * PUBLIC: void __mutex_print_debug_single 294 * PUBLIC: __P((ENV *, const char *, db_mutex_t, u_int32_t)); 295 */ 296void 297__mutex_print_debug_single(env, tag, mutex, flags) 298 ENV *env; 299 const char *tag; 300 db_mutex_t mutex; 301 u_int32_t flags; 302{ 303 DB_MSGBUF mb, *mbp; 304 305 DB_MSGBUF_INIT(&mb); 306 mbp = &mb; 307 308 if (LF_ISSET(DB_STAT_SUBSYSTEM)) 309 LF_CLR(DB_STAT_CLEAR); 310 __db_msgadd(env, mbp, "%lu\t%s ", (u_long)mutex, tag); 311 __mutex_print_debug_stats(env, mbp, mutex, flags); 312 DB_MSGBUF_FLUSH(env, mbp); 313} 314 315/* 316 * __mutex_print_debug_stats -- 317 * Print mutex internal debugging statistics, that is, the statistics 318 * in the [] square brackets. 319 * 320 * PUBLIC: void __mutex_print_debug_stats 321 * PUBLIC: __P((ENV *, DB_MSGBUF *, db_mutex_t, u_int32_t)); 322 */ 323void 324__mutex_print_debug_stats(env, mbp, mutex, flags) 325 ENV *env; 326 DB_MSGBUF *mbp; 327 db_mutex_t mutex; 328 u_int32_t flags; 329{ 330 DB_ENV *dbenv; 331 DB_MUTEX *mutexp; 332 DB_MUTEXMGR *mtxmgr; 333 DB_MUTEXREGION *mtxregion; 334 u_long value; 335 char buf[DB_THREADID_STRLEN]; 336 337 if (mutex == MUTEX_INVALID) { 338 __db_msgadd(env, mbp, "[!Set]"); 339 return; 340 } 341 342 dbenv = env->dbenv; 343 mtxmgr = env->mutex_handle; 344 mtxregion = mtxmgr->reginfo.primary; 345 mutexp = MUTEXP_SET(mutex); 346 347 __db_msgadd(env, mbp, "["); 348 if ((value = mutexp->mutex_set_wait) < 10000000) 349 __db_msgadd(env, mbp, "%lu", value); 350 else 351 __db_msgadd(env, mbp, "%luM", value / 1000000); 352 if ((value = mutexp->mutex_set_nowait) < 10000000) 353 __db_msgadd(env, mbp, "/%lu", value); 354 else 355 __db_msgadd(env, mbp, "/%luM", value / 1000000); 356 357 __db_msgadd(env, mbp, " %d%%", 358 DB_PCT(mutexp->mutex_set_wait, 359 mutexp->mutex_set_wait + mutexp->mutex_set_nowait)); 360 361 if (F_ISSET(mutexp, DB_MUTEX_LOCKED)) 362 __db_msgadd(env, mbp, " %s]", 363 dbenv->thread_id_string(dbenv, 364 mutexp->pid, mutexp->tid, buf)); 365 else 366 __db_msgadd(env, mbp, " !Own]"); 367 368 if (LF_ISSET(DB_STAT_CLEAR)) 369 __mutex_clear(env, mutex); 370} 371 372static const char * 373__mutex_print_id(alloc_id) 374 int alloc_id; 375{ 376 switch (alloc_id) { 377 case MTX_APPLICATION: return ("application allocated"); 378 case MTX_DB_HANDLE: return ("db handle"); 379 case MTX_ENV_DBLIST: return ("env dblist"); 380 case MTX_ENV_HANDLE: return ("env handle"); 381 case MTX_ENV_REGION: return ("env region"); 382 case MTX_LOCK_REGION: return ("lock region"); 383 case MTX_LOGICAL_LOCK: return ("logical lock"); 384 case MTX_LOG_FILENAME: return ("log filename"); 385 case MTX_LOG_FLUSH: return ("log flush"); 386 case MTX_LOG_HANDLE: return ("log handle"); 387 case MTX_LOG_REGION: return ("log region"); 388 case MTX_MPOOLFILE_HANDLE: return ("mpoolfile handle"); 389 case MTX_MPOOL_FH: return ("mpool filehandle"); 390 case MTX_MPOOL_FILE_BUCKET: return ("mpool file bucket"); 391 case MTX_MPOOL_HANDLE: return ("mpool handle"); 392 case MTX_MPOOL_HASH_BUCKET: return ("mpool hash bucket"); 393 case MTX_MPOOL_IO: return ("mpool buffer I/O"); 394 case MTX_MPOOL_REGION: return ("mpool region"); 395 case MTX_MUTEX_REGION: return ("mutex region"); 396 case MTX_MUTEX_TEST: return ("mutex test"); 397 case MTX_REP_CHKPT: return ("replication checkpoint"); 398 case MTX_REP_DATABASE: return ("replication database"); 399 case MTX_REP_EVENT: return ("replication event"); 400 case MTX_REP_REGION: return ("replication region"); 401 case MTX_SEQUENCE: return ("sequence"); 402 case MTX_TWISTER: return ("twister"); 403 case MTX_TXN_ACTIVE: return ("txn active list"); 404 case MTX_TXN_CHKPT: return ("transaction checkpoint"); 405 case MTX_TXN_COMMIT: return ("txn commit"); 406 case MTX_TXN_MVCC: return ("txn mvcc"); 407 case MTX_TXN_REGION: return ("txn region"); 408 default: return ("unknown mutex type"); 409 /* NOTREACHED */ 410 } 411} 412 413/* 414 * __mutex_set_wait_info -- 415 * Return mutex statistics. 416 * 417 * PUBLIC: void __mutex_set_wait_info 418 * PUBLIC: __P((ENV *, db_mutex_t, u_int32_t *, u_int32_t *)); 419 */ 420void 421__mutex_set_wait_info(env, mutex, waitp, nowaitp) 422 ENV *env; 423 db_mutex_t mutex; 424 u_int32_t *waitp, *nowaitp; 425{ 426 DB_MUTEX *mutexp; 427 DB_MUTEXMGR *mtxmgr; 428 DB_MUTEXREGION *mtxregion; 429 430 mtxmgr = env->mutex_handle; 431 mtxregion = mtxmgr->reginfo.primary; 432 mutexp = MUTEXP_SET(mutex); 433 434 *waitp = mutexp->mutex_set_wait; 435 *nowaitp = mutexp->mutex_set_nowait; 436} 437 438/* 439 * __mutex_clear -- 440 * Clear mutex statistics. 441 * 442 * PUBLIC: void __mutex_clear __P((ENV *, db_mutex_t)); 443 */ 444void 445__mutex_clear(env, mutex) 446 ENV *env; 447 db_mutex_t mutex; 448{ 449 DB_MUTEX *mutexp; 450 DB_MUTEXMGR *mtxmgr; 451 DB_MUTEXREGION *mtxregion; 452 453 mtxmgr = env->mutex_handle; 454 mtxregion = mtxmgr->reginfo.primary; 455 mutexp = MUTEXP_SET(mutex); 456 457 mutexp->mutex_set_wait = mutexp->mutex_set_nowait = 0; 458} 459 460#else /* !HAVE_STATISTICS */ 461 462int 463__mutex_stat_pp(dbenv, statp, flags) 464 DB_ENV *dbenv; 465 DB_MUTEX_STAT **statp; 466 u_int32_t flags; 467{ 468 COMPQUIET(statp, NULL); 469 COMPQUIET(flags, 0); 470 471 return (__db_stat_not_built(dbenv->env)); 472} 473 474int 475__mutex_stat_print_pp(dbenv, flags) 476 DB_ENV *dbenv; 477 u_int32_t flags; 478{ 479 COMPQUIET(flags, 0); 480 481 return (__db_stat_not_built(dbenv->env)); 482} 483#endif 484