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