1289177Speter/* stats-cmd.c -- implements the size stats sub-command. 2289177Speter * 3289177Speter * ==================================================================== 4289177Speter * Licensed to the Apache Software Foundation (ASF) under one 5289177Speter * or more contributor license agreements. See the NOTICE file 6289177Speter * distributed with this work for additional information 7289177Speter * regarding copyright ownership. The ASF licenses this file 8289177Speter * to you under the Apache License, Version 2.0 (the 9289177Speter * "License"); you may not use this file except in compliance 10289177Speter * with the License. You may obtain a copy of the License at 11289177Speter * 12289177Speter * http://www.apache.org/licenses/LICENSE-2.0 13289177Speter * 14289177Speter * Unless required by applicable law or agreed to in writing, 15289177Speter * software distributed under the License is distributed on an 16289177Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17289177Speter * KIND, either express or implied. See the License for the 18289177Speter * specific language governing permissions and limitations 19289177Speter * under the License. 20289177Speter * ==================================================================== 21289177Speter */ 22289177Speter 23289177Speter#include <assert.h> 24289177Speter 25289177Speter#include "svn_fs.h" 26289177Speter#include "svn_pools.h" 27289177Speter#include "svn_sorts.h" 28289177Speter 29289177Speter#include "private/svn_sorts_private.h" 30289177Speter#include "private/svn_string_private.h" 31289177Speter#include "private/svn_fs_fs_private.h" 32289177Speter 33289177Speter#include "svn_private_config.h" 34289177Speter#include "svnfsfs.h" 35289177Speter 36289177Speter/* Return the string, allocated in RESULT_POOL, describing the value 2**I. 37289177Speter */ 38289177Speterstatic const char * 39289177Speterprint_two_power(int i, 40289177Speter apr_pool_t *result_pool) 41289177Speter{ 42289177Speter /* These are the SI prefixes for base-1000, the binary ones with base-1024 43289177Speter are too clumsy and require appending B for "byte" to be intelligible, 44289177Speter e.g. "MiB". 45289177Speter 46289177Speter Therefore, we ignore the official standard and revert to the traditional 47289177Speter contextual use were the base-1000 prefixes are understood as base-1024 48289177Speter when it came to data sizes. 49289177Speter */ 50289177Speter const char *si_prefixes = " kMGTPEZY"; 51289177Speter 52289177Speter int number = (i >= 0) ? (1 << (i % 10)) : 0; 53289177Speter int thousands = (i >= 0) ? (i / 10) : 0; 54289177Speter 55289177Speter char si_prefix = (thousands < strlen(si_prefixes)) 56289177Speter ? si_prefixes[thousands] 57289177Speter : '?'; 58289177Speter 59289177Speter if (si_prefix == ' ') 60289177Speter return apr_psprintf(result_pool, "%d", number); 61289177Speter 62289177Speter return apr_psprintf(result_pool, "%d%c", number, si_prefix); 63289177Speter} 64289177Speter 65289177Speter/* Print statistics for the given group of representations to console. 66289177Speter * Use POOL for allocations. 67289177Speter */ 68289177Speterstatic void 69289177Speterprint_rep_stats(svn_fs_fs__representation_stats_t *stats, 70289177Speter apr_pool_t *pool) 71289177Speter{ 72289177Speter printf(_("%20s bytes in %12s reps\n" 73289177Speter "%20s bytes in %12s shared reps\n" 74289177Speter "%20s bytes expanded size\n" 75289177Speter "%20s bytes expanded shared size\n" 76289177Speter "%20s bytes with rep-sharing off\n" 77362181Sdim "%20s shared references\n" 78362181Sdim "%20.3f average delta chain length\n"), 79289177Speter svn__ui64toa_sep(stats->total.packed_size, ',', pool), 80289177Speter svn__ui64toa_sep(stats->total.count, ',', pool), 81289177Speter svn__ui64toa_sep(stats->shared.packed_size, ',', pool), 82289177Speter svn__ui64toa_sep(stats->shared.count, ',', pool), 83289177Speter svn__ui64toa_sep(stats->total.expanded_size, ',', pool), 84289177Speter svn__ui64toa_sep(stats->shared.expanded_size, ',', pool), 85289177Speter svn__ui64toa_sep(stats->expanded_size, ',', pool), 86362181Sdim svn__ui64toa_sep(stats->references - stats->total.count, ',', pool), 87362181Sdim stats->chain_len / MAX(1.0, (double)stats->total.count)); 88289177Speter} 89289177Speter 90289177Speter/* Print the (used) contents of CHANGES. Use POOL for allocations. 91289177Speter */ 92289177Speterstatic void 93289177Speterprint_largest_reps(svn_fs_fs__largest_changes_t *changes, 94289177Speter apr_pool_t *pool) 95289177Speter{ 96289177Speter apr_size_t i; 97289177Speter for (i = 0; i < changes->count && changes->changes[i]->size; ++i) 98289177Speter printf(_("%12s r%-8ld %s\n"), 99289177Speter svn__ui64toa_sep(changes->changes[i]->size, ',', pool), 100289177Speter changes->changes[i]->revision, 101289177Speter changes->changes[i]->path->data); 102289177Speter} 103289177Speter 104289177Speter/* Print the non-zero section of HISTOGRAM to console. 105289177Speter * Use POOL for allocations. 106289177Speter */ 107289177Speterstatic void 108289177Speterprint_histogram(svn_fs_fs__histogram_t *histogram, 109289177Speter apr_pool_t *pool) 110289177Speter{ 111289177Speter int first = 0; 112289177Speter int last = 63; 113289177Speter int i; 114289177Speter 115289177Speter /* identify non-zero range */ 116289177Speter while (last > 0 && histogram->lines[last].count == 0) 117289177Speter --last; 118289177Speter 119289177Speter while (first <= last && histogram->lines[first].count == 0) 120289177Speter ++first; 121289177Speter 122289177Speter /* display histogram lines */ 123289177Speter for (i = last; i >= first; --i) 124289177Speter printf(_(" %4s .. < %-4s %19s (%2d%%) bytes in %12s (%2d%%) items\n"), 125289177Speter print_two_power(i-1, pool), print_two_power(i, pool), 126289177Speter svn__ui64toa_sep(histogram->lines[i].sum, ',', pool), 127289177Speter (int)(histogram->lines[i].sum * 100 / histogram->total.sum), 128289177Speter svn__ui64toa_sep(histogram->lines[i].count, ',', pool), 129289177Speter (int)(histogram->lines[i].count * 100 / histogram->total.count)); 130289177Speter} 131289177Speter 132289177Speter/* COMPARISON_FUNC for svn_sort__hash. 133289177Speter * Sort extension_info_t values by total count in descending order. 134289177Speter */ 135289177Speterstatic int 136289177Spetercompare_count(const svn_sort__item_t *a, 137289177Speter const svn_sort__item_t *b) 138289177Speter{ 139289177Speter const svn_fs_fs__extension_info_t *lhs = a->value; 140289177Speter const svn_fs_fs__extension_info_t *rhs = b->value; 141289177Speter apr_int64_t diff = lhs->node_histogram.total.count 142289177Speter - rhs->node_histogram.total.count; 143289177Speter 144289177Speter return diff > 0 ? -1 : (diff < 0 ? 1 : 0); 145289177Speter} 146289177Speter 147289177Speter/* COMPARISON_FUNC for svn_sort__hash. 148289177Speter * Sort extension_info_t values by total uncompressed size in descending order. 149289177Speter */ 150289177Speterstatic int 151289177Spetercompare_node_size(const svn_sort__item_t *a, 152289177Speter const svn_sort__item_t *b) 153289177Speter{ 154289177Speter const svn_fs_fs__extension_info_t *lhs = a->value; 155289177Speter const svn_fs_fs__extension_info_t *rhs = b->value; 156289177Speter apr_int64_t diff = lhs->node_histogram.total.sum 157289177Speter - rhs->node_histogram.total.sum; 158289177Speter 159289177Speter return diff > 0 ? -1 : (diff < 0 ? 1 : 0); 160289177Speter} 161289177Speter 162289177Speter/* COMPARISON_FUNC for svn_sort__hash. 163289177Speter * Sort extension_info_t values by total prep count in descending order. 164289177Speter */ 165289177Speterstatic int 166289177Spetercompare_rep_size(const svn_sort__item_t *a, 167289177Speter const svn_sort__item_t *b) 168289177Speter{ 169289177Speter const svn_fs_fs__extension_info_t *lhs = a->value; 170289177Speter const svn_fs_fs__extension_info_t *rhs = b->value; 171289177Speter apr_int64_t diff = lhs->rep_histogram.total.sum 172289177Speter - rhs->rep_histogram.total.sum; 173289177Speter 174289177Speter return diff > 0 ? -1 : (diff < 0 ? 1 : 0); 175289177Speter} 176289177Speter 177289177Speter/* Return an array of extension_info_t* for the (up to) 16 most prominent 178289177Speter * extensions in STATS according to the sort criterion COMPARISON_FUNC. 179289177Speter * Allocate results in POOL. 180289177Speter */ 181289177Speterstatic apr_array_header_t * 182289177Speterget_by_extensions(svn_fs_fs__stats_t *stats, 183289177Speter int (*comparison_func)(const svn_sort__item_t *, 184289177Speter const svn_sort__item_t *), 185289177Speter apr_pool_t *pool) 186289177Speter{ 187289177Speter /* sort all data by extension */ 188289177Speter apr_array_header_t *sorted 189289177Speter = svn_sort__hash(stats->by_extension, comparison_func, pool); 190289177Speter 191289177Speter /* select the top (first) 16 entries */ 192289177Speter int count = MIN(sorted->nelts, 16); 193289177Speter apr_array_header_t *result 194289177Speter = apr_array_make(pool, count, sizeof(svn_fs_fs__extension_info_t*)); 195289177Speter int i; 196289177Speter 197289177Speter for (i = 0; i < count; ++i) 198289177Speter APR_ARRAY_PUSH(result, svn_fs_fs__extension_info_t*) 199289177Speter = APR_ARRAY_IDX(sorted, i, svn_sort__item_t).value; 200289177Speter 201289177Speter return result; 202289177Speter} 203289177Speter 204289177Speter/* Add all extension_info_t* entries of TO_ADD not already in TARGET to 205289177Speter * TARGET. 206289177Speter */ 207289177Speterstatic void 208289177Spetermerge_by_extension(apr_array_header_t *target, 209289177Speter apr_array_header_t *to_add) 210289177Speter{ 211289177Speter int i, k, count; 212289177Speter 213289177Speter count = target->nelts; 214289177Speter for (i = 0; i < to_add->nelts; ++i) 215289177Speter { 216289177Speter svn_fs_fs__extension_info_t *info 217289177Speter = APR_ARRAY_IDX(to_add, i, svn_fs_fs__extension_info_t *); 218289177Speter for (k = 0; k < count; ++k) 219289177Speter if (info == APR_ARRAY_IDX(target, k, svn_fs_fs__extension_info_t *)) 220289177Speter break; 221289177Speter 222289177Speter if (k == count) 223289177Speter APR_ARRAY_PUSH(target, svn_fs_fs__extension_info_t*) = info; 224289177Speter } 225289177Speter} 226289177Speter 227289177Speter/* Print the (up to) 16 extensions in STATS with the most changes. 228289177Speter * Use POOL for allocations. 229289177Speter */ 230289177Speterstatic void 231289177Speterprint_extensions_by_changes(svn_fs_fs__stats_t *stats, 232289177Speter apr_pool_t *pool) 233289177Speter{ 234289177Speter apr_array_header_t *data = get_by_extensions(stats, compare_count, pool); 235289177Speter apr_int64_t sum = 0; 236289177Speter int i; 237289177Speter 238289177Speter for (i = 0; i < data->nelts; ++i) 239289177Speter { 240289177Speter svn_fs_fs__extension_info_t *info 241289177Speter = APR_ARRAY_IDX(data, i, svn_fs_fs__extension_info_t *); 242289177Speter 243289177Speter /* If there are elements, then their count cannot be 0. */ 244289177Speter assert(stats->file_histogram.total.count); 245289177Speter 246289177Speter sum += info->node_histogram.total.count; 247289177Speter printf(_("%11s %20s (%2d%%) representations\n"), 248289177Speter info->extension, 249289177Speter svn__ui64toa_sep(info->node_histogram.total.count, ',', pool), 250289177Speter (int)(info->node_histogram.total.count * 100 / 251289177Speter stats->file_histogram.total.count)); 252289177Speter } 253289177Speter 254289177Speter if (stats->file_histogram.total.count) 255289177Speter { 256289177Speter printf(_("%11s %20s (%2d%%) representations\n"), 257289177Speter "(others)", 258289177Speter svn__ui64toa_sep(stats->file_histogram.total.count - sum, ',', 259289177Speter pool), 260289177Speter (int)((stats->file_histogram.total.count - sum) * 100 / 261289177Speter stats->file_histogram.total.count)); 262289177Speter } 263289177Speter} 264289177Speter 265289177Speter/* Calculate a percentage, handling edge cases. */ 266289177Speterstatic int 267289177Speterget_percentage(apr_uint64_t part, 268289177Speter apr_uint64_t total) 269289177Speter{ 270289177Speter /* This include total == 0. */ 271289177Speter if (part >= total) 272289177Speter return 100; 273289177Speter 274289177Speter /* Standard case. */ 275289177Speter return (int)(part * 100.0 / total); 276289177Speter} 277289177Speter 278289177Speter/* Print the (up to) 16 extensions in STATS with the largest total size of 279289177Speter * changed file content. Use POOL for allocations. 280289177Speter */ 281289177Speterstatic void 282289177Speterprint_extensions_by_nodes(svn_fs_fs__stats_t *stats, 283289177Speter apr_pool_t *pool) 284289177Speter{ 285289177Speter apr_array_header_t *data = get_by_extensions(stats, compare_node_size, pool); 286289177Speter apr_int64_t sum = 0; 287289177Speter int i; 288289177Speter 289289177Speter for (i = 0; i < data->nelts; ++i) 290289177Speter { 291289177Speter svn_fs_fs__extension_info_t *info 292289177Speter = APR_ARRAY_IDX(data, i, svn_fs_fs__extension_info_t *); 293289177Speter sum += info->node_histogram.total.sum; 294289177Speter printf(_("%11s %20s (%2d%%) bytes\n"), 295289177Speter info->extension, 296289177Speter svn__ui64toa_sep(info->node_histogram.total.sum, ',', pool), 297289177Speter get_percentage(info->node_histogram.total.sum, 298289177Speter stats->file_histogram.total.sum)); 299289177Speter } 300289177Speter 301289177Speter if (stats->file_histogram.total.sum > sum) 302289177Speter { 303289177Speter /* Total sum can't be zero here. */ 304289177Speter printf(_("%11s %20s (%2d%%) bytes\n"), 305289177Speter "(others)", 306289177Speter svn__ui64toa_sep(stats->file_histogram.total.sum - sum, ',', 307289177Speter pool), 308289177Speter get_percentage(stats->file_histogram.total.sum - sum, 309289177Speter stats->file_histogram.total.sum)); 310289177Speter } 311289177Speter} 312289177Speter 313289177Speter/* Print the (up to) 16 extensions in STATS with the largest total size of 314289177Speter * changed file content. Use POOL for allocations. 315289177Speter */ 316289177Speterstatic void 317289177Speterprint_extensions_by_reps(svn_fs_fs__stats_t *stats, 318289177Speter apr_pool_t *pool) 319289177Speter{ 320289177Speter apr_array_header_t *data = get_by_extensions(stats, compare_rep_size, pool); 321289177Speter apr_int64_t sum = 0; 322289177Speter int i; 323289177Speter 324289177Speter for (i = 0; i < data->nelts; ++i) 325289177Speter { 326289177Speter svn_fs_fs__extension_info_t *info 327289177Speter = APR_ARRAY_IDX(data, i, svn_fs_fs__extension_info_t *); 328289177Speter sum += info->rep_histogram.total.sum; 329289177Speter printf(_("%11s %20s (%2d%%) bytes\n"), 330289177Speter info->extension, 331289177Speter svn__ui64toa_sep(info->rep_histogram.total.sum, ',', pool), 332289177Speter get_percentage(info->rep_histogram.total.sum, 333289177Speter stats->rep_size_histogram.total.sum)); 334289177Speter } 335289177Speter 336289177Speter if (stats->rep_size_histogram.total.sum > sum) 337289177Speter { 338289177Speter /* Total sum can't be zero here. */ 339289177Speter printf(_("%11s %20s (%2d%%) bytes\n"), 340289177Speter "(others)", 341289177Speter svn__ui64toa_sep(stats->rep_size_histogram.total.sum - sum, ',', 342289177Speter pool), 343289177Speter get_percentage(stats->rep_size_histogram.total.sum - sum, 344289177Speter stats->rep_size_histogram.total.sum)); 345289177Speter } 346289177Speter} 347289177Speter 348289177Speter/* Print per-extension histograms for the most frequent extensions in STATS. 349289177Speter * Use POOL for allocations. */ 350289177Speterstatic void 351289177Speterprint_histograms_by_extension(svn_fs_fs__stats_t *stats, 352289177Speter apr_pool_t *pool) 353289177Speter{ 354289177Speter apr_array_header_t *data = get_by_extensions(stats, compare_count, pool); 355289177Speter int i; 356289177Speter 357289177Speter merge_by_extension(data, get_by_extensions(stats, compare_node_size, pool)); 358289177Speter merge_by_extension(data, get_by_extensions(stats, compare_rep_size, pool)); 359289177Speter 360289177Speter for (i = 0; i < data->nelts; ++i) 361289177Speter { 362289177Speter svn_fs_fs__extension_info_t *info 363289177Speter = APR_ARRAY_IDX(data, i, svn_fs_fs__extension_info_t *); 364289177Speter printf("\nHistogram of '%s' file sizes:\n", info->extension); 365289177Speter print_histogram(&info->node_histogram, pool); 366289177Speter printf("\nHistogram of '%s' file representation sizes:\n", 367289177Speter info->extension); 368289177Speter print_histogram(&info->rep_histogram, pool); 369289177Speter } 370289177Speter} 371289177Speter 372289177Speter/* Print the contents of STATS to the console. 373289177Speter * Use POOL for allocations. 374289177Speter */ 375289177Speterstatic void 376289177Speterprint_stats(svn_fs_fs__stats_t *stats, 377289177Speter apr_pool_t *pool) 378289177Speter{ 379289177Speter /* print results */ 380362181Sdim printf("\n\nGlobal statistics:\n"); 381289177Speter printf(_("%20s bytes in %12s revisions\n" 382289177Speter "%20s bytes in %12s changes\n" 383289177Speter "%20s bytes in %12s node revision records\n" 384289177Speter "%20s bytes in %12s representations\n" 385289177Speter "%20s bytes expanded representation size\n" 386289177Speter "%20s bytes with rep-sharing off\n"), 387289177Speter svn__ui64toa_sep(stats->total_size, ',', pool), 388289177Speter svn__ui64toa_sep(stats->revision_count, ',', pool), 389289177Speter svn__ui64toa_sep(stats->change_len, ',', pool), 390289177Speter svn__ui64toa_sep(stats->change_count, ',', pool), 391289177Speter svn__ui64toa_sep(stats->total_node_stats.size, ',', pool), 392289177Speter svn__ui64toa_sep(stats->total_node_stats.count, ',', pool), 393289177Speter svn__ui64toa_sep(stats->total_rep_stats.total.packed_size, ',', 394289177Speter pool), 395289177Speter svn__ui64toa_sep(stats->total_rep_stats.total.count, ',', pool), 396289177Speter svn__ui64toa_sep(stats->total_rep_stats.total.expanded_size, ',', 397289177Speter pool), 398289177Speter svn__ui64toa_sep(stats->total_rep_stats.expanded_size, ',', pool)); 399289177Speter 400289177Speter printf("\nNoderev statistics:\n"); 401289177Speter printf(_("%20s bytes in %12s nodes total\n" 402289177Speter "%20s bytes in %12s directory noderevs\n" 403289177Speter "%20s bytes in %12s file noderevs\n"), 404289177Speter svn__ui64toa_sep(stats->total_node_stats.size, ',', pool), 405289177Speter svn__ui64toa_sep(stats->total_node_stats.count, ',', pool), 406289177Speter svn__ui64toa_sep(stats->dir_node_stats.size, ',', pool), 407289177Speter svn__ui64toa_sep(stats->dir_node_stats.count, ',', pool), 408289177Speter svn__ui64toa_sep(stats->file_node_stats.size, ',', pool), 409289177Speter svn__ui64toa_sep(stats->file_node_stats.count, ',', pool)); 410289177Speter 411289177Speter printf("\nRepresentation statistics:\n"); 412289177Speter printf(_("%20s bytes in %12s representations total\n" 413289177Speter "%20s bytes in %12s directory representations\n" 414289177Speter "%20s bytes in %12s file representations\n" 415289177Speter "%20s bytes in %12s representations of added file nodes\n" 416289177Speter "%20s bytes in %12s directory property representations\n" 417289177Speter "%20s bytes in %12s file property representations\n" 418362181Sdim " with %12.3f average delta chain length\n" 419289177Speter "%20s bytes in header & footer overhead\n"), 420289177Speter svn__ui64toa_sep(stats->total_rep_stats.total.packed_size, ',', 421289177Speter pool), 422289177Speter svn__ui64toa_sep(stats->total_rep_stats.total.count, ',', pool), 423289177Speter svn__ui64toa_sep(stats->dir_rep_stats.total.packed_size, ',', 424289177Speter pool), 425289177Speter svn__ui64toa_sep(stats->dir_rep_stats.total.count, ',', pool), 426289177Speter svn__ui64toa_sep(stats->file_rep_stats.total.packed_size, ',', 427289177Speter pool), 428289177Speter svn__ui64toa_sep(stats->file_rep_stats.total.count, ',', pool), 429289177Speter svn__ui64toa_sep(stats->added_rep_size_histogram.total.sum, ',', 430289177Speter pool), 431289177Speter svn__ui64toa_sep(stats->added_rep_size_histogram.total.count, ',', 432289177Speter pool), 433289177Speter svn__ui64toa_sep(stats->dir_prop_rep_stats.total.packed_size, ',', 434289177Speter pool), 435289177Speter svn__ui64toa_sep(stats->dir_prop_rep_stats.total.count, ',', pool), 436289177Speter svn__ui64toa_sep(stats->file_prop_rep_stats.total.packed_size, ',', 437289177Speter pool), 438289177Speter svn__ui64toa_sep(stats->file_prop_rep_stats.total.count, ',', pool), 439362181Sdim stats->total_rep_stats.chain_len 440362181Sdim / (double)stats->total_rep_stats.total.count, 441289177Speter svn__ui64toa_sep(stats->total_rep_stats.total.overhead_size, ',', 442362181Sdim pool)); 443289177Speter 444289177Speter printf("\nDirectory representation statistics:\n"); 445289177Speter print_rep_stats(&stats->dir_rep_stats, pool); 446289177Speter printf("\nFile representation statistics:\n"); 447289177Speter print_rep_stats(&stats->file_rep_stats, pool); 448289177Speter printf("\nDirectory property representation statistics:\n"); 449289177Speter print_rep_stats(&stats->dir_prop_rep_stats, pool); 450289177Speter printf("\nFile property representation statistics:\n"); 451289177Speter print_rep_stats(&stats->file_prop_rep_stats, pool); 452289177Speter 453289177Speter printf("\nLargest representations:\n"); 454289177Speter print_largest_reps(stats->largest_changes, pool); 455289177Speter printf("\nExtensions by number of representations:\n"); 456289177Speter print_extensions_by_changes(stats, pool); 457289177Speter printf("\nExtensions by size of changed files:\n"); 458289177Speter print_extensions_by_nodes(stats, pool); 459289177Speter printf("\nExtensions by size of representations:\n"); 460289177Speter print_extensions_by_reps(stats, pool); 461289177Speter 462289177Speter printf("\nHistogram of expanded node sizes:\n"); 463289177Speter print_histogram(&stats->node_size_histogram, pool); 464289177Speter printf("\nHistogram of representation sizes:\n"); 465289177Speter print_histogram(&stats->rep_size_histogram, pool); 466289177Speter printf("\nHistogram of file sizes:\n"); 467289177Speter print_histogram(&stats->file_histogram, pool); 468289177Speter printf("\nHistogram of file representation sizes:\n"); 469289177Speter print_histogram(&stats->file_rep_histogram, pool); 470289177Speter printf("\nHistogram of file property sizes:\n"); 471289177Speter print_histogram(&stats->file_prop_histogram, pool); 472289177Speter printf("\nHistogram of file property representation sizes:\n"); 473289177Speter print_histogram(&stats->file_prop_rep_histogram, pool); 474289177Speter printf("\nHistogram of directory sizes:\n"); 475289177Speter print_histogram(&stats->dir_histogram, pool); 476289177Speter printf("\nHistogram of directory representation sizes:\n"); 477289177Speter print_histogram(&stats->dir_rep_histogram, pool); 478289177Speter printf("\nHistogram of directory property sizes:\n"); 479289177Speter print_histogram(&stats->dir_prop_histogram, pool); 480289177Speter printf("\nHistogram of directory property representation sizes:\n"); 481289177Speter print_histogram(&stats->dir_prop_rep_histogram, pool); 482289177Speter 483289177Speter print_histograms_by_extension(stats, pool); 484289177Speter} 485289177Speter 486289177Speter/* Our progress function simply prints the REVISION number and makes it 487289177Speter * appear immediately. 488289177Speter */ 489289177Speterstatic void 490289177Speterprint_progress(svn_revnum_t revision, 491289177Speter void *baton, 492289177Speter apr_pool_t *pool) 493289177Speter{ 494289177Speter printf("%8ld", revision); 495289177Speter fflush(stdout); 496289177Speter} 497289177Speter 498289177Speter/* This implements `svn_opt_subcommand_t'. */ 499289177Spetersvn_error_t * 500289177Spetersubcommand__stats(apr_getopt_t *os, void *baton, apr_pool_t *pool) 501289177Speter{ 502289177Speter svnfsfs__opt_state *opt_state = baton; 503289177Speter svn_fs_t *fs; 504362181Sdim svn_fs_fs__ioctl_get_stats_input_t input = {0}; 505362181Sdim svn_fs_fs__ioctl_get_stats_output_t *output; 506289177Speter 507289177Speter printf("Reading revisions\n"); 508289177Speter SVN_ERR(open_fs(&fs, opt_state->repository_path, pool)); 509289177Speter 510362181Sdim input.progress_func = print_progress; 511362181Sdim SVN_ERR(svn_fs_ioctl(fs, SVN_FS_FS__IOCTL_GET_STATS, &input, (void **)&output, 512362181Sdim check_cancel, NULL, pool, pool)); 513362181Sdim print_stats(output->stats, pool); 514289177Speter 515289177Speter return SVN_NO_ERROR; 516289177Speter} 517