[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20220905224849.80af1cb24d9eed1c1cdbcaee@kernel.org>
Date: Mon, 5 Sep 2022 22:48:49 +0900
From: Masami Hiramatsu (Google) <mhiramat@...nel.org>
To: Steven Rostedt <rostedt@...dmis.org>
Cc: linux-kernel@...r.kernel.org, Ingo Molnar <mingo@...nel.org>,
Andrew Morton <akpm@...ux-foundation.org>,
Masami Hiramatsu <mhiramat@...nel.org>,
Tom Zanussi <zanussi@...nel.org>
Subject: Re: [PATCH 2/4] tracing/hist: Call hist functions directly via a
switch statement
Hi Steve,
I found this crashed the kernel if I ran
# ftracetest test.d/trigger/trigger-hist-expressions.tc
More specifically, here is the minimum reproduce command.
# echo "hist:keys=common_pid:x=16-8-4" > events/sched/sched_process_fork/trigger
[ 75.874402] BUG: kernel NULL pointer dereference, address: 0000000000000038
[ 75.875378] #PF: supervisor read access in kernel mode
I investigated it and found you missed to set correct fn_num for
combined constant field;
> @@ -2725,7 +2748,8 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
> if (var2)
> expr->operands[1] = var2;
>
> - expr->constant = op_fn(expr, NULL, NULL, NULL, NULL);
> + expr->fn_num = op_fn;
> + expr->constant = hist_fn_call(expr, NULL, NULL, NULL, NULL);
>
> expr->operands[0] = NULL;
> expr->operands[1] = NULL;
Here, we need this;
expr->fn_num = HIST_FIELD_FN_CONST;
Without this fix, the binary op_fn is kept on this const field and it
causes the problem because the const field doesn't have operands.
Thank you,
On Tue, 23 Aug 2022 17:46:08 -0400
Steven Rostedt <rostedt@...dmis.org> wrote:
> From: "Steven Rostedt (Google)" <rostedt@...dmis.org>
>
> Due to retpolines, indirect calls are much more expensive than direct
> calls. The histograms have a select set of functions it uses for the
> histograms, instead of using function pointers to call them, create a
> hist_fn_call() function that uses a switch statement to call the histogram
> functions directly. This gives a 13% speedup to the histogram logic.
>
> Using the histogram benchmark:
>
> Before:
>
> # event histogram
> #
> # trigger info: hist:keys=delta:vals=hitcount:sort=delta:size=2048 if delta > 0 [active]
> #
>
> { delta: 129 } hitcount: 2213
> { delta: 130 } hitcount: 285965
> { delta: 131 } hitcount: 1146545
> { delta: 132 } hitcount: 5185432
> { delta: 133 } hitcount: 19896215
> { delta: 134 } hitcount: 53118616
> { delta: 135 } hitcount: 83816709
> { delta: 136 } hitcount: 68329562
> { delta: 137 } hitcount: 41859349
> { delta: 138 } hitcount: 46257797
> { delta: 139 } hitcount: 54400831
> { delta: 140 } hitcount: 72875007
> { delta: 141 } hitcount: 76193272
> { delta: 142 } hitcount: 49504263
> { delta: 143 } hitcount: 38821072
> { delta: 144 } hitcount: 47702679
> { delta: 145 } hitcount: 41357297
> { delta: 146 } hitcount: 22058238
> { delta: 147 } hitcount: 9720002
> { delta: 148 } hitcount: 3193542
> { delta: 149 } hitcount: 927030
> { delta: 150 } hitcount: 850772
> { delta: 151 } hitcount: 1477380
> { delta: 152 } hitcount: 2687977
> { delta: 153 } hitcount: 2865985
> { delta: 154 } hitcount: 1977492
> { delta: 155 } hitcount: 2475607
> { delta: 156 } hitcount: 3403612
>
> After:
>
> # event histogram
> #
> # trigger info: hist:keys=delta:vals=hitcount:sort=delta:size=2048 if delta > 0 [active]
> #
>
> { delta: 113 } hitcount: 272
> { delta: 114 } hitcount: 840
> { delta: 118 } hitcount: 344
> { delta: 119 } hitcount: 25428
> { delta: 120 } hitcount: 350590
> { delta: 121 } hitcount: 1892484
> { delta: 122 } hitcount: 6205004
> { delta: 123 } hitcount: 11583521
> { delta: 124 } hitcount: 37590979
> { delta: 125 } hitcount: 108308504
> { delta: 126 } hitcount: 131672461
> { delta: 127 } hitcount: 88700598
> { delta: 128 } hitcount: 65939870
> { delta: 129 } hitcount: 45055004
> { delta: 130 } hitcount: 33174464
> { delta: 131 } hitcount: 31813493
> { delta: 132 } hitcount: 29011676
> { delta: 133 } hitcount: 22798782
> { delta: 134 } hitcount: 22072486
> { delta: 135 } hitcount: 17034113
> { delta: 136 } hitcount: 8982490
> { delta: 137 } hitcount: 2865908
> { delta: 138 } hitcount: 980382
> { delta: 139 } hitcount: 1651944
> { delta: 140 } hitcount: 4112073
> { delta: 141 } hitcount: 3963269
> { delta: 142 } hitcount: 1712508
> { delta: 143 } hitcount: 575941
> { delta: 144 } hitcount: 351427
> { delta: 145 } hitcount: 218077
> { delta: 146 } hitcount: 167297
> { delta: 147 } hitcount: 146198
> { delta: 148 } hitcount: 116122
> { delta: 149 } hitcount: 58993
> { delta: 150 } hitcount: 40228
>
> The delta above is in nanoseconds. It brings the fastest time down from
> 129ns to 113ns, and the peak from 141ns to 126ns.
>
> Signed-off-by: Steven Rostedt (Google) <rostedt@...dmis.org>
> ---
> kernel/trace/trace_events_hist.c | 244 +++++++++++++++++++++----------
> 1 file changed, 168 insertions(+), 76 deletions(-)
>
> diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
> index fdf784620c28..92fbd72b6408 100644
> --- a/kernel/trace/trace_events_hist.c
> +++ b/kernel/trace/trace_events_hist.c
> @@ -104,6 +104,38 @@ enum field_op_id {
> FIELD_OP_MULT,
> };
>
> +enum hist_field_fn {
> + HIST_FIELD_FN_NOP,
> + HIST_FIELD_FN_VAR_REF,
> + HIST_FIELD_FN_COUNTER,
> + HIST_FIELD_FN_CONST,
> + HIST_FIELD_FN_LOG2,
> + HIST_FIELD_FN_BUCKET,
> + HIST_FIELD_FN_TIMESTAMP,
> + HIST_FIELD_FN_CPU,
> + HIST_FIELD_FN_STRING,
> + HIST_FIELD_FN_DYNSTRING,
> + HIST_FIELD_FN_RELDYNSTRING,
> + HIST_FIELD_FN_PSTRING,
> + HIST_FIELD_FN_S64,
> + HIST_FIELD_FN_U64,
> + HIST_FIELD_FN_S32,
> + HIST_FIELD_FN_U32,
> + HIST_FIELD_FN_S16,
> + HIST_FIELD_FN_U16,
> + HIST_FIELD_FN_S8,
> + HIST_FIELD_FN_U8,
> + HIST_FIELD_FN_UMINUS,
> + HIST_FIELD_FN_MINUS,
> + HIST_FIELD_FN_PLUS,
> + HIST_FIELD_FN_DIV,
> + HIST_FIELD_FN_MULT,
> + HIST_FIELD_FN_DIV_POWER2,
> + HIST_FIELD_FN_DIV_NOT_POWER2,
> + HIST_FIELD_FN_DIV_MULT_SHIFT,
> + HIST_FIELD_FN_EXECNAME,
> +};
> +
> /*
> * A hist_var (histogram variable) contains variable information for
> * hist_fields having the HIST_FIELD_FL_VAR or HIST_FIELD_FL_VAR_REF
> @@ -123,15 +155,15 @@ struct hist_var {
> struct hist_field {
> struct ftrace_event_field *field;
> unsigned long flags;
> - hist_field_fn_t fn;
> - unsigned int ref;
> - unsigned int size;
> - unsigned int offset;
> - unsigned int is_signed;
> unsigned long buckets;
> const char *type;
> struct hist_field *operands[HIST_FIELD_OPERANDS_MAX];
> struct hist_trigger_data *hist_data;
> + enum hist_field_fn fn_num;
> + unsigned int ref;
> + unsigned int size;
> + unsigned int offset;
> + unsigned int is_signed;
>
> /*
> * Variable fields contain variable-specific info in var.
> @@ -166,14 +198,11 @@ struct hist_field {
> u64 div_multiplier;
> };
>
> -static u64 hist_field_none(struct hist_field *field,
> - struct tracing_map_elt *elt,
> - struct trace_buffer *buffer,
> - struct ring_buffer_event *rbe,
> - void *event)
> -{
> - return 0;
> -}
> +static u64 hist_fn_call(struct hist_field *hist_field,
> + struct tracing_map_elt *elt,
> + struct trace_buffer *buffer,
> + struct ring_buffer_event *rbe,
> + void *event);
>
> static u64 hist_field_const(struct hist_field *field,
> struct tracing_map_elt *elt,
> @@ -250,7 +279,7 @@ static u64 hist_field_log2(struct hist_field *hist_field,
> {
> struct hist_field *operand = hist_field->operands[0];
>
> - u64 val = operand->fn(operand, elt, buffer, rbe, event);
> + u64 val = hist_fn_call(operand, elt, buffer, rbe, event);
>
> return (u64) ilog2(roundup_pow_of_two(val));
> }
> @@ -264,7 +293,7 @@ static u64 hist_field_bucket(struct hist_field *hist_field,
> struct hist_field *operand = hist_field->operands[0];
> unsigned long buckets = hist_field->buckets;
>
> - u64 val = operand->fn(operand, elt, buffer, rbe, event);
> + u64 val = hist_fn_call(operand, elt, buffer, rbe, event);
>
> if (WARN_ON_ONCE(!buckets))
> return val;
> @@ -285,8 +314,8 @@ static u64 hist_field_plus(struct hist_field *hist_field,
> struct hist_field *operand1 = hist_field->operands[0];
> struct hist_field *operand2 = hist_field->operands[1];
>
> - u64 val1 = operand1->fn(operand1, elt, buffer, rbe, event);
> - u64 val2 = operand2->fn(operand2, elt, buffer, rbe, event);
> + u64 val1 = hist_fn_call(operand1, elt, buffer, rbe, event);
> + u64 val2 = hist_fn_call(operand2, elt, buffer, rbe, event);
>
> return val1 + val2;
> }
> @@ -300,8 +329,8 @@ static u64 hist_field_minus(struct hist_field *hist_field,
> struct hist_field *operand1 = hist_field->operands[0];
> struct hist_field *operand2 = hist_field->operands[1];
>
> - u64 val1 = operand1->fn(operand1, elt, buffer, rbe, event);
> - u64 val2 = operand2->fn(operand2, elt, buffer, rbe, event);
> + u64 val1 = hist_fn_call(operand1, elt, buffer, rbe, event);
> + u64 val2 = hist_fn_call(operand2, elt, buffer, rbe, event);
>
> return val1 - val2;
> }
> @@ -315,8 +344,8 @@ static u64 hist_field_div(struct hist_field *hist_field,
> struct hist_field *operand1 = hist_field->operands[0];
> struct hist_field *operand2 = hist_field->operands[1];
>
> - u64 val1 = operand1->fn(operand1, elt, buffer, rbe, event);
> - u64 val2 = operand2->fn(operand2, elt, buffer, rbe, event);
> + u64 val1 = hist_fn_call(operand1, elt, buffer, rbe, event);
> + u64 val2 = hist_fn_call(operand2, elt, buffer, rbe, event);
>
> /* Return -1 for the undefined case */
> if (!val2)
> @@ -338,7 +367,7 @@ static u64 div_by_power_of_two(struct hist_field *hist_field,
> struct hist_field *operand1 = hist_field->operands[0];
> struct hist_field *operand2 = hist_field->operands[1];
>
> - u64 val1 = operand1->fn(operand1, elt, buffer, rbe, event);
> + u64 val1 = hist_fn_call(operand1, elt, buffer, rbe, event);
>
> return val1 >> __ffs64(operand2->constant);
> }
> @@ -352,7 +381,7 @@ static u64 div_by_not_power_of_two(struct hist_field *hist_field,
> struct hist_field *operand1 = hist_field->operands[0];
> struct hist_field *operand2 = hist_field->operands[1];
>
> - u64 val1 = operand1->fn(operand1, elt, buffer, rbe, event);
> + u64 val1 = hist_fn_call(operand1, elt, buffer, rbe, event);
>
> return div64_u64(val1, operand2->constant);
> }
> @@ -366,7 +395,7 @@ static u64 div_by_mult_and_shift(struct hist_field *hist_field,
> struct hist_field *operand1 = hist_field->operands[0];
> struct hist_field *operand2 = hist_field->operands[1];
>
> - u64 val1 = operand1->fn(operand1, elt, buffer, rbe, event);
> + u64 val1 = hist_fn_call(operand1, elt, buffer, rbe, event);
>
> /*
> * If the divisor is a constant, do a multiplication and shift instead.
> @@ -400,8 +429,8 @@ static u64 hist_field_mult(struct hist_field *hist_field,
> struct hist_field *operand1 = hist_field->operands[0];
> struct hist_field *operand2 = hist_field->operands[1];
>
> - u64 val1 = operand1->fn(operand1, elt, buffer, rbe, event);
> - u64 val2 = operand2->fn(operand2, elt, buffer, rbe, event);
> + u64 val1 = hist_fn_call(operand1, elt, buffer, rbe, event);
> + u64 val2 = hist_fn_call(operand2, elt, buffer, rbe, event);
>
> return val1 * val2;
> }
> @@ -414,7 +443,7 @@ static u64 hist_field_unary_minus(struct hist_field *hist_field,
> {
> struct hist_field *operand = hist_field->operands[0];
>
> - s64 sval = (s64)operand->fn(operand, elt, buffer, rbe, event);
> + s64 sval = (s64)hist_fn_call(operand, elt, buffer, rbe, event);
> u64 val = (u64)-sval;
>
> return val;
> @@ -657,19 +686,19 @@ struct snapshot_context {
> * Returns the specific division function to use if the divisor
> * is constant. This avoids extra branches when the trigger is hit.
> */
> -static hist_field_fn_t hist_field_get_div_fn(struct hist_field *divisor)
> +static enum hist_field_fn hist_field_get_div_fn(struct hist_field *divisor)
> {
> u64 div = divisor->constant;
>
> if (!(div & (div - 1)))
> - return div_by_power_of_two;
> + return HIST_FIELD_FN_DIV_POWER2;
>
> /* If the divisor is too large, do a regular division */
> if (div > (1 << HIST_DIV_SHIFT))
> - return div_by_not_power_of_two;
> + return HIST_FIELD_FN_DIV_NOT_POWER2;
>
> divisor->div_multiplier = div64_u64((u64)(1 << HIST_DIV_SHIFT), div);
> - return div_by_mult_and_shift;
> + return HIST_FIELD_FN_DIV_MULT_SHIFT;
> }
>
> static void track_data_free(struct track_data *track_data)
> @@ -1334,38 +1363,32 @@ static const char *hist_field_name(struct hist_field *field,
> return field_name;
> }
>
> -static hist_field_fn_t select_value_fn(int field_size, int field_is_signed)
> +static enum hist_field_fn select_value_fn(int field_size, int field_is_signed)
> {
> - hist_field_fn_t fn = NULL;
> -
> switch (field_size) {
> case 8:
> if (field_is_signed)
> - fn = hist_field_s64;
> + return HIST_FIELD_FN_S64;
> else
> - fn = hist_field_u64;
> - break;
> + return HIST_FIELD_FN_U64;
> case 4:
> if (field_is_signed)
> - fn = hist_field_s32;
> + return HIST_FIELD_FN_S32;
> else
> - fn = hist_field_u32;
> - break;
> + return HIST_FIELD_FN_U32;
> case 2:
> if (field_is_signed)
> - fn = hist_field_s16;
> + return HIST_FIELD_FN_S16;
> else
> - fn = hist_field_u16;
> - break;
> + return HIST_FIELD_FN_U16;
> case 1:
> if (field_is_signed)
> - fn = hist_field_s8;
> + return HIST_FIELD_FN_S8;
> else
> - fn = hist_field_u8;
> - break;
> + return HIST_FIELD_FN_U8;
> }
>
> - return fn;
> + return HIST_FIELD_FN_NOP;
> }
>
> static int parse_map_size(char *str)
> @@ -1922,19 +1945,19 @@ static struct hist_field *create_hist_field(struct hist_trigger_data *hist_data,
> goto out; /* caller will populate */
>
> if (flags & HIST_FIELD_FL_VAR_REF) {
> - hist_field->fn = hist_field_var_ref;
> + hist_field->fn_num = HIST_FIELD_FN_VAR_REF;
> goto out;
> }
>
> if (flags & HIST_FIELD_FL_HITCOUNT) {
> - hist_field->fn = hist_field_counter;
> + hist_field->fn_num = HIST_FIELD_FN_COUNTER;
> hist_field->size = sizeof(u64);
> hist_field->type = "u64";
> goto out;
> }
>
> if (flags & HIST_FIELD_FL_CONST) {
> - hist_field->fn = hist_field_const;
> + hist_field->fn_num = HIST_FIELD_FN_CONST;
> hist_field->size = sizeof(u64);
> hist_field->type = kstrdup("u64", GFP_KERNEL);
> if (!hist_field->type)
> @@ -1943,14 +1966,14 @@ static struct hist_field *create_hist_field(struct hist_trigger_data *hist_data,
> }
>
> if (flags & HIST_FIELD_FL_STACKTRACE) {
> - hist_field->fn = hist_field_none;
> + hist_field->fn_num = HIST_FIELD_FN_NOP;
> goto out;
> }
>
> if (flags & (HIST_FIELD_FL_LOG2 | HIST_FIELD_FL_BUCKET)) {
> unsigned long fl = flags & ~(HIST_FIELD_FL_LOG2 | HIST_FIELD_FL_BUCKET);
> - hist_field->fn = flags & HIST_FIELD_FL_LOG2 ? hist_field_log2 :
> - hist_field_bucket;
> + hist_field->fn_num = flags & HIST_FIELD_FL_LOG2 ? HIST_FIELD_FN_LOG2 :
> + HIST_FIELD_FN_BUCKET;
> hist_field->operands[0] = create_hist_field(hist_data, field, fl, NULL);
> hist_field->size = hist_field->operands[0]->size;
> hist_field->type = kstrdup_const(hist_field->operands[0]->type, GFP_KERNEL);
> @@ -1960,14 +1983,14 @@ static struct hist_field *create_hist_field(struct hist_trigger_data *hist_data,
> }
>
> if (flags & HIST_FIELD_FL_TIMESTAMP) {
> - hist_field->fn = hist_field_timestamp;
> + hist_field->fn_num = HIST_FIELD_FN_TIMESTAMP;
> hist_field->size = sizeof(u64);
> hist_field->type = "u64";
> goto out;
> }
>
> if (flags & HIST_FIELD_FL_CPU) {
> - hist_field->fn = hist_field_cpu;
> + hist_field->fn_num = HIST_FIELD_FN_CPU;
> hist_field->size = sizeof(int);
> hist_field->type = "unsigned int";
> goto out;
> @@ -1987,14 +2010,14 @@ static struct hist_field *create_hist_field(struct hist_trigger_data *hist_data,
> goto free;
>
> if (field->filter_type == FILTER_STATIC_STRING) {
> - hist_field->fn = hist_field_string;
> + hist_field->fn_num = HIST_FIELD_FN_STRING;
> hist_field->size = field->size;
> } else if (field->filter_type == FILTER_DYN_STRING) {
> - hist_field->fn = hist_field_dynstring;
> + hist_field->fn_num = HIST_FIELD_FN_DYNSTRING;
> } else if (field->filter_type == FILTER_RDYN_STRING)
> - hist_field->fn = hist_field_reldynstring;
> + hist_field->fn_num = HIST_FIELD_FN_RELDYNSTRING;
> else
> - hist_field->fn = hist_field_pstring;
> + hist_field->fn_num = HIST_FIELD_FN_PSTRING;
> } else {
> hist_field->size = field->size;
> hist_field->is_signed = field->is_signed;
> @@ -2002,9 +2025,9 @@ static struct hist_field *create_hist_field(struct hist_trigger_data *hist_data,
> if (!hist_field->type)
> goto free;
>
> - hist_field->fn = select_value_fn(field->size,
> - field->is_signed);
> - if (!hist_field->fn) {
> + hist_field->fn_num = select_value_fn(field->size,
> + field->is_signed);
> + if (hist_field->fn_num == HIST_FIELD_FN_NOP) {
> destroy_hist_field(hist_field, 0);
> return NULL;
> }
> @@ -2340,7 +2363,7 @@ static struct hist_field *create_alias(struct hist_trigger_data *hist_data,
> if (!alias)
> return NULL;
>
> - alias->fn = var_ref->fn;
> + alias->fn_num = var_ref->fn_num;
> alias->operands[0] = var_ref;
>
> if (init_var_ref(alias, var_ref, var_ref->system, var_ref->event_name)) {
> @@ -2523,7 +2546,7 @@ static struct hist_field *parse_unary(struct hist_trigger_data *hist_data,
>
> expr->flags |= operand1->flags &
> (HIST_FIELD_FL_TIMESTAMP | HIST_FIELD_FL_TIMESTAMP_USECS);
> - expr->fn = hist_field_unary_minus;
> + expr->fn_num = HIST_FIELD_FN_UMINUS;
> expr->operands[0] = operand1;
> expr->size = operand1->size;
> expr->is_signed = operand1->is_signed;
> @@ -2595,7 +2618,7 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
> unsigned long operand_flags, operand2_flags;
> int field_op, ret = -EINVAL;
> char *sep, *operand1_str;
> - hist_field_fn_t op_fn;
> + enum hist_field_fn op_fn;
> bool combine_consts;
>
> if (*n_subexprs > 3) {
> @@ -2654,16 +2677,16 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
>
> switch (field_op) {
> case FIELD_OP_MINUS:
> - op_fn = hist_field_minus;
> + op_fn = HIST_FIELD_FN_MINUS;
> break;
> case FIELD_OP_PLUS:
> - op_fn = hist_field_plus;
> + op_fn = HIST_FIELD_FN_PLUS;
> break;
> case FIELD_OP_DIV:
> - op_fn = hist_field_div;
> + op_fn = HIST_FIELD_FN_DIV;
> break;
> case FIELD_OP_MULT:
> - op_fn = hist_field_mult;
> + op_fn = HIST_FIELD_FN_MULT;
> break;
> default:
> ret = -EINVAL;
> @@ -2725,7 +2748,8 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
> if (var2)
> expr->operands[1] = var2;
>
> - expr->constant = op_fn(expr, NULL, NULL, NULL, NULL);
> + expr->fn_num = op_fn;
> + expr->constant = hist_fn_call(expr, NULL, NULL, NULL, NULL);
>
> expr->operands[0] = NULL;
> expr->operands[1] = NULL;
> @@ -2739,7 +2763,7 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
>
> expr->name = expr_str(expr, 0);
> } else {
> - expr->fn = op_fn;
> + expr->fn_num = op_fn;
>
> /* The operand sizes should be the same, so just pick one */
> expr->size = operand1->size;
> @@ -3065,7 +3089,7 @@ static inline void __update_field_vars(struct tracing_map_elt *elt,
> struct hist_field *var = field_var->var;
> struct hist_field *val = field_var->val;
>
> - var_val = val->fn(val, elt, buffer, rbe, rec);
> + var_val = hist_fn_call(val, elt, buffer, rbe, rec);
> var_idx = var->var.idx;
>
> if (val->flags & HIST_FIELD_FL_STRING) {
> @@ -4186,6 +4210,74 @@ static u64 hist_field_execname(struct hist_field *hist_field,
> return (u64)(unsigned long)(elt_data->comm);
> }
>
> +static u64 hist_fn_call(struct hist_field *hist_field,
> + struct tracing_map_elt *elt,
> + struct trace_buffer *buffer,
> + struct ring_buffer_event *rbe,
> + void *event)
> +{
> + switch (hist_field->fn_num) {
> + case HIST_FIELD_FN_VAR_REF:
> + return hist_field_var_ref(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_COUNTER:
> + return hist_field_counter(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_CONST:
> + return hist_field_const(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_LOG2:
> + return hist_field_log2(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_BUCKET:
> + return hist_field_bucket(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_TIMESTAMP:
> + return hist_field_timestamp(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_CPU:
> + return hist_field_cpu(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_STRING:
> + return hist_field_string(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_DYNSTRING:
> + return hist_field_dynstring(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_RELDYNSTRING:
> + return hist_field_reldynstring(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_PSTRING:
> + return hist_field_pstring(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_S64:
> + return hist_field_s64(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_U64:
> + return hist_field_u64(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_S32:
> + return hist_field_s32(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_U32:
> + return hist_field_u32(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_S16:
> + return hist_field_s16(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_U16:
> + return hist_field_u16(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_S8:
> + return hist_field_s8(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_U8:
> + return hist_field_u8(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_UMINUS:
> + return hist_field_unary_minus(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_MINUS:
> + return hist_field_minus(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_PLUS:
> + return hist_field_plus(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_DIV:
> + return hist_field_div(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_MULT:
> + return hist_field_mult(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_DIV_POWER2:
> + return div_by_power_of_two(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_DIV_NOT_POWER2:
> + return div_by_not_power_of_two(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_DIV_MULT_SHIFT:
> + return div_by_mult_and_shift(hist_field, elt, buffer, rbe, event);
> + case HIST_FIELD_FN_EXECNAME:
> + return hist_field_execname(hist_field, elt, buffer, rbe, event);
> + default:
> + return 0;
> + }
> +}
> +
> /* Convert a var that points to common_pid.execname to a string */
> static void update_var_execname(struct hist_field *hist_field)
> {
> @@ -4197,7 +4289,7 @@ static void update_var_execname(struct hist_field *hist_field)
> kfree_const(hist_field->type);
> hist_field->type = "char[]";
>
> - hist_field->fn = hist_field_execname;
> + hist_field->fn_num = HIST_FIELD_FN_EXECNAME;
> }
>
> static int create_var_field(struct hist_trigger_data *hist_data,
> @@ -4956,7 +5048,7 @@ static void hist_trigger_elt_update(struct hist_trigger_data *hist_data,
>
> for_each_hist_val_field(i, hist_data) {
> hist_field = hist_data->fields[i];
> - hist_val = hist_field->fn(hist_field, elt, buffer, rbe, rec);
> + hist_val = hist_fn_call(hist_field, elt, buffer, rbe, rec);
> if (hist_field->flags & HIST_FIELD_FL_VAR) {
> var_idx = hist_field->var.idx;
>
> @@ -4987,7 +5079,7 @@ static void hist_trigger_elt_update(struct hist_trigger_data *hist_data,
> for_each_hist_key_field(i, hist_data) {
> hist_field = hist_data->fields[i];
> if (hist_field->flags & HIST_FIELD_FL_VAR) {
> - hist_val = hist_field->fn(hist_field, elt, buffer, rbe, rec);
> + hist_val = hist_fn_call(hist_field, elt, buffer, rbe, rec);
> var_idx = hist_field->var.idx;
> tracing_map_set_var(elt, var_idx, hist_val);
> }
> @@ -5062,7 +5154,7 @@ static void event_hist_trigger(struct event_trigger_data *data,
> HIST_STACKTRACE_SKIP);
> key = entries;
> } else {
> - field_contents = key_field->fn(key_field, elt, buffer, rbe, rec);
> + field_contents = hist_fn_call(key_field, elt, buffer, rbe, rec);
> if (key_field->flags & HIST_FIELD_FL_STRING) {
> key = (void *)(unsigned long)field_contents;
> use_compound_key = true;
> --
> 2.35.1
--
Masami Hiramatsu (Google) <mhiramat@...nel.org>
Powered by blists - more mailing lists