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