68
68
C(INVALID_SORT_FIELD, "Sort field must be a key or a val"), \
69
69
C(INVALID_STR_OPERAND, "String type can not be an operand in expression"), \
70
70
C(EXPECT_NUMBER, "Expecting numeric literal"), \
71
- C(UNARY_MINUS_SUBEXPR, "Unary minus not supported in sub-expressions"),
71
+ C(UNARY_MINUS_SUBEXPR, "Unary minus not supported in sub-expressions"), \
72
+ C(DIVISION_BY_ZERO, "Division by zero"),
72
73
73
74
#undef C
74
75
#define C (a , b ) HIST_ERR_##a
@@ -92,6 +93,7 @@ typedef u64 (*hist_field_fn_t) (struct hist_field *field,
92
93
#define HIST_FIELDS_MAX (TRACING_MAP_FIELDS_MAX + TRACING_MAP_VARS_MAX)
93
94
#define HIST_ACTIONS_MAX 8
94
95
#define HIST_CONST_DIGITS_MAX 21
96
+ #define HIST_DIV_SHIFT 20 /* For optimizing division by constants */
95
97
96
98
enum field_op_id {
97
99
FIELD_OP_NONE ,
@@ -160,6 +162,8 @@ struct hist_field {
160
162
161
163
/* Numeric literals are represented as u64 */
162
164
u64 constant ;
165
+ /* Used to optimize division by constants */
166
+ u64 div_multiplier ;
163
167
};
164
168
165
169
static u64 hist_field_none (struct hist_field * field ,
@@ -311,6 +315,68 @@ static u64 hist_field_div(struct hist_field *hist_field,
311
315
return div64_u64 (val1 , val2 );
312
316
}
313
317
318
+ static u64 div_by_power_of_two (struct hist_field * hist_field ,
319
+ struct tracing_map_elt * elt ,
320
+ struct trace_buffer * buffer ,
321
+ struct ring_buffer_event * rbe ,
322
+ void * event )
323
+ {
324
+ struct hist_field * operand1 = hist_field -> operands [0 ];
325
+ struct hist_field * operand2 = hist_field -> operands [1 ];
326
+
327
+ u64 val1 = operand1 -> fn (operand1 , elt , buffer , rbe , event );
328
+
329
+ return val1 >> __ffs64 (operand2 -> constant );
330
+ }
331
+
332
+ static u64 div_by_not_power_of_two (struct hist_field * hist_field ,
333
+ struct tracing_map_elt * elt ,
334
+ struct trace_buffer * buffer ,
335
+ struct ring_buffer_event * rbe ,
336
+ void * event )
337
+ {
338
+ struct hist_field * operand1 = hist_field -> operands [0 ];
339
+ struct hist_field * operand2 = hist_field -> operands [1 ];
340
+
341
+ u64 val1 = operand1 -> fn (operand1 , elt , buffer , rbe , event );
342
+
343
+ return div64_u64 (val1 , operand2 -> constant );
344
+ }
345
+
346
+ static u64 div_by_mult_and_shift (struct hist_field * hist_field ,
347
+ struct tracing_map_elt * elt ,
348
+ struct trace_buffer * buffer ,
349
+ struct ring_buffer_event * rbe ,
350
+ void * event )
351
+ {
352
+ struct hist_field * operand1 = hist_field -> operands [0 ];
353
+ struct hist_field * operand2 = hist_field -> operands [1 ];
354
+
355
+ u64 val1 = operand1 -> fn (operand1 , elt , buffer , rbe , event );
356
+
357
+ /*
358
+ * If the divisor is a constant, do a multiplication and shift instead.
359
+ *
360
+ * Choose Z = some power of 2. If Y <= Z, then:
361
+ * X / Y = (X * (Z / Y)) / Z
362
+ *
363
+ * (Z / Y) is a constant (mult) which is calculated at parse time, so:
364
+ * X / Y = (X * mult) / Z
365
+ *
366
+ * The division by Z can be replaced by a shift since Z is a power of 2:
367
+ * X / Y = (X * mult) >> HIST_DIV_SHIFT
368
+ *
369
+ * As long, as X < Z the results will not be off by more than 1.
370
+ */
371
+ if (val1 < (1 << HIST_DIV_SHIFT )) {
372
+ u64 mult = operand2 -> div_multiplier ;
373
+
374
+ return (val1 * mult + ((1 << HIST_DIV_SHIFT ) - 1 )) >> HIST_DIV_SHIFT ;
375
+ }
376
+
377
+ return div64_u64 (val1 , operand2 -> constant );
378
+ }
379
+
314
380
static u64 hist_field_mult (struct hist_field * hist_field ,
315
381
struct tracing_map_elt * elt ,
316
382
struct trace_buffer * buffer ,
@@ -573,6 +639,25 @@ struct snapshot_context {
573
639
void * key ;
574
640
};
575
641
642
+ /*
643
+ * Returns the specific division function to use if the divisor
644
+ * is constant. This avoids extra branches when the trigger is hit.
645
+ */
646
+ static hist_field_fn_t hist_field_get_div_fn (struct hist_field * divisor )
647
+ {
648
+ u64 div = divisor -> constant ;
649
+
650
+ if (!(div & (div - 1 )))
651
+ return div_by_power_of_two ;
652
+
653
+ /* If the divisor is too large, do a regular division */
654
+ if (div > (1 << HIST_DIV_SHIFT ))
655
+ return div_by_not_power_of_two ;
656
+
657
+ divisor -> div_multiplier = div64_u64 ((u64 )(1 << HIST_DIV_SHIFT ), div );
658
+ return div_by_mult_and_shift ;
659
+ }
660
+
576
661
static void track_data_free (struct track_data * track_data )
577
662
{
578
663
struct hist_elt_data * elt_data ;
@@ -2575,6 +2660,24 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
2575
2660
expr -> operands [0 ] = operand1 ;
2576
2661
expr -> operands [1 ] = operand2 ;
2577
2662
2663
+ if (field_op == FIELD_OP_DIV &&
2664
+ operand2_flags & HIST_FIELD_FL_CONST ) {
2665
+ u64 divisor = var2 ? var2 -> constant : operand2 -> constant ;
2666
+
2667
+ if (!divisor ) {
2668
+ hist_err (file -> tr , HIST_ERR_DIVISION_BY_ZERO , errpos (str ));
2669
+ ret = - EDOM ;
2670
+ goto free ;
2671
+ }
2672
+
2673
+ /*
2674
+ * Copy the divisor here so we don't have to look it up
2675
+ * later if this is a var ref
2676
+ */
2677
+ operand2 -> constant = divisor ;
2678
+ op_fn = hist_field_get_div_fn (operand2 );
2679
+ }
2680
+
2578
2681
if (combine_consts ) {
2579
2682
if (var1 )
2580
2683
expr -> operands [0 ] = var1 ;
0 commit comments