From: Nikolay Kuratov <kniv@yandex-team.ru>
To: linux-kernel@vger.kernel.org
Cc: linux-trace-kernel@vger.kernel.org,
Wen Yang <wenyang@linux.alibaba.com>,
Steven Rostedt <rostedt@goodmis.org>,
Mark Rutland <mark.rutland@arm.com>,
Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
kniv@yandex-team.ru
Subject: Re: [PATCH] ftrace: Avoid potential division by zero in function_stat_show()
Date: Wed, 5 Feb 2025 13:39:29 +0300 [thread overview]
Message-ID: <20250205103929.1538065-1-kniv@yandex-team.ru> (raw)
In-Reply-To: <20250204194820.7ef50d96@gandalf.local.home>
Your approach should prevent both zero division and overflow in the
denominator. We also should consider that the numerator
> stddev = counter * rec->time_squared - rec->stddev_time * rec->stddev_time;
may overflow too. Suppose 1000 ns per call case. On each function execution
time_squared would get additional 10^6. So for 32-bit and
MAX_STDDEV_COUNTER = 2072 we would have
counter * rec->time_squared = 2071 * (2071 * 10^6) = 4289041000000,
a 42-bit number.
It looks like overflow prevention here is not viable with macro constants,
since function execution time is dynamic in nature.
My suggestion is to rewrite formula such as we perform division earlier
and avoid overflow checks as much as possible. Note that doing divisions
earlier may result in precision loss, but I think that is acceptable since
rec->time is nanoseconds precision. Also this allows us to not care about
counter overflow at all, because expression rec->time * rec->time will always
overflow earlier than both counter and rec->time_square_sum. Renamed
time_squared into time_square_sum just to clarify.
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 728ecda6e8d4..91e7185dd5de 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -419,7 +419,8 @@ struct ftrace_profile {
unsigned long counter;
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
unsigned long long time;
- unsigned long long time_squared;
+ unsigned long long time_square_sum;
+ unsigned long long saved_stddev;
#endif
};
@@ -560,22 +561,24 @@ static int function_stat_show(struct seq_file *m, void *v)
seq_puts(m, " ");
/* Sample standard deviation (s^2) */
- if (rec->counter <= 1)
+ if (rec->counter <= 1 || !rec->time)
stddev = 0;
+ else if (div64_ul(rec->time * rec->time, rec->time) != rec->time)
+ stddev = rec->saved_stddev;
else {
/*
- * Apply Welford's method:
- * s^2 = 1 / (n * (n-1)) * (n * \Sum (x_i)^2 - (\Sum x_i)^2)
+ * A formula for calculating the variance is:
+ * s^2 = (\Sum (x_i)^2 - (\Sum x_i)^2 / n) / (n - 1)
*/
- stddev = rec->counter * rec->time_squared -
- rec->time * rec->time;
-
+ stddev = rec->time_square_sum -
+ div64_ul(rec->time * rec->time, rec->counter);
+ stddev = div64_ul(stddev, rec->counter - 1);
/*
* Divide only 1000 for ns^2 -> us^2 conversion.
* trace_print_graph_duration will divide 1000 again.
*/
- stddev = div64_ul(stddev,
- rec->counter * (rec->counter - 1) * 1000);
+ stddev = div64_ul(stddev, 1000);
+ rec->saved_stddev = stddev;
}
trace_seq_init(&s);
@@ -888,7 +891,7 @@ static void profile_graph_return(struct ftrace_graph_ret *trace,
rec = ftrace_find_profiled_func(stat, trace->func);
if (rec) {
rec->time += calltime;
- rec->time_squared += calltime * calltime;
+ rec->time_square_sum += calltime * calltime;
}
}
next prev parent reply other threads:[~2025-02-05 10:42 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-31 15:53 [PATCH] ftrace: Avoid potential division by zero in function_stat_show() Nikolay Kuratov
2025-02-03 15:06 ` Steven Rostedt
2025-02-04 7:43 ` Nikolay Kuratov
2025-02-04 22:20 ` Steven Rostedt
2025-02-05 0:48 ` Steven Rostedt
2025-02-05 10:39 ` Nikolay Kuratov [this message]
2025-02-05 11:21 ` Nikolay Kuratov
2025-02-05 14:50 ` Steven Rostedt
2025-02-06 8:57 ` Nikolay Kuratov
2025-02-06 9:01 ` [PATCH v2] " Nikolay Kuratov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250205103929.1538065-1-kniv@yandex-team.ru \
--to=kniv@yandex-team.ru \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mathieu.desnoyers@efficios.com \
--cc=rostedt@goodmis.org \
--cc=wenyang@linux.alibaba.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox