1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996,2008 Oracle. All rights reserved. 5 * 6 * $Id: mp_stat.c,v 12.43 2008/01/08 20:58:42 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/log.h" 15#include "dbinc/mp.h" 16#include "dbinc/txn.h" 17 18#ifdef HAVE_STATISTICS 19static void __memp_print_bh __P((ENV *, 20 DB_MPOOL *, const char *, BH *, roff_t *)); 21static int __memp_print_all __P((ENV *, u_int32_t)); 22static int __memp_print_stats __P((ENV *, u_int32_t)); 23static int __memp_print_hash __P((ENV *, 24 DB_MPOOL *, REGINFO *, roff_t *, u_int32_t)); 25static int __memp_stat __P((ENV *, 26 DB_MPOOL_STAT **, DB_MPOOL_FSTAT ***, u_int32_t)); 27static void __memp_stat_wait 28 __P((ENV *, REGINFO *, MPOOL *, DB_MPOOL_STAT *, u_int32_t)); 29static int __memp_file_stats __P((ENV *, 30 MPOOLFILE *, void *, u_int32_t *, u_int32_t)); 31static int __memp_count_files __P((ENV *, 32 MPOOLFILE *, void *, u_int32_t *, u_int32_t)); 33static int __memp_get_files __P((ENV *, 34 MPOOLFILE *, void *, u_int32_t *, u_int32_t)); 35static int __memp_print_files __P((ENV *, 36 MPOOLFILE *, void *, u_int32_t *, u_int32_t)); 37 38/* 39 * __memp_stat_pp -- 40 * DB_ENV->memp_stat pre/post processing. 41 * 42 * PUBLIC: int __memp_stat_pp 43 * PUBLIC: __P((DB_ENV *, DB_MPOOL_STAT **, DB_MPOOL_FSTAT ***, u_int32_t)); 44 */ 45int 46__memp_stat_pp(dbenv, gspp, fspp, flags) 47 DB_ENV *dbenv; 48 DB_MPOOL_STAT **gspp; 49 DB_MPOOL_FSTAT ***fspp; 50 u_int32_t flags; 51{ 52 DB_THREAD_INFO *ip; 53 ENV *env; 54 int ret; 55 56 env = dbenv->env; 57 58 ENV_REQUIRES_CONFIG(env, 59 env->mp_handle, "DB_ENV->memp_stat", DB_INIT_MPOOL); 60 61 if ((ret = __db_fchk(env, 62 "DB_ENV->memp_stat", flags, DB_STAT_CLEAR)) != 0) 63 return (ret); 64 65 ENV_ENTER(env, ip); 66 REPLICATION_WRAP(env, (__memp_stat(env, gspp, fspp, flags)), 0, ret); 67 ENV_LEAVE(env, ip); 68 return (ret); 69} 70 71/* 72 * __memp_stat -- 73 * ENV->memp_stat 74 */ 75static int 76__memp_stat(env, gspp, fspp, flags) 77 ENV *env; 78 DB_MPOOL_STAT **gspp; 79 DB_MPOOL_FSTAT ***fspp; 80 u_int32_t flags; 81{ 82 DB_MPOOL *dbmp; 83 DB_MPOOL_FSTAT **tfsp; 84 DB_MPOOL_STAT *sp; 85 MPOOL *c_mp, *mp; 86 size_t len; 87 u_int32_t i, st_bytes, st_gbytes, st_hash_buckets, st_pages; 88 u_int32_t tmp_wait, tmp_nowait; 89 int ret; 90 91 dbmp = env->mp_handle; 92 mp = dbmp->reginfo[0].primary; 93 94 /* Global statistics. */ 95 if (gspp != NULL) { 96 *gspp = NULL; 97 98 if ((ret = __os_umalloc(env, sizeof(**gspp), gspp)) != 0) 99 return (ret); 100 memset(*gspp, 0, sizeof(**gspp)); 101 sp = *gspp; 102 103 /* 104 * Initialization and information that is not maintained on 105 * a per-cache basis. Note that configuration information 106 * may be modified at any time, and so we have to lock. 107 */ 108 sp->st_gbytes = mp->stat.st_gbytes; 109 sp->st_bytes = mp->stat.st_bytes; 110 sp->st_ncache = mp->nreg; 111 sp->st_max_ncache = mp->max_nreg; 112 sp->st_regsize = dbmp->reginfo[0].rp->size; 113 114 MPOOL_SYSTEM_LOCK(env); 115 sp->st_mmapsize = mp->mp_mmapsize; 116 sp->st_maxopenfd = mp->mp_maxopenfd; 117 sp->st_maxwrite = mp->mp_maxwrite; 118 sp->st_maxwrite_sleep = mp->mp_maxwrite_sleep; 119 MPOOL_SYSTEM_UNLOCK(env); 120 121 /* Walk the cache list and accumulate the global information. */ 122 for (i = 0; i < mp->nreg; ++i) { 123 c_mp = dbmp->reginfo[i].primary; 124 125 sp->st_map += c_mp->stat.st_map; 126 sp->st_cache_hit += c_mp->stat.st_cache_hit; 127 sp->st_cache_miss += c_mp->stat.st_cache_miss; 128 sp->st_page_create += c_mp->stat.st_page_create; 129 sp->st_page_in += c_mp->stat.st_page_in; 130 sp->st_page_out += c_mp->stat.st_page_out; 131 sp->st_ro_evict += c_mp->stat.st_ro_evict; 132 sp->st_rw_evict += c_mp->stat.st_rw_evict; 133 sp->st_page_trickle += c_mp->stat.st_page_trickle; 134 sp->st_pages += c_mp->stat.st_pages; 135 /* 136 * st_page_dirty calculated by __memp_stat_hash 137 * st_page_clean calculated here 138 */ 139 __memp_stat_hash( 140 &dbmp->reginfo[i], c_mp, &sp->st_page_dirty); 141 sp->st_page_clean = sp->st_pages - sp->st_page_dirty; 142 sp->st_hash_buckets += c_mp->stat.st_hash_buckets; 143 sp->st_hash_searches += c_mp->stat.st_hash_searches; 144 sp->st_hash_longest += c_mp->stat.st_hash_longest; 145 sp->st_hash_examined += c_mp->stat.st_hash_examined; 146 /* 147 * st_hash_nowait calculated by __memp_stat_wait 148 * st_hash_wait 149 */ 150 __memp_stat_wait( 151 env, &dbmp->reginfo[i], c_mp, sp, flags); 152 __mutex_set_wait_info(env, 153 c_mp->mtx_region, &tmp_wait, &tmp_nowait); 154 sp->st_region_nowait += tmp_nowait; 155 sp->st_region_wait += tmp_wait; 156 sp->st_alloc += c_mp->stat.st_alloc; 157 sp->st_alloc_buckets += c_mp->stat.st_alloc_buckets; 158 if (sp->st_alloc_max_buckets < 159 c_mp->stat.st_alloc_max_buckets) 160 sp->st_alloc_max_buckets = 161 c_mp->stat.st_alloc_max_buckets; 162 sp->st_alloc_pages += c_mp->stat.st_alloc_pages; 163 if (sp->st_alloc_max_pages < 164 c_mp->stat.st_alloc_max_pages) 165 sp->st_alloc_max_pages = 166 c_mp->stat.st_alloc_max_pages; 167 168 if (LF_ISSET(DB_STAT_CLEAR)) { 169 if (!LF_ISSET(DB_STAT_SUBSYSTEM)) 170 __mutex_clear(env, c_mp->mtx_region); 171 172 MPOOL_SYSTEM_LOCK(env); 173 st_bytes = c_mp->stat.st_bytes; 174 st_gbytes = c_mp->stat.st_gbytes; 175 st_hash_buckets = c_mp->stat.st_hash_buckets; 176 st_pages = c_mp->stat.st_pages; 177 memset(&c_mp->stat, 0, sizeof(c_mp->stat)); 178 c_mp->stat.st_bytes = st_bytes; 179 c_mp->stat.st_gbytes = st_gbytes; 180 c_mp->stat.st_hash_buckets = st_hash_buckets; 181 c_mp->stat.st_pages = st_pages; 182 MPOOL_SYSTEM_UNLOCK(env); 183 } 184 } 185 186 /* 187 * We have duplicate statistics fields in per-file structures 188 * and the cache. The counters are only incremented in the 189 * per-file structures, except if a file is flushed from the 190 * mpool, at which time we copy its information into the cache 191 * statistics. We added the cache information above, now we 192 * add the per-file information. 193 */ 194 if ((ret = __memp_walk_files(env, mp, __memp_file_stats, 195 sp, NULL, fspp == NULL ? LF_ISSET(DB_STAT_CLEAR) : 0)) != 0) 196 return (ret); 197 } 198 199 /* Per-file statistics. */ 200 if (fspp != NULL) { 201 *fspp = NULL; 202 203 /* Count the MPOOLFILE structures. */ 204 i = 0; 205 len = 0; 206 if ((ret = __memp_walk_files(env, 207 mp, __memp_count_files, &len, &i, flags)) != 0) 208 return (ret); 209 210 if (i == 0) 211 return (0); 212 len += sizeof(DB_MPOOL_FSTAT *); /* Trailing NULL */ 213 214 /* Allocate space */ 215 if ((ret = __os_umalloc(env, len, fspp)) != 0) 216 return (ret); 217 218 tfsp = *fspp; 219 *tfsp = NULL; 220 221 /* 222 * Files may have been opened since we counted, don't walk 223 * off the end of the allocated space. 224 */ 225 if ((ret = __memp_walk_files(env, 226 mp, __memp_get_files, &tfsp, &i, flags)) != 0) 227 return (ret); 228 229 *++tfsp = NULL; 230 } 231 232 return (0); 233} 234 235static int 236__memp_file_stats(env, mfp, argp, countp, flags) 237 ENV *env; 238 MPOOLFILE *mfp; 239 void *argp; 240 u_int32_t *countp; 241 u_int32_t flags; 242{ 243 DB_MPOOL_STAT *sp; 244 u_int32_t pagesize; 245 246 COMPQUIET(env, NULL); 247 COMPQUIET(countp, NULL); 248 249 sp = argp; 250 251 sp->st_map += mfp->stat.st_map; 252 sp->st_cache_hit += mfp->stat.st_cache_hit; 253 sp->st_cache_miss += mfp->stat.st_cache_miss; 254 sp->st_page_create += mfp->stat.st_page_create; 255 sp->st_page_in += mfp->stat.st_page_in; 256 sp->st_page_out += mfp->stat.st_page_out; 257 if (LF_ISSET(DB_STAT_CLEAR)) { 258 pagesize = mfp->stat.st_pagesize; 259 memset(&mfp->stat, 0, sizeof(mfp->stat)); 260 mfp->stat.st_pagesize = pagesize; 261 } 262 return (0); 263} 264 265static int 266__memp_count_files(env, mfp, argp, countp, flags) 267 ENV *env; 268 MPOOLFILE *mfp; 269 void *argp; 270 u_int32_t *countp; 271 u_int32_t flags; 272{ 273 DB_MPOOL *dbmp; 274 size_t len; 275 276 COMPQUIET(flags, 0); 277 dbmp = env->mp_handle; 278 len = *(size_t *)argp; 279 280 (*countp)++; 281 len += sizeof(DB_MPOOL_FSTAT *) + 282 sizeof(DB_MPOOL_FSTAT) + strlen(__memp_fns(dbmp, mfp)) + 1; 283 284 *(size_t *)argp = len; 285 return (0); 286} 287 288/* 289 * __memp_get_files -- 290 * get file specific statistics 291 * 292 * Build each individual entry. We assume that an array of pointers are 293 * aligned correctly to be followed by an array of structures, which should 294 * be safe (in this particular case, the first element of the structure 295 * is a pointer, so we're doubly safe). The array is followed by space 296 * for the text file names. 297 */ 298static int 299__memp_get_files(env, mfp, argp, countp, flags) 300 ENV *env; 301 MPOOLFILE *mfp; 302 void *argp; 303 u_int32_t *countp; 304 u_int32_t flags; 305{ 306 DB_MPOOL *dbmp; 307 DB_MPOOL_FSTAT **tfsp, *tstruct; 308 char *name, *tname; 309 size_t nlen; 310 u_int32_t pagesize; 311 312 if (*countp == 0) 313 return (0); 314 315 dbmp = env->mp_handle; 316 tfsp = *(DB_MPOOL_FSTAT ***)argp; 317 318 if (*tfsp == NULL) { 319 /* Add 1 to count because we need to skip over the NULL. */ 320 tstruct = (DB_MPOOL_FSTAT *)(tfsp + *countp + 1); 321 tname = (char *)(tstruct + *countp); 322 *tfsp = tstruct; 323 } else { 324 tstruct = *tfsp + 1; 325 tname = (*tfsp)->file_name + strlen((*tfsp)->file_name) + 1; 326 *++tfsp = tstruct; 327 } 328 329 name = __memp_fns(dbmp, mfp); 330 nlen = strlen(name) + 1; 331 memcpy(tname, name, nlen); 332 *tstruct = mfp->stat; 333 tstruct->file_name = tname; 334 335 *(DB_MPOOL_FSTAT ***)argp = tfsp; 336 (*countp)--; 337 338 if (LF_ISSET(DB_STAT_CLEAR)) { 339 pagesize = mfp->stat.st_pagesize; 340 memset(&mfp->stat, 0, sizeof(mfp->stat)); 341 mfp->stat.st_pagesize = pagesize; 342 } 343 return (0); 344} 345 346/* 347 * __memp_stat_print_pp -- 348 * ENV->memp_stat_print pre/post processing. 349 * 350 * PUBLIC: int __memp_stat_print_pp __P((DB_ENV *, u_int32_t)); 351 */ 352int 353__memp_stat_print_pp(dbenv, flags) 354 DB_ENV *dbenv; 355 u_int32_t flags; 356{ 357 DB_THREAD_INFO *ip; 358 ENV *env; 359 int ret; 360 361 env = dbenv->env; 362 363 ENV_REQUIRES_CONFIG(env, 364 env->mp_handle, "DB_ENV->memp_stat_print", DB_INIT_MPOOL); 365 366#define DB_STAT_MEMP_FLAGS \ 367 (DB_STAT_ALL | DB_STAT_CLEAR | DB_STAT_MEMP_HASH) 368 if ((ret = __db_fchk(env, 369 "DB_ENV->memp_stat_print", flags, DB_STAT_MEMP_FLAGS)) != 0) 370 return (ret); 371 372 ENV_ENTER(env, ip); 373 REPLICATION_WRAP(env, (__memp_stat_print(env, flags)), 0, ret); 374 ENV_LEAVE(env, ip); 375 return (ret); 376} 377 378#define FMAP_ENTRIES 200 /* Files we map. */ 379 380/* 381 * __memp_stat_print -- 382 * ENV->memp_stat_print method. 383 * 384 * PUBLIC: int __memp_stat_print __P((ENV *, u_int32_t)); 385 */ 386int 387__memp_stat_print(env, flags) 388 ENV *env; 389 u_int32_t flags; 390{ 391 u_int32_t orig_flags; 392 int ret; 393 394 orig_flags = flags; 395 LF_CLR(DB_STAT_CLEAR | DB_STAT_SUBSYSTEM); 396 if (flags == 0 || LF_ISSET(DB_STAT_ALL)) { 397 ret = __memp_print_stats(env, 398 LF_ISSET(DB_STAT_ALL) ? flags : orig_flags); 399 if (flags == 0 || ret != 0) 400 return (ret); 401 } 402 403 if (LF_ISSET(DB_STAT_ALL | DB_STAT_MEMP_HASH) && 404 (ret = __memp_print_all(env, orig_flags)) != 0) 405 return (ret); 406 407 return (0); 408} 409 410/* 411 * __memp_print_stats -- 412 * Display default mpool region statistics. 413 */ 414static int 415__memp_print_stats(env, flags) 416 ENV *env; 417 u_int32_t flags; 418{ 419 DB_MPOOL_FSTAT **fsp, **tfsp; 420 DB_MPOOL_STAT *gsp; 421 int ret; 422 423 if ((ret = __memp_stat(env, &gsp, &fsp, flags)) != 0) 424 return (ret); 425 426 if (LF_ISSET(DB_STAT_ALL)) 427 __db_msg(env, "Default cache region information:"); 428 __db_dlbytes(env, "Total cache size", 429 (u_long)gsp->st_gbytes, (u_long)0, (u_long)gsp->st_bytes); 430 __db_dl(env, "Number of caches", (u_long)gsp->st_ncache); 431 __db_dl(env, "Maximum number of caches", (u_long)gsp->st_max_ncache); 432 __db_dlbytes(env, "Pool individual cache size", 433 (u_long)0, (u_long)0, (u_long)gsp->st_regsize); 434 __db_dlbytes(env, "Maximum memory-mapped file size", 435 (u_long)0, (u_long)0, (u_long)gsp->st_mmapsize); 436 STAT_LONG("Maximum open file descriptors", gsp->st_maxopenfd); 437 STAT_LONG("Maximum sequential buffer writes", gsp->st_maxwrite); 438 STAT_LONG("Sleep after writing maximum sequential buffers", 439 gsp->st_maxwrite_sleep); 440 __db_dl(env, 441 "Requested pages mapped into the process' address space", 442 (u_long)gsp->st_map); 443 __db_dl_pct(env, "Requested pages found in the cache", 444 (u_long)gsp->st_cache_hit, DB_PCT( 445 gsp->st_cache_hit, gsp->st_cache_hit + gsp->st_cache_miss), NULL); 446 __db_dl(env, "Requested pages not found in the cache", 447 (u_long)gsp->st_cache_miss); 448 __db_dl(env, 449 "Pages created in the cache", (u_long)gsp->st_page_create); 450 __db_dl(env, "Pages read into the cache", (u_long)gsp->st_page_in); 451 __db_dl(env, "Pages written from the cache to the backing file", 452 (u_long)gsp->st_page_out); 453 __db_dl(env, "Clean pages forced from the cache", 454 (u_long)gsp->st_ro_evict); 455 __db_dl(env, "Dirty pages forced from the cache", 456 (u_long)gsp->st_rw_evict); 457 __db_dl(env, "Dirty pages written by trickle-sync thread", 458 (u_long)gsp->st_page_trickle); 459 __db_dl(env, "Current total page count", 460 (u_long)gsp->st_pages); 461 __db_dl(env, "Current clean page count", 462 (u_long)gsp->st_page_clean); 463 __db_dl(env, "Current dirty page count", 464 (u_long)gsp->st_page_dirty); 465 __db_dl(env, "Number of hash buckets used for page location", 466 (u_long)gsp->st_hash_buckets); 467 __db_dl(env, 468 "Total number of times hash chains searched for a page", 469 (u_long)gsp->st_hash_searches); 470 __db_dl(env, "The longest hash chain searched for a page", 471 (u_long)gsp->st_hash_longest); 472 __db_dl(env, 473 "Total number of hash chain entries checked for page", 474 (u_long)gsp->st_hash_examined); 475 __db_dl_pct(env, 476 "The number of hash bucket locks that required waiting", 477 (u_long)gsp->st_hash_wait, DB_PCT( 478 gsp->st_hash_wait, gsp->st_hash_wait + gsp->st_hash_nowait), NULL); 479 __db_dl_pct(env, 480 "The maximum number of times any hash bucket lock was waited for", 481 (u_long)gsp->st_hash_max_wait, DB_PCT(gsp->st_hash_max_wait, 482 gsp->st_hash_max_wait + gsp->st_hash_max_nowait), NULL); 483 __db_dl_pct(env, 484 "The number of region locks that required waiting", 485 (u_long)gsp->st_region_wait, DB_PCT(gsp->st_region_wait, 486 gsp->st_region_wait + gsp->st_region_nowait), NULL); 487 __db_dl(env, "The number of buffers frozen", 488 (u_long)gsp->st_mvcc_frozen); 489 __db_dl(env, "The number of buffers thawed", 490 (u_long)gsp->st_mvcc_thawed); 491 __db_dl(env, "The number of frozen buffers freed", 492 (u_long)gsp->st_mvcc_freed); 493 __db_dl(env, "The number of page allocations", (u_long)gsp->st_alloc); 494 __db_dl(env, 495 "The number of hash buckets examined during allocations", 496 (u_long)gsp->st_alloc_buckets); 497 __db_dl(env, 498 "The maximum number of hash buckets examined for an allocation", 499 (u_long)gsp->st_alloc_max_buckets); 500 __db_dl(env, "The number of pages examined during allocations", 501 (u_long)gsp->st_alloc_pages); 502 __db_dl(env, "The max number of pages examined for an allocation", 503 (u_long)gsp->st_alloc_max_pages); 504 __db_dl(env, "Threads waited on page I/O", (u_long)gsp->st_io_wait); 505 506 for (tfsp = fsp; fsp != NULL && *tfsp != NULL; ++tfsp) { 507 if (LF_ISSET(DB_STAT_ALL)) 508 __db_msg(env, "%s", DB_GLOBAL(db_line)); 509 __db_msg(env, "Pool File: %s", (*tfsp)->file_name); 510 __db_dl(env, "Page size", (u_long)(*tfsp)->st_pagesize); 511 __db_dl(env, 512 "Requested pages mapped into the process' address space", 513 (u_long)(*tfsp)->st_map); 514 __db_dl_pct(env, "Requested pages found in the cache", 515 (u_long)(*tfsp)->st_cache_hit, DB_PCT((*tfsp)->st_cache_hit, 516 (*tfsp)->st_cache_hit + (*tfsp)->st_cache_miss), NULL); 517 __db_dl(env, "Requested pages not found in the cache", 518 (u_long)(*tfsp)->st_cache_miss); 519 __db_dl(env, "Pages created in the cache", 520 (u_long)(*tfsp)->st_page_create); 521 __db_dl(env, "Pages read into the cache", 522 (u_long)(*tfsp)->st_page_in); 523 __db_dl(env, 524 "Pages written from the cache to the backing file", 525 (u_long)(*tfsp)->st_page_out); 526 } 527 528 __os_ufree(env, fsp); 529 __os_ufree(env, gsp); 530 return (0); 531} 532 533/* 534 * __memp_print_all -- 535 * Display debugging mpool region statistics. 536 */ 537static int 538__memp_print_all(env, flags) 539 ENV *env; 540 u_int32_t flags; 541{ 542 static const FN cfn[] = { 543 { DB_MPOOL_NOFILE, "DB_MPOOL_NOFILE" }, 544 { DB_MPOOL_UNLINK, "DB_MPOOL_UNLINK" }, 545 { 0, NULL } 546 }; 547 DB_MPOOL *dbmp; 548 DB_MPOOLFILE *dbmfp; 549 MPOOL *mp; 550 roff_t fmap[FMAP_ENTRIES + 1]; 551 u_int32_t i, cnt; 552 int ret; 553 554 dbmp = env->mp_handle; 555 mp = dbmp->reginfo[0].primary; 556 ret = 0; 557 558 MPOOL_SYSTEM_LOCK(env); 559 560 __db_print_reginfo(env, dbmp->reginfo, "Mpool", flags); 561 __db_msg(env, "%s", DB_GLOBAL(db_line)); 562 563 __db_msg(env, "MPOOL structure:"); 564 __mutex_print_debug_single( 565 env, "MPOOL region mutex", mp->mtx_region, flags); 566 STAT_LSN("Maximum checkpoint LSN", &mp->lsn); 567 STAT_ULONG("Hash table entries", mp->htab_buckets); 568 STAT_ULONG("Hash table last-checked", mp->last_checked); 569 STAT_ULONG("Hash table LRU count", mp->lru_count); 570 STAT_ULONG("Put counter", mp->put_counter); 571 572 __db_msg(env, "%s", DB_GLOBAL(db_line)); 573 __db_msg(env, "DB_MPOOL handle information:"); 574 __mutex_print_debug_single( 575 env, "DB_MPOOL handle mutex", dbmp->mutex, flags); 576 STAT_ULONG("Underlying cache regions", mp->nreg); 577 578 __db_msg(env, "%s", DB_GLOBAL(db_line)); 579 __db_msg(env, "DB_MPOOLFILE structures:"); 580 for (cnt = 0, dbmfp = TAILQ_FIRST(&dbmp->dbmfq); 581 dbmfp != NULL; dbmfp = TAILQ_NEXT(dbmfp, q), ++cnt) { 582 __db_msg(env, "File #%lu: %s: per-process, %s", 583 (u_long)cnt + 1, __memp_fn(dbmfp), 584 F_ISSET(dbmfp, MP_READONLY) ? "readonly" : "read/write"); 585 STAT_ULONG("Reference count", dbmfp->ref); 586 STAT_ULONG("Pinned block reference count", dbmfp->ref); 587 STAT_ULONG("Clear length", dbmfp->clear_len); 588 __db_print_fileid(env, dbmfp->fileid, "\tID"); 589 STAT_ULONG("File type", dbmfp->ftype); 590 STAT_ULONG("LSN offset", dbmfp->lsn_offset); 591 STAT_ULONG("Max gbytes", dbmfp->gbytes); 592 STAT_ULONG("Max bytes", dbmfp->bytes); 593 STAT_ULONG("Cache priority", dbmfp->priority); 594 STAT_POINTER("mmap address", dbmfp->addr); 595 STAT_ULONG("mmap length", dbmfp->len); 596 __db_prflags(env, NULL, dbmfp->flags, cfn, NULL, "\tFlags"); 597 __db_print_fh(env, "File handle", dbmfp->fhp, flags); 598 } 599 600 __db_msg(env, "%s", DB_GLOBAL(db_line)); 601 __db_msg(env, "MPOOLFILE structures:"); 602 cnt = 0; 603 if ((ret = __memp_walk_files(env, 604 mp, __memp_print_files, fmap, &cnt, flags)) != 0) 605 return (ret); 606 MPOOL_SYSTEM_UNLOCK(env); 607 608 if (cnt < FMAP_ENTRIES) 609 fmap[cnt] = INVALID_ROFF; 610 else 611 fmap[FMAP_ENTRIES] = INVALID_ROFF; 612 613 /* Dump the individual caches. */ 614 for (i = 0; i < mp->nreg; ++i) { 615 __db_msg(env, "%s", DB_GLOBAL(db_line)); 616 __db_msg(env, "Cache #%d:", i + 1); 617 if ((ret = __memp_print_hash( 618 env, dbmp, &dbmp->reginfo[i], fmap, flags)) != 0) 619 break; 620 } 621 622 return (ret); 623} 624 625static int 626__memp_print_files(env, mfp, argp, countp, flags) 627 ENV *env; 628 MPOOLFILE *mfp; 629 void *argp; 630 u_int32_t *countp; 631 u_int32_t flags; 632{ 633 roff_t *fmap; 634 DB_MPOOL *dbmp; 635 u_int32_t mfp_flags; 636 static const FN fn[] = { 637 { MP_CAN_MMAP, "MP_CAN_MMAP" }, 638 { MP_DIRECT, "MP_DIRECT" }, 639 { MP_EXTENT, "MP_EXTENT" }, 640 { MP_FAKE_DEADFILE, "deadfile" }, 641 { MP_FAKE_FILEWRITTEN, "file written" }, 642 { MP_FAKE_NB, "no backing file" }, 643 { MP_FAKE_UOC, "unlink on close" }, 644 { MP_NOT_DURABLE, "not durable" }, 645 { MP_TEMP, "MP_TEMP" }, 646 { 0, NULL } 647 }; 648 649 dbmp = env->mp_handle; 650 fmap = argp; 651 652 __db_msg(env, "File #%d: %s", *countp + 1, __memp_fns(dbmp, mfp)); 653 __mutex_print_debug_single(env, "Mutex", mfp->mutex, flags); 654 655 MUTEX_LOCK(env, mfp->mutex); 656 STAT_ULONG("Reference count", mfp->mpf_cnt); 657 STAT_ULONG("Block count", mfp->block_cnt); 658 STAT_ULONG("Last page number", mfp->last_pgno); 659 STAT_ULONG("Original last page number", mfp->orig_last_pgno); 660 STAT_ULONG("Maximum page number", mfp->maxpgno); 661 STAT_LONG("Type", mfp->ftype); 662 STAT_LONG("Priority", mfp->priority); 663 STAT_LONG("Page's LSN offset", mfp->lsn_off); 664 STAT_LONG("Page's clear length", mfp->clear_len); 665 666 __db_print_fileid(env, 667 R_ADDR(dbmp->reginfo, mfp->fileid_off), "\tID"); 668 669 mfp_flags = 0; 670 if (mfp->deadfile) 671 FLD_SET(mfp_flags, MP_FAKE_DEADFILE); 672 if (mfp->file_written) 673 FLD_SET(mfp_flags, MP_FAKE_FILEWRITTEN); 674 if (mfp->no_backing_file) 675 FLD_SET(mfp_flags, MP_FAKE_NB); 676 if (mfp->unlink_on_close) 677 FLD_SET(mfp_flags, MP_FAKE_UOC); 678 __db_prflags(env, NULL, mfp_flags, fn, NULL, "\tFlags"); 679 680 if (*countp < FMAP_ENTRIES) 681 fmap[*countp] = R_OFFSET(dbmp->reginfo, mfp); 682 (*countp)++; 683 MUTEX_UNLOCK(env, mfp->mutex); 684 return (0); 685} 686 687/* 688 * __memp_print_hash -- 689 * Display hash bucket statistics for a cache. 690 */ 691static int 692__memp_print_hash(env, dbmp, reginfo, fmap, flags) 693 ENV *env; 694 DB_MPOOL *dbmp; 695 REGINFO *reginfo; 696 roff_t *fmap; 697 u_int32_t flags; 698{ 699 BH *bhp, *vbhp; 700 DB_MPOOL_HASH *hp; 701 DB_MSGBUF mb; 702 MPOOL *c_mp; 703 u_int32_t bucket; 704 705 c_mp = reginfo->primary; 706 DB_MSGBUF_INIT(&mb); 707 708 /* Display the hash table list of BH's. */ 709 __db_msg(env, 710 "BH hash table (%lu hash slots)", (u_long)c_mp->htab_buckets); 711 __db_msg(env, "bucket #: priority, I/O wait, [mutex]"); 712 __db_msg(env, "\tpageno, file, ref, LSN, address, priority, flags"); 713 714 for (hp = R_ADDR(reginfo, c_mp->htab), 715 bucket = 0; bucket < c_mp->htab_buckets; ++hp, ++bucket) { 716 MUTEX_LOCK(env, hp->mtx_hash); 717 if ((bhp = SH_TAILQ_FIRST(&hp->hash_bucket, __bh)) != NULL) { 718 __db_msgadd(env, &mb, 719 "bucket %lu: %lu (%lu dirty)", 720 (u_long)bucket, (u_long)hp->hash_io_wait, 721 (u_long)hp->hash_page_dirty); 722 if (hp->hash_frozen != 0) 723 __db_msgadd(env, &mb, "(MVCC %lu/%lu/%lu) ", 724 (u_long)hp->hash_frozen, 725 (u_long)hp->hash_thawed, 726 (u_long)hp->hash_frozen_freed); 727 __mutex_print_debug_stats( 728 env, &mb, hp->mtx_hash, flags); 729 DB_MSGBUF_FLUSH(env, &mb); 730 } 731 for (; bhp != NULL; bhp = SH_TAILQ_NEXT(bhp, hq, __bh)) { 732 __memp_print_bh(env, dbmp, NULL, bhp, fmap); 733 734 /* Print the version chain, if it exists. */ 735 for (vbhp = SH_CHAIN_PREV(bhp, vc, __bh); 736 vbhp != NULL; 737 vbhp = SH_CHAIN_PREV(vbhp, vc, __bh)) { 738 __memp_print_bh(env, dbmp, 739 " next:\t", vbhp, fmap); 740 } 741 } 742 MUTEX_UNLOCK(env, hp->mtx_hash); 743 } 744 745 return (0); 746} 747 748/* 749 * __memp_print_bh -- 750 * Display a BH structure. 751 */ 752static void 753__memp_print_bh(env, dbmp, prefix, bhp, fmap) 754 ENV *env; 755 DB_MPOOL *dbmp; 756 const char *prefix; 757 BH *bhp; 758 roff_t *fmap; 759{ 760 static const FN fn[] = { 761 { BH_CALLPGIN, "callpgin" }, 762 { BH_DIRTY, "dirty" }, 763 { BH_DIRTY_CREATE, "created" }, 764 { BH_DISCARD, "discard" }, 765 { BH_FREED, "freed" }, 766 { BH_FROZEN, "frozen" }, 767 { BH_LOCKED, "locked" }, 768 { BH_TRASH, "trash" }, 769 { 0, NULL } 770 }; 771 DB_MSGBUF mb; 772 int i; 773 774 DB_MSGBUF_INIT(&mb); 775 776 if (prefix != NULL) 777 __db_msgadd(env, &mb, "%s", prefix); 778 else 779 __db_msgadd(env, &mb, "\t"); 780 781 for (i = 0; i < FMAP_ENTRIES; ++i) 782 if (fmap[i] == INVALID_ROFF || fmap[i] == bhp->mf_offset) 783 break; 784 785 if (fmap[i] == INVALID_ROFF) 786 __db_msgadd(env, &mb, "%5lu, %lu, ", 787 (u_long)bhp->pgno, (u_long)bhp->mf_offset); 788 else 789 __db_msgadd( 790 env, &mb, "%5lu, #%d, ", (u_long)bhp->pgno, i + 1); 791 792 __db_msgadd(env, &mb, "%2lu%s, %lu/%lu", (u_long)bhp->ref, 793 bhp->ref_sync == 0 ? "" : " (sync-lock)", 794 F_ISSET(bhp, BH_FROZEN) ? 0 : (u_long)LSN(bhp->buf).file, 795 F_ISSET(bhp, BH_FROZEN) ? 0 : (u_long)LSN(bhp->buf).offset); 796 if (bhp->td_off != INVALID_ROFF) 797 __db_msgadd(env, &mb, " (@%lu/%lu)", 798 (u_long)VISIBLE_LSN(env, bhp)->file, 799 (u_long)VISIBLE_LSN(env, bhp)->offset); 800 __db_msgadd(env, &mb, ", %#08lx, %lu", 801 (u_long)R_OFFSET(dbmp->reginfo, bhp), (u_long)bhp->priority); 802 __db_prflags(env, &mb, bhp->flags, fn, " (", ")"); 803 DB_MSGBUF_FLUSH(env, &mb); 804} 805 806/* 807 * __memp_stat_wait -- 808 * Total hash bucket wait stats into the region. 809 */ 810static void 811__memp_stat_wait(env, reginfo, mp, mstat, flags) 812 ENV *env; 813 REGINFO *reginfo; 814 MPOOL *mp; 815 DB_MPOOL_STAT *mstat; 816 u_int32_t flags; 817{ 818 DB_MPOOL_HASH *hp; 819 u_int32_t i, tmp_nowait, tmp_wait; 820 821 mstat->st_hash_max_wait = 0; 822 hp = R_ADDR(reginfo, mp->htab); 823 for (i = 0; i < mp->htab_buckets; i++, hp++) { 824 __mutex_set_wait_info( 825 env, hp->mtx_hash, &tmp_wait, &tmp_nowait); 826 mstat->st_hash_nowait += tmp_nowait; 827 mstat->st_hash_wait += tmp_wait; 828 if (tmp_wait > mstat->st_hash_max_wait) { 829 mstat->st_hash_max_wait = tmp_wait; 830 mstat->st_hash_max_nowait = tmp_nowait; 831 } 832 if (LF_ISSET(DB_STAT_CLEAR | 833 DB_STAT_SUBSYSTEM) == DB_STAT_CLEAR) 834 __mutex_clear(env, hp->mtx_hash); 835 836 mstat->st_io_wait += hp->hash_io_wait; 837 mstat->st_mvcc_frozen += hp->hash_frozen; 838 mstat->st_mvcc_thawed += hp->hash_thawed; 839 mstat->st_mvcc_freed += hp->hash_frozen_freed; 840 if (LF_ISSET(DB_STAT_CLEAR)) { 841 hp->hash_io_wait = 0; 842 hp->hash_frozen = 0; 843 hp->hash_thawed = 0; 844 hp->hash_frozen_freed = 0; 845 } 846 } 847} 848 849#else /* !HAVE_STATISTICS */ 850 851int 852__memp_stat_pp(dbenv, gspp, fspp, flags) 853 DB_ENV *dbenv; 854 DB_MPOOL_STAT **gspp; 855 DB_MPOOL_FSTAT ***fspp; 856 u_int32_t flags; 857{ 858 COMPQUIET(gspp, NULL); 859 COMPQUIET(fspp, NULL); 860 COMPQUIET(flags, 0); 861 862 return (__db_stat_not_built(dbenv->env)); 863} 864 865int 866__memp_stat_print_pp(dbenv, flags) 867 DB_ENV *dbenv; 868 u_int32_t flags; 869{ 870 COMPQUIET(flags, 0); 871 872 return (__db_stat_not_built(dbenv->env)); 873} 874#endif 875 876/* 877 * __memp_stat_hash -- 878 * Total hash bucket stats (other than mutex wait) into the region. 879 * 880 * PUBLIC: void __memp_stat_hash __P((REGINFO *, MPOOL *, u_int32_t *)); 881 */ 882void 883__memp_stat_hash(reginfo, mp, dirtyp) 884 REGINFO *reginfo; 885 MPOOL *mp; 886 u_int32_t *dirtyp; 887{ 888 DB_MPOOL_HASH *hp; 889 u_int32_t dirty, i; 890 891 hp = R_ADDR(reginfo, mp->htab); 892 for (i = 0, dirty = 0; i < mp->htab_buckets; i++, hp++) 893 dirty += hp->hash_page_dirty; 894 *dirtyp = dirty; 895} 896