22
33#include "builtin.h"
44#include "environment.h"
5+ #include "hex.h"
6+ #include "odb.h"
57#include "parse-options.h"
68#include "path-walk.h"
79#include "progress.h"
@@ -241,13 +243,19 @@ struct ref_stats {
241243 size_t others ;
242244};
243245
244- struct object_stats {
246+ struct object_values {
245247 size_t tags ;
246248 size_t commits ;
247249 size_t trees ;
248250 size_t blobs ;
249251};
250252
253+ struct object_stats {
254+ struct object_values type_counts ;
255+ struct object_values inflated_sizes ;
256+ struct object_values disk_sizes ;
257+ };
258+
251259struct repo_structure {
252260 struct ref_stats refs ;
253261 struct object_stats objects ;
@@ -258,13 +266,15 @@ struct stats_table {
258266
259267 int name_col_width ;
260268 int value_col_width ;
269+ int unit_col_width ;
261270};
262271
263272/*
264273 * Holds column data that gets stored for each row.
265274 */
266275struct stats_table_entry {
267276 char * value ;
277+ const char * unit ;
268278};
269279
270280static void stats_table_vaddf (struct stats_table * table ,
@@ -285,11 +295,18 @@ static void stats_table_vaddf(struct stats_table *table,
285295
286296 if (name_width > table -> name_col_width )
287297 table -> name_col_width = name_width ;
288- if (entry ) {
298+ if (!entry )
299+ return ;
300+ if (entry -> value ) {
289301 int value_width = utf8_strwidth (entry -> value );
290302 if (value_width > table -> value_col_width )
291303 table -> value_col_width = value_width ;
292304 }
305+ if (entry -> unit ) {
306+ int unit_width = utf8_strwidth (entry -> unit );
307+ if (unit_width > table -> unit_col_width )
308+ table -> unit_col_width = unit_width ;
309+ }
293310}
294311
295312static void stats_table_addf (struct stats_table * table , const char * format , ...)
@@ -301,14 +318,75 @@ static void stats_table_addf(struct stats_table *table, const char *format, ...)
301318 va_end (ap );
302319}
303320
321+ static const char * unit_k = "k" ;
322+ static const char * unit_M = "M" ;
323+ static const char * unit_G = "G" ;
324+
304325static void stats_table_count_addf (struct stats_table * table , size_t value ,
305326 const char * format , ...)
306327{
307328 struct stats_table_entry * entry ;
308329 va_list ap ;
309330
310331 CALLOC_ARRAY (entry , 1 );
311- entry -> value = xstrfmt ("%" PRIuMAX , (uintmax_t )value );
332+
333+ if (value >= 1000000000 ) {
334+ uintmax_t x = (uintmax_t )value + 5000000 ;
335+ entry -> value = xstrfmt ("%" PRIuMAX ".%02" PRIuMAX ,
336+ x / 1000000000 ,
337+ x % 1000000000 / 10000000 );
338+ entry -> unit = unit_G ;
339+ } else if (value >= 1000000 ) {
340+ uintmax_t x = (uintmax_t )value + 5000 ;
341+ entry -> value = xstrfmt ("%" PRIuMAX ".%02" PRIuMAX ,
342+ x / 1000000 , x % 1000000 / 10000 );
343+ entry -> unit = unit_M ;
344+ } else if (value >= 1000 ) {
345+ uintmax_t x = (uintmax_t )value + 5 ;
346+ entry -> value = xstrfmt ("%" PRIuMAX ".%02" PRIuMAX ,
347+ x / 1000 , x % 1000 / 10 );
348+ entry -> unit = unit_k ;
349+ } else {
350+ entry -> value = xstrfmt ("%" PRIuMAX , (uintmax_t )value );
351+ }
352+
353+ va_start (ap , format );
354+ stats_table_vaddf (table , entry , format , ap );
355+ va_end (ap );
356+ }
357+
358+ static const char * unit_B = "B" ;
359+ static const char * unit_KiB = "KiB" ;
360+ static const char * unit_MiB = "MiB" ;
361+ static const char * unit_GiB = "GiB" ;
362+
363+ static void stats_table_size_addf (struct stats_table * table , size_t value ,
364+ const char * format , ...)
365+ {
366+ struct stats_table_entry * entry ;
367+ va_list ap ;
368+
369+ CALLOC_ARRAY (entry , 1 );
370+
371+ if (value > 1 << 30 ) {
372+ uintmax_t x = (uintmax_t )value + 5368709 ;
373+ entry -> value = xstrfmt ("%" PRIuMAX ".%02" PRIuMAX , x >> 30 ,
374+ ((x & ((1 << 30 ) - 1 )) * 100 ) >> 30 );
375+ entry -> unit = unit_GiB ;
376+ } else if (value > 1 << 20 ) {
377+ uintmax_t x = (uintmax_t )value + 5243 ;
378+ entry -> value = xstrfmt ("%" PRIuMAX ".%02" PRIuMAX , x >> 20 ,
379+ ((x & ((1 << 20 ) - 1 )) * 100 ) >> 20 );
380+ entry -> unit = unit_MiB ;
381+ } else if (value > 1 << 10 ) {
382+ uintmax_t x = (uintmax_t )value + 5 ;
383+ entry -> value = xstrfmt ("%" PRIuMAX ".%02" PRIuMAX , x >> 10 ,
384+ ((x & ((1 << 10 ) - 1 )) * 100 ) >> 10 );
385+ entry -> unit = unit_KiB ;
386+ } else {
387+ entry -> value = xstrfmt ("%" PRIuMAX , (uintmax_t )value );
388+ entry -> unit = unit_B ;
389+ }
312390
313391 va_start (ap , format );
314392 stats_table_vaddf (table , entry , format , ap );
@@ -320,17 +398,19 @@ static inline size_t get_total_reference_count(struct ref_stats *stats)
320398 return stats -> branches + stats -> remotes + stats -> tags + stats -> others ;
321399}
322400
323- static inline size_t get_total_object_count (struct object_stats * stats )
401+ static inline size_t get_total_object_values (struct object_values * values )
324402{
325- return stats -> tags + stats -> commits + stats -> trees + stats -> blobs ;
403+ return values -> tags + values -> commits + values -> trees + values -> blobs ;
326404}
327405
328406static void stats_table_setup_structure (struct stats_table * table ,
329407 struct repo_structure * stats )
330408{
331409 struct object_stats * objects = & stats -> objects ;
332410 struct ref_stats * refs = & stats -> refs ;
333- size_t object_total ;
411+ size_t inflated_object_total ;
412+ size_t object_count_total ;
413+ size_t disk_object_total ;
334414 size_t ref_total ;
335415
336416 ref_total = get_total_reference_count (refs );
@@ -341,59 +421,96 @@ static void stats_table_setup_structure(struct stats_table *table,
341421 stats_table_count_addf (table , refs -> remotes , " * %s" , _ ("Remotes" ));
342422 stats_table_count_addf (table , refs -> others , " * %s" , _ ("Others" ));
343423
344- object_total = get_total_object_count ( objects );
424+ object_count_total = get_total_object_values ( & objects -> type_counts );
345425 stats_table_addf (table , "" );
346426 stats_table_addf (table , "* %s" , _ ("Reachable objects" ));
347- stats_table_count_addf (table , object_total , " * %s" , _ ("Count" ));
348- stats_table_count_addf (table , objects -> commits , " * %s" , _ ("Commits" ));
349- stats_table_count_addf (table , objects -> trees , " * %s" , _ ("Trees" ));
350- stats_table_count_addf (table , objects -> blobs , " * %s" , _ ("Blobs" ));
351- stats_table_count_addf (table , objects -> tags , " * %s" , _ ("Tags" ));
427+ stats_table_count_addf (table , object_count_total , " * %s" , _ ("Count" ));
428+ stats_table_count_addf (table , objects -> type_counts .commits ,
429+ " * %s" , _ ("Commits" ));
430+ stats_table_count_addf (table , objects -> type_counts .trees ,
431+ " * %s" , _ ("Trees" ));
432+ stats_table_count_addf (table , objects -> type_counts .blobs ,
433+ " * %s" , _ ("Blobs" ));
434+ stats_table_count_addf (table , objects -> type_counts .tags ,
435+ " * %s" , _ ("Tags" ));
436+
437+ inflated_object_total = get_total_object_values (& objects -> inflated_sizes );
438+ stats_table_size_addf (table , inflated_object_total ,
439+ " * %s" , _ ("Inflated size" ));
440+ stats_table_size_addf (table , objects -> inflated_sizes .commits ,
441+ " * %s" , _ ("Commits" ));
442+ stats_table_size_addf (table , objects -> inflated_sizes .trees ,
443+ " * %s" , _ ("Trees" ));
444+ stats_table_size_addf (table , objects -> inflated_sizes .blobs ,
445+ " * %s" , _ ("Blobs" ));
446+ stats_table_size_addf (table , objects -> inflated_sizes .tags ,
447+ " * %s" , _ ("Tags" ));
448+
449+ disk_object_total = get_total_object_values (& objects -> disk_sizes );
450+ stats_table_size_addf (table , disk_object_total ,
451+ " * %s" , _ ("Disk size" ));
452+ stats_table_size_addf (table , objects -> disk_sizes .commits ,
453+ " * %s" , _ ("Commits" ));
454+ stats_table_size_addf (table , objects -> disk_sizes .trees ,
455+ " * %s" , _ ("Trees" ));
456+ stats_table_size_addf (table , objects -> disk_sizes .blobs ,
457+ " * %s" , _ ("Blobs" ));
458+ stats_table_size_addf (table , objects -> disk_sizes .tags ,
459+ " * %s" , _ ("Tags" ));
352460}
353461
354462static void stats_table_print_structure (const struct stats_table * table )
355463{
356464 const char * name_col_title = _ ("Repository structure" );
357465 const char * value_col_title = _ ("Value" );
358- int name_col_width = utf8_strwidth (name_col_title );
359- int value_col_width = utf8_strwidth (value_col_title );
466+ int title_name_width = utf8_strwidth (name_col_title );
467+ int title_value_width = utf8_strwidth (value_col_title );
468+ int name_col_width = table -> name_col_width ;
469+ int value_col_width = table -> value_col_width ;
470+ int unit_col_width = table -> unit_col_width ;
360471 struct string_list_item * item ;
361472 struct strbuf buf = STRBUF_INIT ;
362473
363- if (table -> name_col_width > name_col_width )
364- name_col_width = table -> name_col_width ;
365- if (table -> value_col_width > value_col_width )
366- value_col_width = table -> value_col_width ;
474+ if (title_name_width > name_col_width )
475+ name_col_width = title_name_width ;
476+ if (title_value_width > value_col_width + unit_col_width + 1 )
477+ value_col_width = title_value_width - unit_col_width ;
367478
368479 strbuf_addstr (& buf , "| " );
369480 strbuf_utf8_align (& buf , ALIGN_LEFT , name_col_width , name_col_title );
370481 strbuf_addstr (& buf , " | " );
371- strbuf_utf8_align (& buf , ALIGN_LEFT , value_col_width , value_col_title );
482+ strbuf_utf8_align (& buf , ALIGN_LEFT ,
483+ value_col_width + unit_col_width + 1 , value_col_title );
372484 strbuf_addstr (& buf , " |" );
373485 printf ("%s\n" , buf .buf );
374486
375487 printf ("| " );
376488 for (int i = 0 ; i < name_col_width ; i ++ )
377489 putchar ('-' );
378490 printf (" | " );
379- for (int i = 0 ; i < value_col_width ; i ++ )
491+ for (int i = 0 ; i < value_col_width + unit_col_width + 1 ; i ++ )
380492 putchar ('-' );
381493 printf (" |\n" );
382494
383495 for_each_string_list_item (item , & table -> rows ) {
384496 struct stats_table_entry * entry = item -> util ;
385497 const char * value = "" ;
498+ const char * unit = "" ;
386499
387500 if (entry ) {
388501 struct stats_table_entry * entry = item -> util ;
389502 value = entry -> value ;
503+ if (entry -> unit )
504+ unit = entry -> unit ;
390505 }
391506
392507 strbuf_reset (& buf );
393508 strbuf_addstr (& buf , "| " );
394509 strbuf_utf8_align (& buf , ALIGN_LEFT , name_col_width , item -> string );
395510 strbuf_addstr (& buf , " | " );
396511 strbuf_utf8_align (& buf , ALIGN_RIGHT , value_col_width , value );
512+ strbuf_addch (& buf , ' ' );
513+ strbuf_utf8_align (& buf , ALIGN_LEFT , unit_col_width , unit );
397514 strbuf_addstr (& buf , " |" );
398515 printf ("%s\n" , buf .buf );
399516 }
@@ -428,13 +545,31 @@ static void structure_keyvalue_print(struct repo_structure *stats,
428545 (uintmax_t )stats -> refs .others , value_delim );
429546
430547 printf ("objects.commits.count%c%" PRIuMAX "%c" , key_delim ,
431- (uintmax_t )stats -> objects .commits , value_delim );
548+ (uintmax_t )stats -> objects .type_counts . commits , value_delim );
432549 printf ("objects.trees.count%c%" PRIuMAX "%c" , key_delim ,
433- (uintmax_t )stats -> objects .trees , value_delim );
550+ (uintmax_t )stats -> objects .type_counts . trees , value_delim );
434551 printf ("objects.blobs.count%c%" PRIuMAX "%c" , key_delim ,
435- (uintmax_t )stats -> objects .blobs , value_delim );
552+ (uintmax_t )stats -> objects .type_counts . blobs , value_delim );
436553 printf ("objects.tags.count%c%" PRIuMAX "%c" , key_delim ,
437- (uintmax_t )stats -> objects .tags , value_delim );
554+ (uintmax_t )stats -> objects .type_counts .tags , value_delim );
555+
556+ printf ("objects.commits.inflated%c%" PRIuMAX "%c" , key_delim ,
557+ (uintmax_t )stats -> objects .inflated_sizes .commits , value_delim );
558+ printf ("objects.trees.inflated%c%" PRIuMAX "%c" , key_delim ,
559+ (uintmax_t )stats -> objects .inflated_sizes .trees , value_delim );
560+ printf ("objects.blobs.inflated%c%" PRIuMAX "%c" , key_delim ,
561+ (uintmax_t )stats -> objects .inflated_sizes .blobs , value_delim );
562+ printf ("objects.tags.inflated%c%" PRIuMAX "%c" , key_delim ,
563+ (uintmax_t )stats -> objects .inflated_sizes .tags , value_delim );
564+
565+ printf ("objects.commits.disk%c%" PRIuMAX "%c" , key_delim ,
566+ (uintmax_t )stats -> objects .disk_sizes .commits , value_delim );
567+ printf ("objects.trees.disk%c%" PRIuMAX "%c" , key_delim ,
568+ (uintmax_t )stats -> objects .disk_sizes .trees , value_delim );
569+ printf ("objects.blobs.disk%c%" PRIuMAX "%c" , key_delim ,
570+ (uintmax_t )stats -> objects .disk_sizes .blobs , value_delim );
571+ printf ("objects.tags.disk%c%" PRIuMAX "%c" , key_delim ,
572+ (uintmax_t )stats -> objects .disk_sizes .tags , value_delim );
438573
439574 fflush (stdout );
440575}
@@ -499,6 +634,7 @@ static void structure_count_references(struct ref_stats *stats,
499634}
500635
501636struct count_objects_data {
637+ struct object_database * odb ;
502638 struct object_stats * stats ;
503639 struct progress * progress ;
504640};
@@ -508,26 +644,53 @@ static int count_objects(const char *path UNUSED, struct oid_array *oids,
508644{
509645 struct count_objects_data * data = cb_data ;
510646 struct object_stats * stats = data -> stats ;
647+ size_t inflated_total = 0 ;
648+ size_t disk_total = 0 ;
511649 size_t object_count ;
512650
651+ for (size_t i = 0 ; i < oids -> nr ; i ++ ) {
652+ struct object_info oi = OBJECT_INFO_INIT ;
653+ unsigned long inflated ;
654+ off_t disk ;
655+
656+ oi .sizep = & inflated ;
657+ oi .disk_sizep = & disk ;
658+
659+ if (odb_read_object_info_extended (data -> odb , & oids -> oid [i ], & oi ,
660+ OBJECT_INFO_FOR_PREFETCH ) < 0 )
661+ die (_ ("cannot read object for %s" ),
662+ oid_to_hex (& oids -> oid [i ]));
663+
664+ inflated_total += inflated ;
665+ disk_total += disk ;
666+ }
667+
513668 switch (type ) {
514669 case OBJ_TAG :
515- stats -> tags += oids -> nr ;
670+ stats -> type_counts .tags += oids -> nr ;
671+ stats -> inflated_sizes .tags += inflated_total ;
672+ stats -> disk_sizes .tags += disk_total ;
516673 break ;
517674 case OBJ_COMMIT :
518- stats -> commits += oids -> nr ;
675+ stats -> type_counts .commits += oids -> nr ;
676+ stats -> inflated_sizes .commits += inflated_total ;
677+ stats -> disk_sizes .commits += disk_total ;
519678 break ;
520679 case OBJ_TREE :
521- stats -> trees += oids -> nr ;
680+ stats -> type_counts .trees += oids -> nr ;
681+ stats -> inflated_sizes .trees += inflated_total ;
682+ stats -> disk_sizes .trees += disk_total ;
522683 break ;
523684 case OBJ_BLOB :
524- stats -> blobs += oids -> nr ;
685+ stats -> type_counts .blobs += oids -> nr ;
686+ stats -> inflated_sizes .blobs += inflated_total ;
687+ stats -> disk_sizes .blobs += disk_total ;
525688 break ;
526689 default :
527690 BUG ("invalid object type" );
528691 }
529692
530- object_count = get_total_object_count ( stats );
693+ object_count = get_total_object_values ( & stats -> type_counts );
531694 display_progress (data -> progress , object_count );
532695
533696 return 0 ;
@@ -539,6 +702,7 @@ static void structure_count_objects(struct object_stats *stats,
539702{
540703 struct path_walk_info info = PATH_WALK_INFO_INIT ;
541704 struct count_objects_data data = {
705+ .odb = repo -> objects ,
542706 .stats = stats ,
543707 };
544708
0 commit comments