linux/kernel/trace/trace_osnoise.c

// SPDX-License-Identifier: GPL-2.0
/*
 * OS Noise Tracer: computes the OS Noise suffered by a running thread.
 * Timerlat Tracer: measures the wakeup latency of a timer triggered IRQ and thread.
 *
 * Based on "hwlat_detector" tracer by:
 *   Copyright (C) 2008-2009 Jon Masters, Red Hat, Inc. <[email protected]>
 *   Copyright (C) 2013-2016 Steven Rostedt, Red Hat, Inc. <[email protected]>
 *   With feedback from Clark Williams <[email protected]>
 *
 * And also based on the rtsl tracer presented on:
 *  DE OLIVEIRA, Daniel Bristot, et al. Demystifying the real-time linux
 *  scheduling latency. In: 32nd Euromicro Conference on Real-Time Systems
 *  (ECRTS 2020). Schloss Dagstuhl-Leibniz-Zentrum fur Informatik, 2020.
 *
 * Copyright (C) 2021 Daniel Bristot de Oliveira, Red Hat, Inc. <[email protected]>
 */

#include <linux/kthread.h>
#include <linux/tracefs.h>
#include <linux/uaccess.h>
#include <linux/cpumask.h>
#include <linux/delay.h>
#include <linux/sched/clock.h>
#include <uapi/linux/sched/types.h>
#include <linux/sched.h>
#include "trace.h"

#ifdef CONFIG_X86_LOCAL_APIC
#include <asm/trace/irq_vectors.h>
#undef TRACE_INCLUDE_PATH
#undef TRACE_INCLUDE_FILE
#endif /* CONFIG_X86_LOCAL_APIC */

#include <trace/events/irq.h>
#include <trace/events/sched.h>

#define CREATE_TRACE_POINTS
#include <trace/events/osnoise.h>

/*
 * Default values.
 */
#define BANNER
#define DEFAULT_SAMPLE_PERIOD
#define DEFAULT_SAMPLE_RUNTIME

#define DEFAULT_TIMERLAT_PERIOD
#define DEFAULT_TIMERLAT_PRIO

/*
 * osnoise/options entries.
 */
enum osnoise_options_index {};

static const char * const osnoise_options_str[OSN_MAX] =;

#define OSN_DEFAULT_OPTIONS
static unsigned long osnoise_options	=;

/*
 * trace_array of the enabled osnoise/timerlat instances.
 */
struct osnoise_instance {};

static struct list_head osnoise_instances;

static bool osnoise_has_registered_instances(void)
{}

/*
 * osnoise_instance_registered - check if a tr is already registered
 */
static int osnoise_instance_registered(struct trace_array *tr)
{}

/*
 * osnoise_register_instance - register a new trace instance
 *
 * Register a trace_array *tr in the list of instances running
 * osnoise/timerlat tracers.
 */
static int osnoise_register_instance(struct trace_array *tr)
{}

/*
 *  osnoise_unregister_instance - unregister a registered trace instance
 *
 * Remove the trace_array *tr from the list of instances running
 * osnoise/timerlat tracers.
 */
static void osnoise_unregister_instance(struct trace_array *tr)
{}

/*
 * NMI runtime info.
 */
struct osn_nmi {};

/*
 * IRQ runtime info.
 */
struct osn_irq {};

#define IRQ_CONTEXT
#define THREAD_CONTEXT
#define THREAD_URET
/*
 * sofirq runtime info.
 */
struct osn_softirq {};

/*
 * thread runtime info.
 */
struct osn_thread {};

/*
 * Runtime information: this structure saves the runtime information used by
 * one sampling thread.
 */
struct osnoise_variables {};

/*
 * Per-cpu runtime information.
 */
static DEFINE_PER_CPU(struct osnoise_variables, per_cpu_osnoise_var);

/*
 * this_cpu_osn_var - Return the per-cpu osnoise_variables on its relative CPU
 */
static inline struct osnoise_variables *this_cpu_osn_var(void)
{}

#ifdef CONFIG_TIMERLAT_TRACER
/*
 * Runtime information for the timer mode.
 */
