@@ -1771,8 +1771,8 @@ using the same key and variable from yet another event::
# echo 'hist:key=pid:wakeupswitch_lat=$wakeup_lat+$switchtime_lat ...' >> event3/trigger
-Expressions support the use of addition, subtraction, multiplication and
-division operators (+-\*/).
+Expressions support the use of addition, subtraction, multiplication,
+division, modulus operators (+-\*/%).
Note if division by zero cannot be detected at parse time (i.e. the
divisor is not a constant), the result will be -1.
@@ -103,6 +103,7 @@ enum field_op_id {
FIELD_OP_UNARY_MINUS,
FIELD_OP_DIV,
FIELD_OP_MULT,
+ FIELD_OP_MOD,
};
enum hist_field_fn {
@@ -131,6 +132,7 @@ enum hist_field_fn {
HIST_FIELD_FN_PLUS,
HIST_FIELD_FN_DIV,
HIST_FIELD_FN_MULT,
+ HIST_FIELD_FN_MOD,
HIST_FIELD_FN_DIV_POWER2,
HIST_FIELD_FN_DIV_NOT_POWER2,
HIST_FIELD_FN_DIV_MULT_SHIFT,
@@ -436,6 +438,21 @@ static u64 hist_field_mult(struct hist_field *hist_field,
return val1 * val2;
}
+static u64 hist_field_mod(struct hist_field *hist_field,
+ struct tracing_map_elt *elt,
+ struct trace_buffer *buffer,
+ struct ring_buffer_event *rbe,
+ void *event)
+{
+ struct hist_field *operand1 = hist_field->operands[0];
+ struct hist_field *operand2 = hist_field->operands[1];
+
+ u64 val1 = hist_fn_call(operand1, elt, buffer, rbe, event);
+ u64 val2 = hist_fn_call(operand2, elt, buffer, rbe, event);
+
+ return val1 % val2;
+}
+
static u64 hist_field_unary_minus(struct hist_field *hist_field,
struct tracing_map_elt *elt,
struct trace_buffer *buffer,
@@ -1796,6 +1813,9 @@ static char *expr_str(struct hist_field *field, unsigned int level)
case FIELD_OP_MULT:
strcat(expr, "*");
break;
+ case FIELD_OP_MOD:
+ strcat(expr, "%");
+ break;
default:
kfree(expr);
return NULL;
@@ -1859,8 +1879,8 @@ static int contains_operator(char *str, char **sep)
return field_op;
/*
- * Second, consider the higher precedence multiplication and division
- * operators.
+ * Second, consider the higher precedence multiplication, division, and
+ * modulus operators.
*/
op = strrchr(str, '/');
if (op > *sep) {
@@ -1874,6 +1894,12 @@ static int contains_operator(char *str, char **sep)
field_op = FIELD_OP_MULT;
}
+ op = strrchr(str, '%');
+ if (op > *sep) {
+ *sep = op;
+ field_op = FIELD_OP_MOD;
+ }
+
return field_op;
}
@@ -2698,6 +2724,9 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
case FIELD_OP_MULT:
op_fn = HIST_FIELD_FN_MULT;
break;
+ case FIELD_OP_MOD:
+ op_fn = HIST_FIELD_FN_MOD;
+ break;
default:
ret = -EINVAL;
goto free_operands;
@@ -4289,6 +4318,8 @@ static u64 hist_fn_call(struct hist_field *hist_field,
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_MOD:
+ return hist_field_mod(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:
Currently historgram field expressions can use addition ('+'), substraction ('-'), division ('/'), and multiplication ('*') operators. It would be helpful to also have a modulus ('%') operator. This is helpful for capturing the alignment of pointers. For example, on arm64 with CONFIG_KPROBE_EVENTS_ON_NOTRACE=y, we can record the size and alignment of copies to user with: | # echo 'p:copy_to_user __arch_copy_to_user to=$arg1 from=$arg2 n=$arg3' >> /sys/kernel/tracing/kprobe_events | # echo 'hist keys=n,to%8:vals=hitcount:sort=n,to%8' > /sys/kernel/tracing/events/kprobes/copy_to_user/trigger | # cat /sys/kernel/tracing/events/kprobes/copy_to_user/hist | # event histogram | # | # trigger info: hist:keys=n,to%8:vals=hitcount:sort=n,to%8:size=2048 [active] | # | | { n: 1, to%8: 1 } hitcount: 5 | { n: 8, to%8: 0 } hitcount: 3 | { n: 16, to%8: 0 } hitcount: 2 | { n: 32, to%8: 0 } hitcount: 1 | { n: 36, to%8: 0 } hitcount: 1 | { n: 128, to%8: 0 } hitcount: 4 | { n: 336, to%8: 0 } hitcount: 1 | { n: 832, to%8: 0 } hitcount: 3 | | Totals: | Hits: 20 | Entries: 8 | Dropped: 0 Add a modulus operator, with the same precedence as multiplication and division, matching C's operator precedence. Signed-off-by: Mark Rutland <mark.rutland@arm.com> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Steven Rostedt (Google) <rostedt@goodmis.org> Cc: Tom Zanussi <zanussi@kernel.org> Cc: linux-trace-kernel@vger.kernel.org --- Documentation/trace/histogram.rst | 4 ++-- kernel/trace/trace_events_hist.c | 35 +++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-)