From dcc52a06270c7d0fba4f70406aa86f782a7a667e Mon Sep 17 00:00:00 2001 From: Alexander Aksenov Date: Fri, 12 Jul 2013 18:29:55 +0400 Subject: [PATCH] [FEATURE] SWAP Sampler port to kernel swap It works, but is not bound with other modules --- sampler/Kbuild | 4 + sampler/Makefile.am | 23 ++++ sampler/kernel_operations.h | 12 ++ sampler/swap_sampler_errors.h | 4 + sampler/swap_sampler_module.c | 258 ++++++++++++++++++++++++++++++++++++++++++ sampler/swap_sampler_module.h | 7 ++ 6 files changed, 308 insertions(+) create mode 100644 sampler/Kbuild create mode 100644 sampler/Makefile.am create mode 100644 sampler/kernel_operations.h create mode 100644 sampler/swap_sampler_errors.h create mode 100644 sampler/swap_sampler_module.c create mode 100644 sampler/swap_sampler_module.h diff --git a/sampler/Kbuild b/sampler/Kbuild new file mode 100644 index 0000000..2200ea9 --- /dev/null +++ b/sampler/Kbuild @@ -0,0 +1,4 @@ +EXTRA_CFLAGS := $(extra_cflags) + +obj-m := swap_sampler.o +swap_sampler-y := swap_sampler_module.o diff --git a/sampler/Makefile.am b/sampler/Makefile.am new file mode 100644 index 0000000..950f6a5 --- /dev/null +++ b/sampler/Makefile.am @@ -0,0 +1,23 @@ +board_opt = -DBOARD_@BOARD@ +target_kernel_src = @KERNEL@ +target_arch = @ARCH@ +module_dir = $(realpath $(top_srcdir)/src/modules/sampler) +module_name = swap_sampler +cross_compiler = $(subst gcc,,$(CC)) + +#inlude_opt = -I$(realpath $(top_srcdir)/src/modules/) +extra_cflags = "$(inlude_opt) $(board_opt)" + +all-local: + $(MAKE) CROSS_COMPILE=$(cross_compiler) ARCH=$(target_arch) extra_cflags=$(extra_cflags) \ + $(AM_MAKEFLAGS) -C $(target_kernel_src) M=$(module_dir) modules + + echo "generate data for version patching <$(OBJDUMP)><$(READELF)>" + PATH=$(PATH) $(top_srcdir)/src/modules/driver/patchko.sh -g $(module_dir)/$(module_name).ko $(OBJDUMP) $(READELF) + +clean-local: + $(MAKE) CROSS_COMPILE=$(cross_compiler) ARCH=$(target_arch) $(AM_MAKEFLAGS) -C $(target_kernel_src) M=$(module_dir) clean + +install-exec-local: + install -m 644 $(module_dir)/$(module_name).ko $(prefix) + install -m 644 $(module_dir)/$(module_name).ko.addr $(prefix) diff --git a/sampler/kernel_operations.h b/sampler/kernel_operations.h new file mode 100644 index 0000000..5170d36 --- /dev/null +++ b/sampler/kernel_operations.h @@ -0,0 +1,12 @@ +#include + +#define print_debug(msg, args...) \ + printk(KERN_DEBUG "SWAP_SAMPLER DEBUG : " msg, ##args) +#define print_msg(msg, args...) \ + printk(KERN_INFO "SWAP_SAMPLER : " msg, ##args) +#define print_warn(msg, args...) \ + printk(KERN_WARNING "SWAP_SAMPLER WARNING : " msg, ##args) +#define print_err(msg, args...) \ + printk(KERN_ERR "SWAP_SAMPLER ERROR : " msg, ##args) +#define print_crit(msg, args...) \ + printk(KERN_CRIT "SWAP_SAMPLER CRITICAL : " msg, ##args) diff --git a/sampler/swap_sampler_errors.h b/sampler/swap_sampler_errors.h new file mode 100644 index 0000000..f387af5 --- /dev/null +++ b/sampler/swap_sampler_errors.h @@ -0,0 +1,4 @@ +enum _swap_sampler_errors { + E_SS_SUCCESS = 0, /* Success */ + E_SS_WRONG_QUANTUM = 1 /* Wrong timer quantum set */ +}; diff --git a/sampler/swap_sampler_module.c b/sampler/swap_sampler_module.c new file mode 100644 index 0000000..3a7d098 --- /dev/null +++ b/sampler/swap_sampler_module.c @@ -0,0 +1,258 @@ + +/* + * Sampling implementation for SWAP + * Two approach: timer-based and event-based on counters callbacks + * + * NOTE: +* 1. timer-based approach uses high resolution timers if its available + * 2. event-based approach that uses counters overflow callbacks doesn't work + * on some hardware; it requires PMU functionality for work + * + * Written by Andreev S.V., 2012 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "swap_sampler_module.h" +#include "swap_sampler_errors.h" +#include "kernel_operations.h" + +unsigned int dbi_timer_quantum = 0; + +#ifdef CONFIG_HIGH_RES_TIMERS +static DEFINE_PER_CPU(struct hrtimer, dbi_hrtimer); +static int dbi_hrtimer_running; +#else +//struct timer_list dbi_timer; +static DEFINE_PER_CPU(struct timer_list, dbi_timer); +static int dbi_timer_running; +#endif + +static BLOCKING_NOTIFIER_HEAD(swap_sampler_notifier_list); + + +#ifdef CONFIG_HIGH_RES_TIMERS +static enum hrtimer_restart dbi_hrtimer_notify(struct hrtimer *hrtimer) +{ +#ifdef CONFIG_ARM + print_debug("lr : 0x%x, pc : 0x%x\n", (task_pt_regs(current))->ARM_lr, + (task_pt_regs(current))->ARM_pc); +#elif CONFIG_X86 + print_debug("lr : 0x%x, pc : 0x%x\n", (task_pt_regs(current))->sp, + (task_pt_regs(current))->bp); +#endif /* CONFIG_arch */ + + hrtimer_forward_now(hrtimer, ns_to_ktime(dbi_timer_quantum)); + return HRTIMER_RESTART; +} + +static void __dbi_hrtimer_start(void *unused) +{ + struct hrtimer *hrtimer = &__get_cpu_var(dbi_hrtimer); + + if (!dbi_hrtimer_running) + return; + hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hrtimer->function = dbi_hrtimer_notify; + hrtimer_start(hrtimer, ns_to_ktime(dbi_timer_quantum), HRTIMER_MODE_REL_PINNED); +} + +static int dbi_hrtimer_start(void) +{ + get_online_cpus(); + dbi_hrtimer_running = 1; + on_each_cpu(__dbi_hrtimer_start, NULL, 1); + put_online_cpus(); + + return E_SS_SUCCESS; +} + +static void __dbi_hrtimer_stop(int cpu) +{ + struct hrtimer *hrtimer = &per_cpu(dbi_hrtimer, cpu); + + if (!dbi_hrtimer_running) + return; + hrtimer_cancel(hrtimer); +} + +static void dbi_hrtimer_stop(void) +{ + int cpu; + + get_online_cpus(); + for_each_online_cpu(cpu) + __dbi_hrtimer_stop(cpu); + dbi_hrtimer_running = 0; + put_online_cpus(); +} + +#else + +void dbi_write_sample_data(unsigned long data) +{ + struct timer_list *timer = (struct timer_list *)data; + +#ifdef CONFIG_ARM + print_debug("lr : 0x%x, pc : 0x%x\n", (task_pt_regs(current))->ARM_lr, + (task_pt_regs(current))->ARM_pc); +#elif CONFIG_X86 + print_debug("lr : 0x%x, pc : 0x%x\n", (task_pt_regs(current))->sp, + (task_pt_regs(current))->bp); +#endif /* CONFIG_arch */ + + // TODO: test pinning + mod_timer_pinned(timer, jiffies + dbi_timer_quantum); +} + +static void __dbi_timer_start(void *unused) +{ + struct timer_list *timer = &__get_cpu_var(dbi_timer); + + if (!dbi_timer_running) + return; + init_timer(timer); + timer->data = timer; + timer->function = dbi_write_sample_data; + // TODO: test pinning + mod_timer_pinned(timer, jiffies + dbi_timer_quantum); +} + +static int dbi_timer_start(void) +{ + get_online_cpus(); + dbi_timer_running = 1; + on_each_cpu(__dbi_timer_start, NULL, 1); + put_online_cpus(); + return E_SS_SUCCESS; +} + +static void __dbi_timer_stop(int cpu) +{ + struct timer_list *timer = &per_cpu(dbi_timer, cpu); + + if (!dbi_timer_running) + return; + del_timer_sync(timer); +} + +static void dbi_timer_stop(void) +{ + int cpu; + + get_online_cpus(); + for_each_online_cpu(cpu) + __dbi_timer_stop(cpu); + dbi_timer_running = 0; + put_online_cpus(); +} + +#endif + +static int __cpuinit dbi_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + long cpu = (long) hcpu; + + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: +#ifdef CONFIG_HIGH_RES_TIMERS + smp_call_function_single(cpu, __dbi_hrtimer_start, NULL, 1); +#else + smp_call_function_single(cpu, __dbi_timer_start, NULL, 1); +#endif + break; + case CPU_DEAD: + case CPU_DEAD_FROZEN: +#ifdef CONFIG_HIGH_RES_TIMERS + __dbi_hrtimer_stop(cpu); +#else + __dbi_timer_stop(cpu); +#endif + break; + } + return NOTIFY_OK; +} + +static struct notifier_block __refdata dbi_cpu_notifier = { + .notifier_call = dbi_cpu_notify, +}; + +int swap_sampler_start(unsigned int timer_quantum) +{ + if (timer_quantum <= 0) + return -E_SS_WRONG_QUANTUM; + + dbi_timer_quantum = timer_quantum; + + if (!try_module_get(THIS_MODULE)) + print_err("Error of try_module_get() for sampling module\n"); + +#ifdef CONFIG_HIGH_RES_TIMERS + dbi_hrtimer_start(); +#else + dbi_timer_start(); +#endif + + return E_SS_SUCCESS; +} + +int swap_sampler_stop(void) +{ +#ifdef CONFIG_HIGH_RES_TIMERS + dbi_hrtimer_stop(); +#else + dbi_timer_stop(); +#endif + module_put(THIS_MODULE); + + return E_SS_SUCCESS; +} + +static int __init sampler_init(void) +{ + int retval; + + retval = register_hotcpu_notifier(&dbi_cpu_notifier); + if (retval) { + print_err("Error of register_hotcpu_notifier()\n"); + return retval; + } + + print_msg("Sample ininitialization success\n"); + + return E_SS_SUCCESS; +} + +static void __exit sampler_exit(void) +{ + unregister_hotcpu_notifier(&dbi_cpu_notifier); + + swap_sampler_stop(); + + print_msg("Sampler uninitialized\n"); +} + +module_init(sampler_init); +module_exit(sampler_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SWAP sampling module"); +MODULE_AUTHOR("Andreev S.V., Aksenov A.S."); diff --git a/sampler/swap_sampler_module.h b/sampler/swap_sampler_module.h new file mode 100644 index 0000000..c534102 --- /dev/null +++ b/sampler/swap_sampler_module.h @@ -0,0 +1,7 @@ +/* SWAP Sampler interface */ + +/* Starts the SWAP Sampler */ +int swap_sampler_start(unsigned int timer_quantum); + +/* Stops the SWAP Sampler */ +int swap_sampler_stop(void); -- 2.7.4