struct timerlat_variables {};

static DEFINE_PER_CPU(struct timerlat_variables, per_cpu_timerlat_var);

/*
 * this_cpu_tmr_var - Return the per-cpu timerlat_variables on its relative CPU
 */
static inline struct timerlat_variables *this_cpu_tmr_var(void)
{}

/*
 * tlat_var_reset - Reset the values of the given timerlat_variables
 */
static inline void tlat_var_reset(void)
{}
#else /* CONFIG_TIMERLAT_TRACER */
#define tlat_var_reset
#endif /* CONFIG_TIMERLAT_TRACER */

/*
 * osn_var_reset - Reset the values of the given osnoise_variables
 */
static inline void osn_var_reset(void)
{}

/*
 * osn_var_reset_all - Reset the value of all per-cpu osnoise_variables
 */
static inline void osn_var_reset_all(void)
{}

/*
 * Tells NMIs to call back to the osnoise tracer to record timestamps.
 */
bool trace_osnoise_callback_enabled;

/*
 * osnoise sample structure definition. Used to store the statistics of a
 * sample run.
 */
struct osnoise_sample {};

#ifdef CONFIG_TIMERLAT_TRACER
/*
 * timerlat sample structure definition. Used to store the statistics of
 * a sample run.
 */
struct timerlat_sample {};
#endif

/*
 * Protect the interface.
 */
static struct mutex interface_lock;

/*
 * Tracer data.
 */
static struct osnoise_data {} osnoise_data =;

#ifdef CONFIG_TIMERLAT_TRACER
static inline bool timerlat_enabled(void)
{}

static inline int timerlat_softirq_exit(struct osnoise_variables *osn_var)
{}

static inline int timerlat_thread_exit(struct osnoise_variables *osn_var)
{}
#else /* CONFIG_TIMERLAT_TRACER */
static inline bool timerlat_enabled(void)
{
	return false;
}

static inline int timerlat_softirq_exit(struct osnoise_variables *osn_var)
{
	return 1;
}
static inline int timerlat_thread_exit(struct osnoise_variables *osn_var)
{
	return 1;
}
#endif

#ifdef CONFIG_PREEMPT_RT
/*
 * Print the osnoise header info.
 */
static void print_osnoise_headers(struct seq_file *s)
{
	if (osnoise_data.tainted)
		seq_puts(s, "# osnoise is tainted!\n");

	seq_puts(s, "#                                _-------=> irqs-off\n");
	seq_puts(s, "#                               / _------=> need-resched\n");
	seq_puts(s, "#                              | / _-----=> need-resched-lazy\n");
	seq_puts(s, "#                              || / _----=> hardirq/softirq\n");
	seq_puts(s, "#                              ||| / _---=> preempt-depth\n");
	seq_puts(s, "#                              |||| / _--=> preempt-lazy-depth\n");
	seq_puts(s, "#                              ||||| / _-=> migrate-disable\n");

	seq_puts(s, "#                              |||||| /          ");
	seq_puts(s, "                                     MAX\n");

	seq_puts(s, "#                              ||||| /                         ");
	seq_puts(s, "                    SINGLE      Interference counters:\n");

	seq_puts(s, "#                              |||||||               RUNTIME   ");
	seq_puts(s, "   NOISE  %% OF CPU  NOISE    +-----------------------------+\n");

	seq_puts(s, "#           TASK-PID      CPU# |||||||   TIMESTAMP    IN US    ");
	seq_puts(s, "   IN US  AVAILABLE  IN US     HW    NMI    IRQ   SIRQ THREAD\n");

	seq_puts(s, "#              | |         |   |||||||      |           |      ");
	seq_puts(s, "       |    |            |      |      |      |      |      |\n");
}
#else /* CONFIG_PREEMPT_RT */
static void print_osnoise_headers(struct seq_file *s)
{}
#endif /* CONFIG_PREEMPT_RT */

/*
 * osnoise_taint - report an osnoise error.
 */
#define osnoise_taint(msg)

/*
 * Record an osnoise_sample into the tracer buffer.
 */
