@@ -58,6 +58,7 @@ enum osnoise_options_index {
5858 OSN_PANIC_ON_STOP ,
5959 OSN_PREEMPT_DISABLE ,
6060 OSN_IRQ_DISABLE ,
61+ OSN_TIMERLAT_ALIGN ,
6162 OSN_MAX
6263};
6364
@@ -66,7 +67,8 @@ static const char * const osnoise_options_str[OSN_MAX] = {
6667 "OSNOISE_WORKLOAD" ,
6768 "PANIC_ON_STOP" ,
6869 "OSNOISE_PREEMPT_DISABLE" ,
69- "OSNOISE_IRQ_DISABLE" };
70+ "OSNOISE_IRQ_DISABLE" ,
71+ "TIMERLAT_ALIGN" };
7072
7173#define OSN_DEFAULT_OPTIONS 0x2
7274static unsigned long osnoise_options = OSN_DEFAULT_OPTIONS ;
@@ -250,6 +252,11 @@ struct timerlat_variables {
250252
251253static DEFINE_PER_CPU (struct timerlat_variables , per_cpu_timerlat_var ) ;
252254
255+ /*
256+ * timerlat wake-up offset for next thread with TIMERLAT_ALIGN set.
257+ */
258+ static atomic64_t align_next ;
259+
253260/*
254261 * this_cpu_tmr_var - Return the per-cpu timerlat_variables on its relative CPU
255262 */
@@ -268,6 +275,7 @@ static inline void tlat_var_reset(void)
268275
269276 /* Synchronize with the timerlat interfaces */
270277 mutex_lock (& interface_lock );
278+
271279 /*
272280 * So far, all the values are initialized as 0, so
273281 * zeroing the structure is perfect.
@@ -278,6 +286,12 @@ static inline void tlat_var_reset(void)
278286 hrtimer_cancel (& tlat_var -> timer );
279287 memset (tlat_var , 0 , sizeof (* tlat_var ));
280288 }
289+ /*
290+ * Reset also align_next, to be filled by a new offset by the first timerlat
291+ * thread that wakes up, if TIMERLAT_ALIGN is set.
292+ */
293+ atomic64_set (& align_next , 0 );
294+
281295 mutex_unlock (& interface_lock );
282296}
283297#else /* CONFIG_TIMERLAT_TRACER */
@@ -326,6 +340,7 @@ static struct osnoise_data {
326340 u64 stop_tracing_total ; /* stop trace in the final operation (report/thread) */
327341#ifdef CONFIG_TIMERLAT_TRACER
328342 u64 timerlat_period ; /* timerlat period */
343+ u64 timerlat_align_us ; /* timerlat alignment */
329344 u64 print_stack ; /* print IRQ stack if total > */
330345 int timerlat_tracer ; /* timerlat tracer */
331346#endif
@@ -338,6 +353,7 @@ static struct osnoise_data {
338353#ifdef CONFIG_TIMERLAT_TRACER
339354 .print_stack = 0 ,
340355 .timerlat_period = DEFAULT_TIMERLAT_PERIOD ,
356+ .timerlat_align_us = 0 ,
341357 .timerlat_tracer = 0 ,
342358#endif
343359};
@@ -1829,6 +1845,26 @@ static int wait_next_period(struct timerlat_variables *tlat)
18291845 */
18301846 tlat -> abs_period = (u64 ) ktime_to_ns (next_abs_period );
18311847
1848+ /*
1849+ * Align thread in the first cycle on each CPU to the set alignment
1850+ * if TIMERLAT_ALIGN is set.
1851+ *
1852+ * This is done by using an atomic64_t to store the next absolute period.
1853+ * The first thread that wakes up will set the atomic64_t to its
1854+ * absolute period, and the other threads will increment it by
1855+ * the alignment value.
1856+ */
1857+ if (test_bit (OSN_TIMERLAT_ALIGN , & osnoise_options ) && !tlat -> count
1858+ && atomic64_cmpxchg_relaxed (& align_next , 0 , tlat -> abs_period )) {
1859+ /*
1860+ * A thread has already set align_next, use it and increment it
1861+ * to be used by the next thread that wakes up after this one.
1862+ */
1863+ tlat -> abs_period = atomic64_add_return_relaxed (
1864+ osnoise_data .timerlat_align_us * 1000 , & align_next );
1865+ next_abs_period = ns_to_ktime (tlat -> abs_period );
1866+ }
1867+
18321868 /*
18331869 * If the new abs_period is in the past, skip the activation.
18341870 */
@@ -2650,6 +2686,17 @@ static struct trace_min_max_param timerlat_period = {
26502686 .min = & timerlat_min_period ,
26512687};
26522688
2689+ /*
2690+ * osnoise/timerlat_align_us: align the first wakeup of all timerlat
2691+ * threads to a common boundary (in us). 0 means disabled.
2692+ */
2693+ static struct trace_min_max_param timerlat_align_us = {
2694+ .lock = & interface_lock ,
2695+ .val = & osnoise_data .timerlat_align_us ,
2696+ .max = NULL ,
2697+ .min = NULL ,
2698+ };
2699+
26532700static const struct file_operations timerlat_fd_fops = {
26542701 .open = timerlat_fd_open ,
26552702 .read = timerlat_fd_read ,
@@ -2746,6 +2793,11 @@ static int init_timerlat_tracefs(struct dentry *top_dir)
27462793 if (!tmp )
27472794 return - ENOMEM ;
27482795
2796+ tmp = tracefs_create_file ("timerlat_align_us" , TRACE_MODE_WRITE , top_dir ,
2797+ & timerlat_align_us , & trace_min_max_fops );
2798+ if (!tmp )
2799+ return - ENOMEM ;
2800+
27492801 retval = osnoise_create_cpu_timerlat_fd (top_dir );
27502802 if (retval )
27512803 return retval ;
0 commit comments