2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
11 #include <linux/workqueue.h>
12 #include <trace/events/kmem.h>
13 #include <linux/hardirq.h>
15 #define MEMINFO_MEMFREE 0
16 #define MEMINFO_MEMUSED 1
17 #define MEMINFO_BUFFERRAM 2
18 #define MEMINFO_TOTAL 3
20 static ulong meminfo_global_enabled;
21 static ulong meminfo_enabled[MEMINFO_TOTAL];
22 static ulong meminfo_key[MEMINFO_TOTAL];
23 static unsigned long long meminfo_buffer[MEMINFO_TOTAL * 2];
24 static int meminfo_length = 0;
25 static unsigned int mem_event = 0;
26 static bool new_data_avail;
28 static void wq_sched_handler(struct work_struct *wsptr);
29 DECLARE_WORK(work, wq_sched_handler);
30 static struct timer_list meminfo_wake_up_timer;
31 static void meminfo_wake_up_handler(unsigned long unused_data);
33 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
34 GATOR_DEFINE_PROBE(mm_page_free_direct, TP_PROTO(struct page *page, unsigned int order))
36 GATOR_DEFINE_PROBE(mm_page_free, TP_PROTO(struct page *page, unsigned int order))
42 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
43 GATOR_DEFINE_PROBE(mm_pagevec_free, TP_PROTO(struct page *page, int cold))
45 GATOR_DEFINE_PROBE(mm_page_free_batched, TP_PROTO(struct page *page, int cold))
51 GATOR_DEFINE_PROBE(mm_page_alloc, TP_PROTO(struct page *page, unsigned int order, gfp_t gfp_flags, int migratetype))
56 static int gator_events_meminfo_create_files(struct super_block *sb, struct dentry *root)
61 for (i = 0; i < MEMINFO_TOTAL; i++) {
64 dir = gatorfs_mkdir(sb, root, "Linux_meminfo_memfree");
67 dir = gatorfs_mkdir(sb, root, "Linux_meminfo_memused");
69 case MEMINFO_BUFFERRAM:
70 dir = gatorfs_mkdir(sb, root, "Linux_meminfo_bufferram");
78 gatorfs_create_ulong(sb, dir, "enabled", &meminfo_enabled[i]);
79 gatorfs_create_ro_ulong(sb, dir, "key", &meminfo_key[i]);
85 static int gator_events_meminfo_start(void)
89 new_data_avail = true;
90 for (i = 0; i < MEMINFO_TOTAL; i++) {
91 if (meminfo_enabled[i]) {
92 meminfo_global_enabled = 1;
96 if (meminfo_global_enabled == 0)
99 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
100 if (GATOR_REGISTER_TRACE(mm_page_free_direct))
102 if (GATOR_REGISTER_TRACE(mm_page_free))
104 goto mm_page_free_exit;
105 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
106 if (GATOR_REGISTER_TRACE(mm_pagevec_free))
108 if (GATOR_REGISTER_TRACE(mm_page_free_batched))
110 goto mm_page_free_batched_exit;
111 if (GATOR_REGISTER_TRACE(mm_page_alloc))
112 goto mm_page_alloc_exit;
114 setup_timer(&meminfo_wake_up_timer, meminfo_wake_up_handler, 0);
118 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
119 GATOR_UNREGISTER_TRACE(mm_pagevec_free);
121 GATOR_UNREGISTER_TRACE(mm_page_free_batched);
123 mm_page_free_batched_exit:
124 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
125 GATOR_UNREGISTER_TRACE(mm_page_free_direct);
127 GATOR_UNREGISTER_TRACE(mm_page_free);
133 static void gator_events_meminfo_stop(void)
137 if (meminfo_global_enabled) {
138 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
139 GATOR_UNREGISTER_TRACE(mm_page_free_direct);
140 GATOR_UNREGISTER_TRACE(mm_pagevec_free);
142 GATOR_UNREGISTER_TRACE(mm_page_free);
143 GATOR_UNREGISTER_TRACE(mm_page_free_batched);
145 GATOR_UNREGISTER_TRACE(mm_page_alloc);
147 del_timer_sync(&meminfo_wake_up_timer);
150 meminfo_global_enabled = 0;
151 for (i = 0; i < MEMINFO_TOTAL; i++) {
152 meminfo_enabled[i] = 0;
156 // Must be run in process context as the kernel function si_meminfo() can sleep
157 static void wq_sched_handler(struct work_struct *wsptr)
161 unsigned long long value;
163 meminfo_length = len = 0;
166 for (i = 0; i < MEMINFO_TOTAL; i++) {
167 if (meminfo_enabled[i]) {
169 case MEMINFO_MEMFREE:
170 value = info.freeram * PAGE_SIZE;
172 case MEMINFO_MEMUSED:
173 value = (info.totalram - info.freeram) * PAGE_SIZE;
175 case MEMINFO_BUFFERRAM:
176 value = info.bufferram * PAGE_SIZE;
182 meminfo_buffer[len++] = (unsigned long long)meminfo_key[i];
183 meminfo_buffer[len++] = value;
187 meminfo_length = len;
188 new_data_avail = true;
191 static void meminfo_wake_up_handler(unsigned long unused_data)
193 // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
194 schedule_work(&work);
197 static int gator_events_meminfo_read(long long **buffer)
199 static unsigned int last_mem_event = 0;
201 if (!on_primary_core() || !meminfo_global_enabled)
204 if (last_mem_event != mem_event) {
205 last_mem_event = mem_event;
206 mod_timer(&meminfo_wake_up_timer, jiffies + 1);
212 new_data_avail = false;
215 *buffer = meminfo_buffer;
217 return meminfo_length;
220 static struct gator_interface gator_events_meminfo_interface = {
221 .create_files = gator_events_meminfo_create_files,
222 .start = gator_events_meminfo_start,
223 .stop = gator_events_meminfo_stop,
224 .read64 = gator_events_meminfo_read,
227 int gator_events_meminfo_init(void)
231 meminfo_global_enabled = 0;
232 for (i = 0; i < MEMINFO_TOTAL; i++) {
233 meminfo_enabled[i] = 0;
234 meminfo_key[i] = gator_events_get_key();
237 return gator_events_install(&gator_events_meminfo_interface);
240 gator_events_init(gator_events_meminfo_init);