static void
__trace_osnoise_sample(struct osnoise_sample *sample, struct trace_buffer *buffer)
{}

/*
 * Record an osnoise_sample on all osnoise instances.
 */
static void trace_osnoise_sample(struct osnoise_sample *sample)
{}

#ifdef CONFIG_TIMERLAT_TRACER
/*
 * Print the timerlat header info.
 */
#ifdef CONFIG_PREEMPT_RT
static void print_timerlat_headers(struct seq_file *s)
{
	seq_puts(s, "#                                _-------=> irqs-off\n");
	seq_puts(s, "#                               / _------=> need-resched\n");
	seq_puts(s, "#                              | / _-----=> need-resched-lazy\n");
	seq_puts(s, "#                              || / _----=> hardirq/softirq\n");
	seq_puts(s, "#                              ||| / _---=> preempt-depth\n");
	seq_puts(s, "#                              |||| / _--=> preempt-lazy-depth\n");
	seq_puts(s, "#                              ||||| / _-=> migrate-disable\n");
	seq_puts(s, "#                              |||||| /\n");
	seq_puts(s, "#                              |||||||             ACTIVATION\n");
	seq_puts(s, "#           TASK-PID      CPU# |||||||   TIMESTAMP    ID     ");
	seq_puts(s, "       CONTEXT                LATENCY\n");
	seq_puts(s, "#              | |         |   |||||||      |         |      ");
	seq_puts(s, "            |                       |\n");
}
#else /* CONFIG_PREEMPT_RT */
static void print_timerlat_headers(struct seq_file *s)
{}
#endif /* CONFIG_PREEMPT_RT */

static void
__trace_timerlat_sample(struct timerlat_sample *sample, struct trace_buffer *buffer)
{}

/*
 * Record an timerlat_sample into the tracer buffer.
 */
static void trace_timerlat_sample(struct timerlat_sample *sample)
{}

#ifdef CONFIG_STACKTRACE

#define MAX_CALLS

/*
 * Stack trace will take place only at IRQ level, so, no need
 * to control nesting here.
 */
struct trace_stack {};

static DEFINE_PER_CPU(struct trace_stack, trace_stack);

/*
 * timerlat_save_stack - save a stack trace without printing
 *
 * Save the current stack trace without printing. The
 * stack will be printed later, after the end of the measurement.
 */
static void timerlat_save_stack(int skip)
{}

static void
__timerlat_dump_stack(struct trace_buffer *buffer, struct trace_stack *fstack, unsigned int size)
{}

/*
 * timerlat_dump_stack - dump a stack trace previously saved
 */
static void timerlat_dump_stack(u64 latency)
{}
#else /* CONFIG_STACKTRACE */
#define timerlat_dump_stack
#define timerlat_save_stack
#endif /* CONFIG_STACKTRACE */
#endif /* CONFIG_TIMERLAT_TRACER */

/*
 * Macros to encapsulate the time capturing infrastructure.
 */
#define time_get()
#define time_to_us(x)
#define time_sub(a, b)

/*
 * cond_move_irq_delta_start - Forward the delta_start of a running IRQ
 *
 * If an IRQ is preempted by an NMI, its delta_start is pushed forward
 * to discount the NMI interference.
 *
 * See get_int_safe_duration().
 */
static inline void
cond_move_irq_delta_start(struct osnoise_variables *osn_var, u64 duration)
{}

#ifndef CONFIG_PREEMPT_RT
/*
 * cond_move_softirq_delta_start - Forward the delta_start of a running softirq.
 *
 * If a softirq is preempted by an IRQ or NMI, its delta_start is pushed
 * forward to discount the interference.
 *
 * See get_int_safe_duration().
 */
static inline void
cond_move_softirq_delta_start(struct osnoise_variables *osn_var, u64 duration)
{}
#else /* CONFIG_PREEMPT_RT */
#define cond_move_softirq_delta_start
#endif

/*
 * cond_move_thread_delta_start - Forward the delta_start of a running thread
 *
 * If a noisy thread is preempted by an softirq, IRQ or NMI, its delta_start
 * is pushed forward to discount the interference.
 *
 * See get_int_safe_duration().
 */
