@@ -506,6 +506,7 @@ enum hist_field_flags {
506
506
HIST_FIELD_FL_ALIAS = 1 << 16 ,
507
507
HIST_FIELD_FL_BUCKET = 1 << 17 ,
508
508
HIST_FIELD_FL_CONST = 1 << 18 ,
509
+ HIST_FIELD_FL_PERCENT = 1 << 19 ,
509
510
};
510
511
511
512
struct var_defs {
@@ -1707,6 +1708,8 @@ static const char *get_hist_field_flags(struct hist_field *hist_field)
1707
1708
flags_str = "buckets" ;
1708
1709
else if (hist_field -> flags & HIST_FIELD_FL_TIMESTAMP_USECS )
1709
1710
flags_str = "usecs" ;
1711
+ else if (hist_field -> flags & HIST_FIELD_FL_PERCENT )
1712
+ flags_str = "percent" ;
1710
1713
1711
1714
return flags_str ;
1712
1715
}
@@ -2315,6 +2318,10 @@ parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file,
2315
2318
if (ret || !(* buckets ))
2316
2319
goto error ;
2317
2320
* flags |= HIST_FIELD_FL_BUCKET ;
2321
+ } else if (strncmp (modifier , "percent" , 7 ) == 0 ) {
2322
+ if (* flags & (HIST_FIELD_FL_VAR | HIST_FIELD_FL_KEY ))
2323
+ goto error ;
2324
+ * flags |= HIST_FIELD_FL_PERCENT ;
2318
2325
} else {
2319
2326
error :
2320
2327
hist_err (tr , HIST_ERR_BAD_FIELD_MODIFIER , errpos (modifier ));
@@ -5291,33 +5298,69 @@ static void hist_trigger_print_key(struct seq_file *m,
5291
5298
seq_puts (m , "}" );
5292
5299
}
5293
5300
5301
+ /* Get the 100 times of the percentage of @val in @total */
5302
+ static inline unsigned int __get_percentage (u64 val , u64 total )
5303
+ {
5304
+ if (!total )
5305
+ goto div0 ;
5306
+
5307
+ if (val < (U64_MAX / 10000 ))
5308
+ return (unsigned int )div64_ul (val * 10000 , total );
5309
+
5310
+ total = div64_u64 (total , 10000 );
5311
+ if (!total )
5312
+ goto div0 ;
5313
+
5314
+ return (unsigned int )div64_ul (val , total );
5315
+ div0 :
5316
+ return val ? UINT_MAX : 0 ;
5317
+ }
5318
+
5319
+ static void hist_trigger_print_val (struct seq_file * m , unsigned int idx ,
5320
+ const char * field_name , unsigned long flags ,
5321
+ u64 * totals , struct tracing_map_elt * elt )
5322
+ {
5323
+ u64 val = tracing_map_read_sum (elt , idx );
5324
+ unsigned int pc ;
5325
+
5326
+ if (flags & HIST_FIELD_FL_PERCENT ) {
5327
+ pc = __get_percentage (val , totals [idx ]);
5328
+ if (pc == UINT_MAX )
5329
+ seq_printf (m , " %s (%%):[ERROR]" , field_name );
5330
+ else
5331
+ seq_printf (m , " %s (%%): %3u.%02u" , field_name ,
5332
+ pc / 100 , pc % 100 );
5333
+ } else if (flags & HIST_FIELD_FL_HEX ) {
5334
+ seq_printf (m , " %s: %10llx" , field_name , val );
5335
+ } else {
5336
+ seq_printf (m , " %s: %10llu" , field_name , val );
5337
+ }
5338
+ }
5339
+
5294
5340
static void hist_trigger_entry_print (struct seq_file * m ,
5295
5341
struct hist_trigger_data * hist_data ,
5342
+ u64 * totals ,
5296
5343
void * key ,
5297
5344
struct tracing_map_elt * elt )
5298
5345
{
5299
5346
const char * field_name ;
5300
- unsigned int i ;
5347
+ unsigned int i = HITCOUNT_IDX ;
5348
+ unsigned long flags ;
5301
5349
5302
5350
hist_trigger_print_key (m , hist_data , key , elt );
5303
5351
5304
- seq_printf ( m , " hitcount: %10llu" ,
5305
- tracing_map_read_sum ( elt , HITCOUNT_IDX ) );
5352
+ /* At first, show the raw hitcount always */
5353
+ hist_trigger_print_val ( m , i , "hitcount" , 0 , totals , elt );
5306
5354
5307
5355
for (i = 1 ; i < hist_data -> n_vals ; i ++ ) {
5308
5356
field_name = hist_field_name (hist_data -> fields [i ], 0 );
5357
+ flags = hist_data -> fields [i ]-> flags ;
5309
5358
5310
- if (hist_data -> fields [i ]-> flags & HIST_FIELD_FL_VAR ||
5311
- hist_data -> fields [i ]-> flags & HIST_FIELD_FL_EXPR )
5359
+ if (flags & HIST_FIELD_FL_VAR || flags & HIST_FIELD_FL_EXPR )
5312
5360
continue ;
5313
5361
5314
- if (hist_data -> fields [i ]-> flags & HIST_FIELD_FL_HEX ) {
5315
- seq_printf (m , " %s: %10llx" , field_name ,
5316
- tracing_map_read_sum (elt , i ));
5317
- } else {
5318
- seq_printf (m , " %s: %10llu" , field_name ,
5319
- tracing_map_read_sum (elt , i ));
5320
- }
5362
+ seq_puts (m , " " );
5363
+ hist_trigger_print_val (m , i , field_name , flags , totals , elt );
5321
5364
}
5322
5365
5323
5366
print_actions (m , hist_data , elt );
@@ -5330,19 +5373,38 @@ static int print_entries(struct seq_file *m,
5330
5373
{
5331
5374
struct tracing_map_sort_entry * * sort_entries = NULL ;
5332
5375
struct tracing_map * map = hist_data -> map ;
5333
- int i , n_entries ;
5376
+ int i , j , n_entries ;
5377
+ u64 * totals = NULL ;
5334
5378
5335
5379
n_entries = tracing_map_sort_entries (map , hist_data -> sort_keys ,
5336
5380
hist_data -> n_sort_keys ,
5337
5381
& sort_entries );
5338
5382
if (n_entries < 0 )
5339
5383
return n_entries ;
5340
5384
5385
+ for (j = 0 ; j < hist_data -> n_vals ; j ++ ) {
5386
+ if (!(hist_data -> fields [j ]-> flags & HIST_FIELD_FL_PERCENT ))
5387
+ continue ;
5388
+ if (!totals ) {
5389
+ totals = kcalloc (hist_data -> n_vals , sizeof (u64 ),
5390
+ GFP_KERNEL );
5391
+ if (!totals ) {
5392
+ n_entries = - ENOMEM ;
5393
+ goto out ;
5394
+ }
5395
+ }
5396
+ for (i = 0 ; i < n_entries ; i ++ )
5397
+ totals [j ] += tracing_map_read_sum (
5398
+ sort_entries [i ]-> elt , j );
5399
+ }
5400
+
5341
5401
for (i = 0 ; i < n_entries ; i ++ )
5342
- hist_trigger_entry_print (m , hist_data ,
5402
+ hist_trigger_entry_print (m , hist_data , totals ,
5343
5403
sort_entries [i ]-> key ,
5344
5404
sort_entries [i ]-> elt );
5345
5405
5406
+ kfree (totals );
5407
+ out :
5346
5408
tracing_map_destroy_sort_entries (sort_entries , n_entries );
5347
5409
5348
5410
return n_entries ;
0 commit comments