Skip to content

Commit f47716b

Browse files
Kalesh Singhrostedt
authored andcommitted
tracing/histogram: Covert expr to const if both operands are constants
If both operands of a hist trigger expression are constants, convert the expression to a constant. This optimization avoids having to perform the same calculation multiple times and also saves on memory since the merged constants are represented by a single struct hist_field instead or multiple. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Kalesh Singh <[email protected]> Suggested-by: Steven Rostedt <[email protected]> Signed-off-by: Steven Rostedt (VMware) <[email protected]>
1 parent c5eac6e commit f47716b

File tree

1 file changed

+74
-30
lines changed

1 file changed

+74
-30
lines changed

kernel/trace/trace_events_hist.c

Lines changed: 74 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2411,9 +2411,15 @@ static struct hist_field *parse_unary(struct hist_trigger_data *hist_data,
24112411
return ERR_PTR(ret);
24122412
}
24132413

2414+
/*
2415+
* If the operands are var refs, return pointers the
2416+
* variable(s) referenced in var1 and var2, else NULL.
2417+
*/
24142418
static int check_expr_operands(struct trace_array *tr,
24152419
struct hist_field *operand1,
2416-
struct hist_field *operand2)
2420+
struct hist_field *operand2,
2421+
struct hist_field **var1,
2422+
struct hist_field **var2)
24172423
{
24182424
unsigned long operand1_flags = operand1->flags;
24192425
unsigned long operand2_flags = operand2->flags;
@@ -2426,6 +2432,7 @@ static int check_expr_operands(struct trace_array *tr,
24262432
if (!var)
24272433
return -EINVAL;
24282434
operand1_flags = var->flags;
2435+
*var1 = var;
24292436
}
24302437

24312438
if ((operand2_flags & HIST_FIELD_FL_VAR_REF) ||
@@ -2436,6 +2443,7 @@ static int check_expr_operands(struct trace_array *tr,
24362443
if (!var)
24372444
return -EINVAL;
24382445
operand2_flags = var->flags;
2446+
*var2 = var;
24392447
}
24402448

24412449
if ((operand1_flags & HIST_FIELD_FL_TIMESTAMP_USECS) !=
@@ -2453,9 +2461,12 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
24532461
char *var_name, unsigned int *n_subexprs)
24542462
{
24552463
struct hist_field *operand1 = NULL, *operand2 = NULL, *expr = NULL;
2456-
unsigned long operand_flags;
2464+
struct hist_field *var1 = NULL, *var2 = NULL;
2465+
unsigned long operand_flags, operand2_flags;
24572466
int field_op, ret = -EINVAL;
24582467
char *sep, *operand1_str;
2468+
hist_field_fn_t op_fn;
2469+
bool combine_consts;
24592470

24602471
if (*n_subexprs > 3) {
24612472
hist_err(file->tr, HIST_ERR_TOO_MANY_SUBEXPR, errpos(str));
@@ -2512,11 +2523,38 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
25122523
goto free;
25132524
}
25142525

2515-
ret = check_expr_operands(file->tr, operand1, operand2);
2526+
switch (field_op) {
2527+
case FIELD_OP_MINUS:
2528+
op_fn = hist_field_minus;
2529+
break;
2530+
case FIELD_OP_PLUS:
2531+
op_fn = hist_field_plus;
2532+
break;
2533+
case FIELD_OP_DIV:
2534+
op_fn = hist_field_div;
2535+
break;
2536+
case FIELD_OP_MULT:
2537+
op_fn = hist_field_mult;
2538+
break;
2539+
default:
2540+
ret = -EINVAL;
2541+
goto free;
2542+
}
2543+
2544+
ret = check_expr_operands(file->tr, operand1, operand2, &var1, &var2);
25162545
if (ret)
25172546
goto free;
25182547

2519-
flags |= HIST_FIELD_FL_EXPR;
2548+
operand_flags = var1 ? var1->flags : operand1->flags;
2549+
operand2_flags = var2 ? var2->flags : operand2->flags;
2550+
2551+
/*
2552+
* If both operands are constant, the expression can be
2553+
* collapsed to a single constant.
2554+
*/
2555+
combine_consts = operand_flags & operand2_flags & HIST_FIELD_FL_CONST;
2556+
2557+
flags |= combine_consts ? HIST_FIELD_FL_CONST : HIST_FIELD_FL_EXPR;
25202558

25212559
flags |= operand1->flags &
25222560
(HIST_FIELD_FL_TIMESTAMP | HIST_FIELD_FL_TIMESTAMP_USECS);
@@ -2533,37 +2571,43 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
25332571
expr->operands[0] = operand1;
25342572
expr->operands[1] = operand2;
25352573

2536-
/* The operand sizes should be the same, so just pick one */
2537-
expr->size = operand1->size;
2574+
if (combine_consts) {
2575+
if (var1)
2576+
expr->operands[0] = var1;
2577+
if (var2)
2578+
expr->operands[1] = var2;
25382579

2539-
expr->operator = field_op;
2540-
expr->name = expr_str(expr, 0);
2541-
expr->type = kstrdup_const(operand1->type, GFP_KERNEL);
2542-
if (!expr->type) {
2543-
ret = -ENOMEM;
2544-
goto free;
2545-
}
2580+
expr->constant = op_fn(expr, NULL, NULL, NULL, NULL);
25462581

2547-
switch (field_op) {
2548-
case FIELD_OP_MINUS:
2549-
expr->fn = hist_field_minus;
2550-
break;
2551-
case FIELD_OP_PLUS:
2552-
expr->fn = hist_field_plus;
2553-
break;
2554-
case FIELD_OP_DIV:
2555-
expr->fn = hist_field_div;
2556-
break;
2557-
case FIELD_OP_MULT:
2558-
expr->fn = hist_field_mult;
2559-
break;
2560-
default:
2561-
ret = -EINVAL;
2562-
goto free;
2582+
expr->operands[0] = NULL;
2583+
expr->operands[1] = NULL;
2584+
2585+
/*
2586+
* var refs won't be destroyed immediately
2587+
* See: destroy_hist_field()
2588+
*/
2589+
destroy_hist_field(operand2, 0);
2590+
destroy_hist_field(operand1, 0);
2591+
2592+
expr->name = expr_str(expr, 0);
2593+
} else {
2594+
expr->fn = op_fn;
2595+
2596+
/* The operand sizes should be the same, so just pick one */
2597+
expr->size = operand1->size;
2598+
2599+
expr->operator = field_op;
2600+
expr->type = kstrdup_const(operand1->type, GFP_KERNEL);
2601+
if (!expr->type) {
2602+
ret = -ENOMEM;
2603+
goto free;
2604+
}
2605+
2606+
expr->name = expr_str(expr, 0);
25632607
}
25642608

25652609
return expr;
2566-
free:
2610+
free:
25672611
destroy_hist_field(operand1, 0);
25682612
destroy_hist_field(operand2, 0);
25692613
destroy_hist_field(expr, 0);

0 commit comments

Comments
 (0)