static inline void
cond_move_thread_delta_start(struct osnoise_variables *osn_var, u64 duration)
{}

/*
 * get_int_safe_duration - Get the duration of a window
 *
 * The irq, softirq and thread varaibles need to have its duration without
 * the interference from higher priority interrupts. Instead of keeping a
 * variable to discount the interrupt interference from these variables, the
 * starting time of these variables are pushed forward with the interrupt's
 * duration. In this way, a single variable is used to:
 *
 *   - Know if a given window is being measured.
 *   - Account its duration.
 *   - Discount the interference.
 *
 * To avoid getting inconsistent values, e.g.,:
 *
 *	now = time_get()
 *		--->	interrupt!
 *			delta_start -= int duration;
 *		<---
 *	duration = now - delta_start;
 *
 *	result: negative duration if the variable duration before the
 *	interrupt was smaller than the interrupt execution.
 *
 * A counter of interrupts is used. If the counter increased, try
 * to capture an interference safe duration.
 */
static inline s64
get_int_safe_duration(struct osnoise_variables *osn_var, u64 *delta_start)
{}

/*
 *
 * set_int_safe_time - Save the current time on *time, aware of interference
 *
 * Get the time, taking into consideration a possible interference from
 * higher priority interrupts.
 *
 * See get_int_safe_duration() for an explanation.
 */
static u64
set_int_safe_time(struct osnoise_variables *osn_var, u64 *time)
{}

#ifdef CONFIG_TIMERLAT_TRACER
/*
 * copy_int_safe_time - Copy *src into *desc aware of interference
 */
static u64
copy_int_safe_time(struct osnoise_variables *osn_var, u64 *dst, u64 *src)
{}
#endif /* CONFIG_TIMERLAT_TRACER */

/*
 * trace_osnoise_callback - NMI entry/exit callback
 *
 * This function is called at the entry and exit NMI code. The bool enter
 * distinguishes between either case. This function is used to note a NMI
 * occurrence, compute the noise caused by the NMI, and to remove the noise
 * it is potentially causing on other interference variables.
 */
void trace_osnoise_callback(bool enter)
{}

/*
 * osnoise_trace_irq_entry - Note the starting of an IRQ
 *
 * Save the starting time of an IRQ. As IRQs are non-preemptive to other IRQs,
 * it is safe to use a single variable (ons_var->irq) to save the statistics.
 * The arrival_time is used to report... the arrival time. The delta_start
 * is used to compute the duration at the IRQ exit handler. See
 * cond_move_irq_delta_start().
 */
void osnoise_trace_irq_entry(int id)
{}

/*
 * osnoise_irq_exit - Note the end of an IRQ, sava data and trace
 *
 * Computes the duration of the IRQ noise, and trace it. Also discounts the
 * interference from other sources of noise could be currently being accounted.
 */
void osnoise_trace_irq_exit(int id, const char *desc)
{}

/*
 * trace_irqentry_callback - Callback to the irq:irq_entry traceevent
 *
 * Used to note the starting of an IRQ occurece.
 */
static void trace_irqentry_callback(void *data, int irq,
				    struct irqaction *action)
{}

/*
 * trace_irqexit_callback - Callback to the irq:irq_exit traceevent
 *
 * Used to note the end of an IRQ occurece.
 */
static void trace_irqexit_callback(void *data, int irq,
				   struct irqaction *action, int ret)
{}

/*
 * arch specific register function.
 */
int __weak osnoise_arch_register(void)
{}

/*
 * arch specific unregister function.
 */
void __weak osnoise_arch_unregister(void)
{}

/*
 * hook_irq_events - Hook IRQ handling events
 *
 * This function hooks the IRQ related callbacks to the respective trace
 * events.
 */
static int hook_irq_events(void)
{}

/*
 * unhook_irq_events - Unhook IRQ handling events
 *
 * This function unhooks the IRQ related callbacks to the respective trace
 * events.
 */
static void unhook_irq_events(void)
{}

