/* SPDX-License-Identifier: GPL-2.0 */
#pragma once

#include <getopt.h>
#include "actions.h"
#include "timerlat_u.h"
#include "trace.h"
#include "utils.h"

/*
 * osnoise_context - read, store, write, restore osnoise configs.
 */
struct osnoise_context {
	int			flags;
	int			ref;

	char			*curr_cpus;
	char			*orig_cpus;

	/* 0 as init value */
	unsigned long long	orig_runtime_us;
	unsigned long long	runtime_us;

	/* 0 as init value */
	unsigned long long	orig_period_us;
	unsigned long long	period_us;

	/* 0 as init value */
	long long		orig_timerlat_period_us;
	long long		timerlat_period_us;

	/* 0 as init value */
	long long		orig_tracing_thresh;
	long long		tracing_thresh;

	/* -1 as init value because 0 is disabled */
	long long		orig_stop_us;
	long long		stop_us;

	/* -1 as init value because 0 is disabled */
	long long		orig_stop_total_us;
	long long		stop_total_us;

	/* -1 as init value because 0 is disabled */
	long long		orig_print_stack;
	long long		print_stack;

	/* -1 as init value because 0 is off */
	int			orig_opt_irq_disable;
	int			opt_irq_disable;

	/* -1 as init value because 0 is off */
	int			orig_opt_workload;
	int			opt_workload;
};

extern struct trace_instance *trace_inst;
extern volatile int stop_tracing;

struct hist_params {
	char			no_irq;
	char			no_thread;
	char			no_header;
	char			no_summary;
	char			no_index;
	char			with_zeros;
	int			bucket_size;
	int			entries;
};

/*
 * common_params - Parameters shared between timerlat_params and osnoise_params
 */
struct common_params {
	/* trace configuration */
	char			*cpus;
	cpu_set_t		monitored_cpus;
	struct trace_events	*events;
	int			buffer_size;

	/* Timing parameters */
	int			warmup;
	long long		stop_us;
	long long		stop_total_us;
	int			sleep_time;
	int			duration;

	/* Scheduling parameters */
	int			set_sched;
	struct sched_attr	sched_param;
	int			cgroup;
	char			*cgroup_name;
	int			hk_cpus;
	cpu_set_t		hk_cpu_set;

	/* Other parameters */
	struct hist_params	hist;
	int			output_divisor;
	int			pretty_output;
	int			quiet;
	int			user_workload;
	int			kernel_workload;
	int			user_data;
	int			aa_only;

	struct actions		threshold_actions;
	struct actions		end_actions;
	struct timerlat_u_params user;
};

extern int nr_cpus;

#define for_each_monitored_cpu(cpu, common) \
	for (cpu = 0; cpu < nr_cpus; cpu++) \
		if (!(common)->cpus || CPU_ISSET(cpu, &(common)->monitored_cpus))

struct tool_ops;

/*
 * osnoise_tool -  osnoise based tool definition.
 *
 * Only the "trace" and "context" fields are used for
 * the additional trace instances (record and aa).
 */
struct osnoise_tool {
	struct tool_ops			*ops;
	struct trace_instance		trace;
	struct osnoise_context		*context;
	void				*data;
	struct common_params		*params;
	time_t				start_time;
	struct osnoise_tool		*record;
	struct osnoise_tool		*aa;
};

struct tool_ops {
	const char *tracer;
	const char *comm_prefix;
	struct common_params *(*parse_args)(int argc, char *argv[]);
	struct osnoise_tool *(*init_tool)(struct common_params *params);
	int (*apply_config)(struct osnoise_tool *tool);
	int (*enable)(struct osnoise_tool *tool);
	int (*main)(struct osnoise_tool *tool);
	void (*print_stats)(struct osnoise_tool *tool);
	void (*analyze)(struct osnoise_tool *tool, bool stopped);
	void (*free)(struct osnoise_tool *tool);
};

/**
 * should_continue_tracing - check if tracing should continue after threshold
 * @params: pointer to the common parameters structure
 *
 * Returns true if the continue action was configured (--on-threshold continue),
 * indicating that tracing should be restarted after handling the threshold event.
 *
 * Return: 1 if tracing should continue, 0 otherwise.
 */
static inline int
should_continue_tracing(const struct common_params *params)
{
	return params->threshold_actions.continue_flag;
}

int
common_threshold_handler(const struct osnoise_tool *tool);

int osnoise_set_cpus(struct osnoise_context *context, char *cpus);
void osnoise_restore_cpus(struct osnoise_context *context);

int osnoise_set_workload(struct osnoise_context *context, bool onoff);

void osnoise_destroy_tool(struct osnoise_tool *top);
struct osnoise_tool *osnoise_init_tool(char *tool_name);
struct osnoise_tool *osnoise_init_trace_tool(const char *tracer);
bool osnoise_trace_is_off(struct osnoise_tool *tool, struct osnoise_tool *record);
int osnoise_set_stop_us(struct osnoise_context *context, long long stop_us);
int osnoise_set_stop_total_us(struct osnoise_context *context,
			      long long stop_total_us);

int getopt_auto(int argc, char **argv, const struct option *long_opts);

#define COMMON_OPTIONS \
	{"cpus",                required_argument,      0, 'c'},\
	{"cgroup",              optional_argument,      0, 'C'},\
	{"debug",               no_argument,            0, 'D'},\
	{"duration",            required_argument,      0, 'd'},\
	{"event",               required_argument,      0, 'e'},\
	{"house-keeping",       required_argument,      0, 'H'},\
	{"priority",            required_argument,      0, 'P'}
int set_common_option(int c, int argc, char **argv, struct common_params *common);

int common_apply_config(struct osnoise_tool *tool, struct common_params *params);
int top_main_loop(struct osnoise_tool *tool);
int hist_main_loop(struct osnoise_tool *tool);
int osn_set_stop(struct osnoise_tool *tool);

void common_usage(const char *tool, const char *mode,
		  const char *desc, const char * const *start_msgs, const char * const *opt_msgs);
