aboutsummaryrefslogtreecommitdiff
path: root/drivers/gator/gator_events_meminfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gator/gator_events_meminfo.c')
-rw-r--r--drivers/gator/gator_events_meminfo.c197
1 files changed, 129 insertions, 68 deletions
diff --git a/drivers/gator/gator_events_meminfo.c b/drivers/gator/gator_events_meminfo.c
index c633dfdce306..c625ac5af9cd 100644
--- a/drivers/gator/gator_events_meminfo.c
+++ b/drivers/gator/gator_events_meminfo.c
@@ -16,6 +16,8 @@
#include <linux/workqueue.h>
#include <trace/events/kmem.h>
+#define USE_THREAD defined(CONFIG_PREEMPT_RT_FULL)
+
enum {
MEMINFO_MEMFREE,
MEMINFO_MEMUSED,
@@ -48,7 +50,7 @@ static bool meminfo_global_enabled;
static ulong meminfo_enabled[MEMINFO_TOTAL];
static ulong meminfo_keys[MEMINFO_TOTAL];
static long long meminfo_buffer[2 * (MEMINFO_TOTAL + 2)];
-static int meminfo_length = 0;
+static int meminfo_length;
static bool new_data_avail;
static bool proc_global_enabled;
@@ -56,22 +58,44 @@ static ulong proc_enabled[PROC_COUNT];
static ulong proc_keys[PROC_COUNT];
static DEFINE_PER_CPU(long long, proc_buffer[2 * (PROC_COUNT + 3)]);
+#if USE_THREAD
+
static int gator_meminfo_func(void *data);
static bool gator_meminfo_run;
-// Initialize semaphore unlocked to initialize memory values
+/* Initialize semaphore unlocked to initialize memory values */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
static DECLARE_MUTEX(gator_meminfo_sem);
#else
static DEFINE_SEMAPHORE(gator_meminfo_sem);
#endif
+static void notify(void)
+{
+ up(&gator_meminfo_sem);
+}
+
+#else
+
+static unsigned int mem_event;
+static void wq_sched_handler(struct work_struct *wsptr);
+DECLARE_WORK(work, wq_sched_handler);
+static struct timer_list meminfo_wake_up_timer;
+static void meminfo_wake_up_handler(unsigned long unused_data);
+
+static void notify(void)
+{
+ mem_event++;
+}
+
+#endif
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
GATOR_DEFINE_PROBE(mm_page_free_direct, TP_PROTO(struct page *page, unsigned int order))
#else
GATOR_DEFINE_PROBE(mm_page_free, TP_PROTO(struct page *page, unsigned int order))
#endif
{
- up(&gator_meminfo_sem);
+ notify();
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
@@ -80,12 +104,12 @@ GATOR_DEFINE_PROBE(mm_pagevec_free, TP_PROTO(struct page *page, int cold))
GATOR_DEFINE_PROBE(mm_page_free_batched, TP_PROTO(struct page *page, int cold))
#endif
{
- up(&gator_meminfo_sem);
+ notify();
}
GATOR_DEFINE_PROBE(mm_page_alloc, TP_PROTO(struct page *page, unsigned int order, gfp_t gfp_flags, int migratetype))
{
- up(&gator_meminfo_sem);
+ notify();
}
static int gator_events_meminfo_create_files(struct super_block *sb, struct dentry *root)
@@ -95,18 +119,16 @@ static int gator_events_meminfo_create_files(struct super_block *sb, struct dent
for (i = 0; i < MEMINFO_TOTAL; i++) {
dir = gatorfs_mkdir(sb, root, meminfo_names[i]);
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &meminfo_enabled[i]);
gatorfs_create_ro_ulong(sb, dir, "key", &meminfo_keys[i]);
}
for (i = 0; i < PROC_COUNT; ++i) {
dir = gatorfs_mkdir(sb, root, proc_names[i]);
- if (!dir) {
+ if (!dir)
return -1;
- }
gatorfs_create_ulong(sb, dir, "enabled", &proc_enabled[i]);
gatorfs_create_ro_ulong(sb, dir, "key", &proc_keys[i]);
}
@@ -134,9 +156,8 @@ static int gator_events_meminfo_start(void)
break;
}
}
- if (meminfo_enabled[MEMINFO_MEMUSED]) {
+ if (meminfo_enabled[MEMINFO_MEMUSED])
proc_global_enabled = 1;
- }
if (meminfo_global_enabled == 0)
return 0;
@@ -156,16 +177,22 @@ static int gator_events_meminfo_start(void)
if (GATOR_REGISTER_TRACE(mm_page_alloc))
goto mm_page_alloc_exit;
- // Start worker thread
+#if USE_THREAD
+ /* Start worker thread */
gator_meminfo_run = true;
- // Since the mutex starts unlocked, memory values will be initialized
+ /* Since the mutex starts unlocked, memory values will be initialized */
if (IS_ERR(kthread_run(gator_meminfo_func, NULL, "gator_meminfo")))
goto kthread_run_exit;
+#else
+ setup_timer(&meminfo_wake_up_timer, meminfo_wake_up_handler, 0);
+#endif
return 0;
+#if USE_THREAD
kthread_run_exit:
GATOR_UNREGISTER_TRACE(mm_page_alloc);
+#endif
mm_page_alloc_exit:
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
GATOR_UNREGISTER_TRACE(mm_pagevec_free);
@@ -194,75 +221,111 @@ static void gator_events_meminfo_stop(void)
#endif
GATOR_UNREGISTER_TRACE(mm_page_alloc);
- // Stop worker thread
+#if USE_THREAD
+ /* Stop worker thread */
gator_meminfo_run = false;
up(&gator_meminfo_sem);
+#else
+ del_timer_sync(&meminfo_wake_up_timer);
+#endif
}
}
-// Must be run in process context as the kernel function si_meminfo() can sleep
-static int gator_meminfo_func(void *data)
+static void do_read(void)
{
struct sysinfo info;
int i, len;
unsigned long long value;
- for (;;) {
- if (down_killable(&gator_meminfo_sem)) {
- break;
+ meminfo_length = len = 0;
+
+ si_meminfo(&info);
+ for (i = 0; i < MEMINFO_TOTAL; i++) {
+ if (meminfo_enabled[i]) {
+ switch (i) {
+ case MEMINFO_MEMFREE:
+ value = info.freeram * PAGE_SIZE;
+ break;
+ case MEMINFO_MEMUSED:
+ /* pid -1 means system wide */
+ meminfo_buffer[len++] = 1;
+ meminfo_buffer[len++] = -1;
+ /* Emit value */
+ meminfo_buffer[len++] = meminfo_keys[MEMINFO_MEMUSED];
+ meminfo_buffer[len++] = (info.totalram - info.freeram) * PAGE_SIZE;
+ /* Clear pid */
+ meminfo_buffer[len++] = 1;
+ meminfo_buffer[len++] = 0;
+ continue;
+ case MEMINFO_BUFFERRAM:
+ value = info.bufferram * PAGE_SIZE;
+ break;
+ default:
+ value = 0;
+ break;
+ }
+ meminfo_buffer[len++] = meminfo_keys[i];
+ meminfo_buffer[len++] = value;
}
+ }
- // Eat up any pending events
- while (!down_trylock(&gator_meminfo_sem));
+ meminfo_length = len;
+ new_data_avail = true;
+}
- if (!gator_meminfo_run) {
+#if USE_THREAD
+
+static int gator_meminfo_func(void *data)
+{
+ for (;;) {
+ if (down_killable(&gator_meminfo_sem))
break;
- }
- meminfo_length = len = 0;
-
- si_meminfo(&info);
- for (i = 0; i < MEMINFO_TOTAL; i++) {
- if (meminfo_enabled[i]) {
- switch (i) {
- case MEMINFO_MEMFREE:
- value = info.freeram * PAGE_SIZE;
- break;
- case MEMINFO_MEMUSED:
- // pid -1 means system wide
- meminfo_buffer[len++] = 1;
- meminfo_buffer[len++] = -1;
- // Emit value
- meminfo_buffer[len++] = meminfo_keys[MEMINFO_MEMUSED];
- meminfo_buffer[len++] = (info.totalram - info.freeram) * PAGE_SIZE;
- // Clear pid
- meminfo_buffer[len++] = 1;
- meminfo_buffer[len++] = 0;
- continue;
- case MEMINFO_BUFFERRAM:
- value = info.bufferram * PAGE_SIZE;
- break;
- default:
- value = 0;
- break;
- }
- meminfo_buffer[len++] = meminfo_keys[i];
- meminfo_buffer[len++] = value;
- }
- }
+ /* Eat up any pending events */
+ while (!down_trylock(&gator_meminfo_sem))
+ ;
+
+ if (!gator_meminfo_run)
+ break;
- meminfo_length = len;
- new_data_avail = true;
+ do_read();
}
return 0;
}
+#else
+
+/* Must be run in process context as the kernel function si_meminfo() can sleep */
+static void wq_sched_handler(struct work_struct *wsptr)
+{
+ do_read();
+}
+
+static void meminfo_wake_up_handler(unsigned long unused_data)
+{
+ /* had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater */
+ schedule_work(&work);
+}
+
+#endif
+
static int gator_events_meminfo_read(long long **buffer)
{
+#if !USE_THREAD
+ static unsigned int last_mem_event;
+#endif
+
if (!on_primary_core() || !meminfo_global_enabled)
return 0;
+#if !USE_THREAD
+ if (last_mem_event != mem_event) {
+ last_mem_event = mem_event;
+ mod_timer(&meminfo_wake_up_timer, jiffies + 1);
+ }
+#endif
+
if (!new_data_avail)
return 0;
@@ -280,6 +343,7 @@ static inline unsigned long gator_get_mm_counter(struct mm_struct *mm, int membe
{
#ifdef SPLIT_RSS_COUNTING
long val = atomic_long_read(&mm->rss_stat.count[member]);
+
if (val < 0)
val = 0;
return (unsigned long)val;
@@ -306,22 +370,19 @@ static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct
int cpu = get_physical_cpu();
long long *buf = per_cpu(proc_buffer, cpu);
- if (!proc_global_enabled) {
+ if (!proc_global_enabled)
return 0;
- }
- // Collect the memory stats of the process instead of the thread
- if (task->group_leader != NULL) {
+ /* Collect the memory stats of the process instead of the thread */
+ if (task->group_leader != NULL)
task = task->group_leader;
- }
- // get_task_mm/mmput is not needed in this context because the task and it's mm are required as part of the sched_switch
+ /* get_task_mm/mmput is not needed in this context because the task and it's mm are required as part of the sched_switch */
mm = task->mm;
- if (mm == NULL) {
+ if (mm == NULL)
return 0;
- }
- // Derived from task_statm in fs/proc/task_mmu.c
+ /* Derived from task_statm in fs/proc/task_mmu.c */
if (meminfo_enabled[MEMINFO_MEMUSED] || proc_enabled[PROC_SHARE]) {
share = get_mm_counter(mm,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
@@ -332,7 +393,7 @@ static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct
);
}
- // key of 1 indicates a pid
+ /* key of 1 indicates a pid */
buf[len++] = 1;
buf[len++] = task->pid;
@@ -366,12 +427,12 @@ static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct
MM_ANONPAGES
#endif
);
- // Send resident for this pid
+ /* Send resident for this pid */
buf[len++] = meminfo_keys[MEMINFO_MEMUSED];
buf[len++] = value * PAGE_SIZE;
}
- // Clear pid
+ /* Clear pid */
buf[len++] = 1;
buf[len++] = 0;