#ifndef CONFIG_PREEMPT_RT
/*
 * trace_softirq_entry_callback - Note the starting of a softirq
 *
 * Save the starting time of a softirq. As softirqs are non-preemptive to
 * other softirqs, it is safe to use a single variable (ons_var->softirq)
 * to save the statistics. The arrival_time is used to report... the
 * arrival time. The delta_start is used to compute the duration at the
 * softirq exit handler. See cond_move_softirq_delta_start().
 */
static void trace_softirq_entry_callback(void *data, unsigned int vec_nr)
{}

/*
 * trace_softirq_exit_callback - Note the end of an softirq
 *
 * Computes the duration of the softirq noise, and trace it. Also discounts the
 * interference from other sources of noise could be currently being accounted.
 */
static void trace_softirq_exit_callback(void *data, unsigned int vec_nr)
{}

/*
 * hook_softirq_events - Hook softirq handling events
 *
 * This function hooks the softirq related callbacks to the respective trace
 * events.
 */
static int hook_softirq_events(void)
{}

/*
 * unhook_softirq_events - Unhook softirq handling events
 *
 * This function hooks the softirq related callbacks to the respective trace
 * events.
 */
static void unhook_softirq_events(void)
{}
#else /* CONFIG_PREEMPT_RT */
/*
 * softirq are threads on the PREEMPT_RT mode.
 */
static int hook_softirq_events(void)
{
	return 0;
}
static void unhook_softirq_events(void)
{
}
#endif

/*
 * thread_entry - Record the starting of a thread noise window
 *
 * It saves the context switch time for a noisy thread, and increments
 * the interference counters.
 */
static void
thread_entry(struct osnoise_variables *osn_var, struct task_struct *t)
{}

/*
 * thread_exit - Report the end of a thread noise window
 *
 * It computes the total noise from a thread, tracing if needed.
 */
static void
thread_exit(struct osnoise_variables *osn_var, struct task_struct *t)
{}

#ifdef CONFIG_TIMERLAT_TRACER
/*
 * osnoise_stop_exception - Stop tracing and the tracer.
 */
static __always_inline void osnoise_stop_exception(char *msg, int cpu)
{}

/*
 * trace_sched_migrate_callback - sched:sched_migrate_task trace event handler
 *
 * his function is hooked to the sched:sched_migrate_task trace event, and monitors
 * timerlat user-space thread migration.
 */
static void trace_sched_migrate_callback(void *data, struct task_struct *p, int dest_cpu)
{}

static int register_migration_monitor(void)
{}

static void unregister_migration_monitor(void)
{}
#else
static int register_migration_monitor(void)
{
	return 0;
}
static void unregister_migration_monitor(void) {}
#endif
/*
 * trace_sched_switch - sched:sched_switch trace event handler
 *
 * This function is hooked to the sched:sched_switch trace event, and it is
 * used to record the beginning and to report the end of a thread noise window.
 */
static void
trace_sched_switch_callback(void *data, bool preempt,
			    struct task_struct *p,
			    struct task_struct *n,
			    unsigned int prev_state)
{}

/*
 * hook_thread_events - Hook the instrumentation for thread noise
 *
 * Hook the osnoise tracer callbacks to handle the noise from other
 * threads on the necessary kernel events.
 */
static int hook_thread_events(void)
{}

/*
 * unhook_thread_events - unhook the instrumentation for thread noise
 *
 * Unook the osnoise tracer callbacks to handle the noise from other
 * threads on the necessary kernel events.
 */
static void unhook_thread_events(void)
{}

/*
 * save_osn_sample_stats - Save the osnoise_sample statistics
 *
 * Save the osnoise_sample statistics before the sampling phase. These
 * values will be used later to compute the diff betwneen the statistics
 * before and after the osnoise sampling.
 */
static void
save_osn_sample_stats(struct osnoise_variables *osn_var, struct osnoise_sample *s)
{}

/*
 * diff_osn_sample_stats - Compute the osnoise_sample statistics
 *
 * After a sample period, compute the difference on the osnoise_sample
 * statistics. The struct osnoise_sample *s contains the statistics saved via
 * save_osn_sample_stats() before the osnoise sampling.
 */
