static void h_free_hd(HDATA* hd) { if(hd->refs > 0) hd->refs--; // still references open or caching requests it stays - do not release. if(hd->refs > 0 || hd->keep_open) return; // actually release the resource (call dtor, free control block). // h_alloc makes sure type != 0; if we get here, it still is H_VTbl* vtbl = hd->type; // call its destructor // note: H_TYPE_DEFINE currently always defines a dtor, but play it safe if(vtbl->dtor) vtbl->dtor(hd->user); if(hd->key && !hd->unique) key_remove(hd->key, hd->type); #ifndef NDEBUG // to_string is slow for some handles, so avoid calling it if unnecessary if(debug_filter_allows(L"H_MGR|")) { wchar_t buf[H_STRING_LEN]; if(vtbl->to_string(hd->user, buf) < 0) wcscpy_s(buf, ARRAY_SIZE(buf), L"(error)"); debug_printf(L"H_MGR| free %ls %ls accesses=%lu %ls\n", hd->type->name, hd->pathname.string().c_str(), (unsigned long)hd->num_derefs, buf); } #endif hd->pathname.~VfsPath(); // FIXME: ugly hack, but necessary to reclaim memory memset(hd, 0, sizeof(*hd)); pool_free(&hpool, hd); }
void file_stats_dump() { if(!debug_filter_allows(L"FILE_STATS|")) return; const double KB = 1e3; const double MB = 1e6; const double ms = 1e-3; debug_printf(L"--------------------------------------------------------------------------------\n"); debug_printf(L"File statistics:\n"); // note: we split the reports into several debug_printfs for clarity; // this is necessary anyway due to fixed-size buffer. debug_printf( L"\nvfs:\n" L"Total files: %lu (%g MB)\n" L"Init/mount time: %g ms\n", (unsigned long)vfs_files, vfs_size_total/MB, vfs_init_elapsed_time/ms ); debug_printf( L"\nfile:\n" L"Total names: %lu (%lu KB)\n" L"Max. concurrent: %lu; leaked: %lu.\n", (unsigned long)unique_names, (unsigned long)(unique_name_len_total/1000), (unsigned long)open_files_max, (unsigned long)open_files_cur ); debug_printf( L"\nfile_buf:\n" L"Total buffers used: %lu (%g MB)\n" L"Max concurrent: %lu; leaked: %lu\n" L"Internal fragmentation: %d%%\n", (unsigned long)extant_bufs_total, buf_size_total/MB, (unsigned long)extant_bufs_max, (unsigned long)extant_bufs_cur, percent(buf_aligned_size_total-buf_size_total, buf_size_total) ); debug_printf( L"\nfile_io:\n" L"Total user load requests: %lu (%g MB)\n" L"IO thoughput [MB/s; 0=never happened]:\n" L" lowio: R=%.3g, W=%.3g\n" L" aio: R=%.3g, W=%.3g\n" L"Average size = %g KB; seeks: %lu; total callback time: %g ms\n" L"Total data actually read from disk = %g MB\n", (unsigned long)user_ios, user_io_size_total/MB, #define THROUGHPUT(impl, opcode) (io_elapsed_time[impl][opcode == LIO_WRITE] == 0.0)? 0.0 : (io_actual_size_total[impl][opcode == LIO_WRITE] / io_elapsed_time[impl][opcode == LIO_WRITE] / MB) THROUGHPUT(FI_LOWIO, LIO_READ), THROUGHPUT(FI_LOWIO, LIO_WRITE), THROUGHPUT(FI_AIO , LIO_READ), THROUGHPUT(FI_AIO , LIO_WRITE), user_io_size_total/user_ios/KB, (unsigned long)io_seeks, io_process_time_total/ms, (io_actual_size_total[FI_LOWIO][0]+io_actual_size_total[FI_AIO][0])/MB ); debug_printf( L"\nfile_cache:\n" L"Hits: %lu (%g MB); misses %lu (%g MB); ratio: %u%%\n" L"Percent of requested bytes satisfied by cache: %u%%; non-compulsory misses: %lu (%u%% of misses)\n" L"Block hits: %lu; misses: %lu; ratio: %u%%\n", (unsigned long)cache_count[CR_HIT], cache_size_total[CR_HIT]/MB, (unsigned long)cache_count[CR_MISS], cache_size_total[CR_MISS]/MB, percent(cache_count[CR_HIT], cache_count[CR_HIT]+cache_count[CR_MISS]), percent(cache_size_total[CR_HIT], cache_size_total[CR_HIT]+cache_size_total[CR_MISS]), (unsigned long)conflict_misses, percent(conflict_misses, cache_count[CR_MISS]), (unsigned long)block_cache_count[CR_HIT], (unsigned long)block_cache_count[CR_MISS], percent(block_cache_count[CR_HIT], block_cache_count[CR_HIT]+block_cache_count[CR_MISS]) ); debug_printf( L"\nvfs_optimizer:\n" L"Total trace entries: %lu; repeated connections: %lu; unique files: %lu\n", (unsigned long)ab_connection_attempts, (unsigned long)ab_repeated_connections, (unsigned long)(ab_connection_attempts-ab_repeated_connections) ); }
void debug_puts_filtered(const char* text) { if(debug_filter_allows(text)) debug_puts(text); }