static void
diff_osn_sample_stats(struct osnoise_variables *osn_var, struct osnoise_sample *s)
{}

/*
 * osnoise_stop_tracing - Stop tracing and the tracer.
 */
static __always_inline void osnoise_stop_tracing(void)
{}

/*
 * osnoise_has_tracing_on - Check if there is at least one instance on
 */
static __always_inline int osnoise_has_tracing_on(void)
{}

/*
 * notify_new_max_latency - Notify a new max latency via fsnotify interface.
 */
static void notify_new_max_latency(u64 latency)
{}

/*
 * run_osnoise - Sample the time and look for osnoise
 *
 * Used to capture the time, looking for potential osnoise latency repeatedly.
 * Different from hwlat_detector, it is called with preemption and interrupts
 * enabled. This allows irqs, softirqs and threads to run, interfering on the
 * osnoise sampling thread, as they would do with a regular thread.
 */
static int run_osnoise(void)
{}

static struct cpumask osnoise_cpumask;
static struct cpumask save_cpumask;

/*
 * osnoise_sleep - sleep until the next period
 */
static void osnoise_sleep(bool skip_period)
{}

/*
 * osnoise_migration_pending - checks if the task needs to migrate
 *
 * osnoise/timerlat threads are per-cpu. If there is a pending request to
 * migrate the thread away from the current CPU, something bad has happened.
 * Play the good citizen and leave.
 *
 * Returns 0 if it is safe to continue, 1 otherwise.
 */
static inline int osnoise_migration_pending(void)
{}

/*
 * osnoise_main - The osnoise detection kernel thread
 *
 * Calls run_osnoise() function to measure the osnoise for the configured runtime,
 * every period.
 */
static int osnoise_main(void *data)
{}

#ifdef CONFIG_TIMERLAT_TRACER
/*
 * timerlat_irq - hrtimer handler for timerlat.
 */
static enum hrtimer_restart timerlat_irq(struct hrtimer *timer)
{}

/*
 * wait_next_period - Wait for the next period for timerlat
 */
static int wait_next_period(struct timerlat_variables *tlat)
{}

/*
 * timerlat_main- Timerlat main
 */
static int timerlat_main(void *data)
{}
#else /* CONFIG_TIMERLAT_TRACER */
static int timerlat_main(void *data)
{
	return 0;
}
#endif /* CONFIG_TIMERLAT_TRACER */

/*
 * stop_kthread - stop a workload thread
 */
static void stop_kthread(unsigned int cpu)
{}

/*
 * stop_per_cpu_kthread - Stop per-cpu threads
 *
 * Stop the osnoise sampling htread. Use this on unload and at system
 * shutdown.
 */
static void stop_per_cpu_kthreads(void)
{}

/*
 * start_kthread - Start a workload tread
 */
static int start_kthread(unsigned int cpu)
{}

/*
 * start_per_cpu_kthread - Kick off per-cpu osnoise sampling kthreads
 *
 * This starts the kernel thread that will look for osnoise on many
 * cpus.
 */
static int start_per_cpu_kthreads(void)
{}

#ifdef CONFIG_HOTPLUG_CPU
static void osnoise_hotplug_workfn(struct work_struct *dummy)
{}

static DECLARE_WORK(osnoise_hotplug_work, osnoise_hotplug_workfn);

/*
 * osnoise_cpu_init - CPU hotplug online callback function
 */
static int osnoise_cpu_init(unsigned int cpu)
{}

/*
 * osnoise_cpu_die - CPU hotplug offline callback function
 */
static int osnoise_cpu_die(unsigned int cpu)
{}

static void osnoise_init_hotplug_support(void)
{}
#else /* CONFIG_HOTPLUG_CPU */
static void osnoise_init_hotplug_support(void)
{
	return;
}
#endif /* CONFIG_HOTPLUG_CPU */

/*
 * seq file functions for the osnoise/options file.
 */
static void *s_options_start(struct seq_file *s, loff_t *pos)
{}

static void *s_options_next(struct seq_file *s, void *v, loff_t *pos)
{}

static int s_options_show(struct seq_file *s, void *v)
{}

static void s_options_stop(struct seq_file *s, void *v)
{}

static const struct seq_operations osnoise_options_seq_ops =;

static int osnoise_options_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &osnoise_options_seq_ops);
};

/**
 * osnoise_options_write - Write function for "options" entry
 * @filp: The active open file structure
 * @ubuf: The user buffer that contains the value to write
 * @cnt: The maximum number of bytes to write to "file"
 * @ppos: The current position in @file
 *
 * Writing the option name sets the option, writing the "NO_"
 * prefix in front of the option name disables it.
 *
 * Writing "DEFAULTS" resets the option values to the default ones.
 */
static ssize_t osnoise_options_write(struct file *filp, const char __user *ubuf,
				     size_t cnt, loff_t *ppos)
{}

/*
 * osnoise_cpus_read - Read function for reading the "cpus" file
 * @filp: The active open file structure
 * @ubuf: The userspace provided buffer to read value into
 * @cnt: The maximum number of bytes to read
 * @ppos: The current "file" position
 *
 * Prints the "cpus" output into the user-provided buffer.
 */
static ssize_t
osnoise_cpus_read(struct file *filp, char __user *ubuf, size_t count,
		  loff_t *ppos)
{}

/*
 * osnoise_cpus_write - Write function for "cpus" entry
 * @filp: The active open file structure
 * @ubuf: The user buffer that contains the value to write
 * @cnt: The maximum number of bytes to write to "file"
 * @ppos: The current position in @file
 *
 * This function provides a write implementation for the "cpus"
 * interface to the osnoise trace. By default, it lists all  CPUs,
 * in this way, allowing osnoise threads to run on any online CPU
 * of the system. It serves to restrict the execution of osnoise to the
 * set of CPUs writing via this interface. Why not use "tracing_cpumask"?
 * Because the user might be interested in tracing what is running on
 * other CPUs. For instance, one might run osnoise in one HT CPU
 * while observing what is running on the sibling HT CPU.
 */
static ssize_t
osnoise_cpus_write(struct file *filp, const char __user *ubuf, size_t count,
		   loff_t *ppos)
{}

#ifdef CONFIG_TIMERLAT_TRACER
static int timerlat_fd_open(struct inode *inode, struct file *file)
{
	struct osnoise_variables *osn_var;
	struct timerlat_variables *tlat;
	long cpu = (long) inode->i_cdev;

	mutex_lock(&interface_lock);

	/*
	 * This file is accessible only if timerlat is enabled, and
	 * NO_OSNOISE_WORKLOAD is set.
	 */
	if (!timerlat_enabled() || test_bit(OSN_WORKLOAD, &osnoise_options)) {
		mutex_unlock(&interface_lock);
		return -EINVAL;
	}

	migrate_disable();

	osn_var = this_cpu_osn_var();

	/*
	 * The osn_var->pid holds the single access to this file.
	 */
	if (osn_var->pid) {
		mutex_unlock(&interface_lock);
		migrate_enable();
		return -EBUSY;
	}

	/*
	 * timerlat tracer is a per-cpu tracer. Check if the user-space too
	 * is pinned to a single CPU. The tracer laters monitor if the task
	 * migrates and then disables tracer if it does. However, it is
	 * worth doing this basic acceptance test to avoid obviusly wrong
	 * setup.
	 */
	if (current->nr_cpus_allowed > 1 ||  cpu != smp_processor_id()) {
		mutex_unlock(&interface_lock);
		migrate_enable();
		return -EPERM;
	}

	/*
	 * From now on, it is good to go.
	 */
	file->private_data = inode->i_cdev;

	get_task_struct(current);

	osn_var->kthread = current;
	osn_var->pid = current->pid;

	/*
	 * Setup is done.
	 */
	mutex_unlock(&interface_lock);

	tlat = this_cpu_tmr_var();
	tlat->count = 0;

	hrtimer_init(&tlat->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED_HARD);
	tlat->timer.function = timerlat_irq;

	migrate_enable();
	return 0;
};

/*
 * timerlat_fd_read - Read function for "timerlat_fd" file
 * @file: The active open file structure
 * @ubuf: The userspace provided buffer to read value into
 * @cnt: The maximum number of bytes to read
 * @ppos: The current "file" position
 *
 * Prints 1 on timerlat, the number of interferences on osnoise, -1 on error.
 */
static ssize_t
timerlat_fd_read(struct file *file, char __user *ubuf, size_t count,
		  loff_t *ppos)
{}

static int timerlat_fd_release(struct inode *inode, struct file *file)
{}
#endif

/*
 * osnoise/runtime_us: cannot be greater than the period.
 */
static struct trace_min_max_param osnoise_runtime =;

/*
 * osnoise/period_us: cannot be smaller than the runtime.
 */
static struct trace_min_max_param osnoise_period =;

/*
 * osnoise/stop_tracing_us: no limit.
 */
static struct trace_min_max_param osnoise_stop_tracing_in =;

/*
 * osnoise/stop_tracing_total_us: no limit.
 */
static struct trace_min_max_param osnoise_stop_tracing_total =;

#ifdef CONFIG_TIMERLAT_TRACER
/*
 * osnoise/print_stack: print the stacktrace of the IRQ handler if the total
 * latency is higher than val.
 */
static struct trace_min_max_param osnoise_print_stack =;

/*
 * osnoise/timerlat_period: min 100 us, max 1 s
 */
static u64 timerlat_min_period =;
static u64 timerlat_max_period =;
static struct trace_min_max_param timerlat_period =;

static const struct file_operations timerlat_fd_fops =;
#endif

static const struct file_operations cpus_fops =;

static const struct file_operations osnoise_options_fops =;

#ifdef CONFIG_TIMERLAT_TRACER
#ifdef CONFIG_STACKTRACE
static int init_timerlat_stack_tracefs(struct dentry *top_dir)
{}
#else /* CONFIG_STACKTRACE */
static int init_timerlat_stack_tracefs(struct dentry *top_dir)
{
	return 0;
}
#endif /* CONFIG_STACKTRACE */

static int osnoise_create_cpu_timerlat_fd(struct dentry *top_dir)
{}

/*
 * init_timerlat_tracefs - A function to initialize the timerlat interface files
 */
static int init_timerlat_tracefs(struct dentry *top_dir)
{}
#else /* CONFIG_TIMERLAT_TRACER */
static int init_timerlat_tracefs(struct dentry *top_dir)
{
	return 0;
}
#endif /* CONFIG_TIMERLAT_TRACER */

/*
 * init_tracefs - A function to initialize the tracefs interface files
 *
 * This function creates entries in tracefs for "osnoise" and "timerlat".
 * It creates these directories in the tracing directory, and within that
 * directory the use can change and view the configs.
 */
static int init_tracefs(void)
{}

static int osnoise_hook_events(void)
{}

static void osnoise_unhook_events(void)
{}

/*
 * osnoise_workload_start - start the workload and hook to events
 */
static int osnoise_workload_start(void)
{}

/*
 * osnoise_workload_stop - stop the workload and unhook the events
 */
static void osnoise_workload_stop(void)
{}

static void osnoise_tracer_start(struct trace_array *tr)
{}

static void osnoise_tracer_stop(struct trace_array *tr)
{}

static int osnoise_tracer_init(struct trace_array *tr)
{}

static void osnoise_tracer_reset(struct trace_array *tr)
{}

static struct tracer osnoise_tracer __read_mostly =;

#ifdef CONFIG_TIMERLAT_TRACER
static void timerlat_tracer_start(struct trace_array *tr)
{}

static void timerlat_tracer_stop(struct trace_array *tr)
{}

static int timerlat_tracer_init(struct trace_array *tr)
{}

static void timerlat_tracer_reset(struct trace_array *tr)
{}

static struct tracer timerlat_tracer __read_mostly =;

__init static int init_timerlat_tracer(void)
{}
#else /* CONFIG_TIMERLAT_TRACER */
__init static int init_timerlat_tracer(void)
{
	return 0;
}
#endif /* CONFIG_TIMERLAT_TRACER */

__init static int init_osnoise_tracer(void)
{}
late_initcall(init_osnoise_tracer);