USB: mct_u232: add sanity checking in probe
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / gator / gator_events_meminfo.c
1 /**
2  * Copyright (C) ARM Limited 2010-2015. All rights reserved.
3  *
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.
7  *
8  */
9
10 #include "gator.h"
11
12 #include <linux/hardirq.h>
13 #include <linux/kthread.h>
14 #include <linux/sched.h>
15 #include <linux/semaphore.h>
16 #include <linux/workqueue.h>
17 #include <trace/events/kmem.h>
18
19 #define USE_THREAD defined(CONFIG_PREEMPT_RT_FULL)
20
21 enum {
22         MEMINFO_MEMFREE,
23         MEMINFO_MEMUSED,
24         MEMINFO_BUFFERRAM,
25         MEMINFO_TOTAL,
26 };
27
28 enum {
29         PROC_SIZE,
30         PROC_SHARE,
31         PROC_TEXT,
32         PROC_DATA,
33         PROC_COUNT,
34 };
35
36 static const char * const meminfo_names[] = {
37         "Linux_meminfo_memfree",
38         "Linux_meminfo_memused",
39         "Linux_meminfo_bufferram",
40 };
41
42 static const char * const proc_names[] = {
43         "Linux_proc_statm_size",
44         "Linux_proc_statm_share",
45         "Linux_proc_statm_text",
46         "Linux_proc_statm_data",
47 };
48
49 static bool meminfo_global_enabled;
50 static ulong meminfo_enabled[MEMINFO_TOTAL];
51 static ulong meminfo_keys[MEMINFO_TOTAL];
52 static long long meminfo_buffer[2 * (MEMINFO_TOTAL + 2)];
53 static int meminfo_length;
54 static bool new_data_avail;
55
56 static bool proc_global_enabled;
57 static ulong proc_enabled[PROC_COUNT];
58 static ulong proc_keys[PROC_COUNT];
59 static DEFINE_PER_CPU(long long, proc_buffer[2 * (PROC_COUNT + 3)]);
60
61 static void do_read(void);
62
63 #if USE_THREAD
64
65 static int gator_meminfo_func(void *data);
66 static bool gator_meminfo_run;
67 /* Initialize semaphore unlocked to initialize memory values */
68 static DEFINE_SEMAPHORE(gator_meminfo_sem);
69
70 static void notify(void)
71 {
72         up(&gator_meminfo_sem);
73 }
74
75 #else
76
77 static unsigned int mem_event;
78 static void wq_sched_handler(struct work_struct *wsptr);
79 static DECLARE_WORK(work, wq_sched_handler);
80 static struct timer_list meminfo_wake_up_timer;
81 static void meminfo_wake_up_handler(unsigned long unused_data);
82
83 static void notify(void)
84 {
85         mem_event++;
86 }
87
88 #endif
89
90 GATOR_DEFINE_PROBE(mm_page_free, TP_PROTO(struct page *page, unsigned int order))
91 {
92         notify();
93 }
94
95 GATOR_DEFINE_PROBE(mm_page_free_batched, TP_PROTO(struct page *page, int cold))
96 {
97         notify();
98 }
99
100 GATOR_DEFINE_PROBE(mm_page_alloc, TP_PROTO(struct page *page, unsigned int order, gfp_t gfp_flags, int migratetype))
101 {
102         notify();
103 }
104
105 static int gator_events_meminfo_create_files(struct super_block *sb, struct dentry *root)
106 {
107         struct dentry *dir;
108         int i;
109
110         for (i = 0; i < MEMINFO_TOTAL; i++) {
111                 dir = gatorfs_mkdir(sb, root, meminfo_names[i]);
112                 if (!dir)
113                         return -1;
114                 gatorfs_create_ulong(sb, dir, "enabled", &meminfo_enabled[i]);
115                 gatorfs_create_ro_ulong(sb, dir, "key", &meminfo_keys[i]);
116         }
117
118         for (i = 0; i < PROC_COUNT; ++i) {
119                 dir = gatorfs_mkdir(sb, root, proc_names[i]);
120                 if (!dir)
121                         return -1;
122                 gatorfs_create_ulong(sb, dir, "enabled", &proc_enabled[i]);
123                 gatorfs_create_ro_ulong(sb, dir, "key", &proc_keys[i]);
124         }
125
126         return 0;
127 }
128
129 static int gator_events_meminfo_start(void)
130 {
131         int i;
132
133         new_data_avail = false;
134         meminfo_global_enabled = 0;
135         for (i = 0; i < MEMINFO_TOTAL; i++) {
136                 if (meminfo_enabled[i]) {
137                         meminfo_global_enabled = 1;
138                         break;
139                 }
140         }
141
142         proc_global_enabled = 0;
143         for (i = 0; i < PROC_COUNT; ++i) {
144                 if (proc_enabled[i]) {
145                         proc_global_enabled = 1;
146                         break;
147                 }
148         }
149         if (meminfo_enabled[MEMINFO_MEMUSED])
150                 proc_global_enabled = 1;
151
152         if (meminfo_global_enabled == 0)
153                 return 0;
154
155         if (GATOR_REGISTER_TRACE(mm_page_free))
156                 goto mm_page_free_exit;
157         if (GATOR_REGISTER_TRACE(mm_page_free_batched))
158                 goto mm_page_free_batched_exit;
159         if (GATOR_REGISTER_TRACE(mm_page_alloc))
160                 goto mm_page_alloc_exit;
161
162         do_read();
163 #if USE_THREAD
164         /* Start worker thread */
165         gator_meminfo_run = true;
166         /* Since the mutex starts unlocked, memory values will be initialized */
167         if (IS_ERR(kthread_run(gator_meminfo_func, NULL, "gator_meminfo")))
168                 goto kthread_run_exit;
169 #else
170         setup_deferrable_timer_on_stack(&meminfo_wake_up_timer, meminfo_wake_up_handler, 0);
171 #endif
172
173         return 0;
174
175 #if USE_THREAD
176 kthread_run_exit:
177         GATOR_UNREGISTER_TRACE(mm_page_alloc);
178 #endif
179 mm_page_alloc_exit:
180         GATOR_UNREGISTER_TRACE(mm_page_free_batched);
181 mm_page_free_batched_exit:
182         GATOR_UNREGISTER_TRACE(mm_page_free);
183 mm_page_free_exit:
184         return -1;
185 }
186
187 static void gator_events_meminfo_stop(void)
188 {
189         if (meminfo_global_enabled) {
190                 GATOR_UNREGISTER_TRACE(mm_page_free);
191                 GATOR_UNREGISTER_TRACE(mm_page_free_batched);
192                 GATOR_UNREGISTER_TRACE(mm_page_alloc);
193
194 #if USE_THREAD
195                 /* Stop worker thread */
196                 gator_meminfo_run = false;
197                 up(&gator_meminfo_sem);
198 #else
199                 del_timer_sync(&meminfo_wake_up_timer);
200 #endif
201         }
202 }
203
204 static void do_read(void)
205 {
206         struct sysinfo info;
207         int i, len;
208         unsigned long long value;
209
210         meminfo_length = len = 0;
211
212         si_meminfo(&info);
213         for (i = 0; i < MEMINFO_TOTAL; i++) {
214                 if (meminfo_enabled[i]) {
215                         switch (i) {
216                         case MEMINFO_MEMFREE:
217                                 value = info.freeram * PAGE_SIZE;
218                                 break;
219                         case MEMINFO_MEMUSED:
220                                 /* pid -1 means system wide */
221                                 meminfo_buffer[len++] = 1;
222                                 meminfo_buffer[len++] = -1;
223                                 /* Emit value */
224                                 meminfo_buffer[len++] = meminfo_keys[MEMINFO_MEMUSED];
225                                 meminfo_buffer[len++] = (info.totalram - info.freeram) * PAGE_SIZE;
226                                 /* Clear pid */
227                                 meminfo_buffer[len++] = 1;
228                                 meminfo_buffer[len++] = 0;
229                                 continue;
230                         case MEMINFO_BUFFERRAM:
231                                 value = info.bufferram * PAGE_SIZE;
232                                 break;
233                         default:
234                                 value = 0;
235                                 break;
236                         }
237                         meminfo_buffer[len++] = meminfo_keys[i];
238                         meminfo_buffer[len++] = value;
239                 }
240         }
241
242         meminfo_length = len;
243         new_data_avail = true;
244 }
245
246 #if USE_THREAD
247
248 static int gator_meminfo_func(void *data)
249 {
250         for (;;) {
251                 if (down_killable(&gator_meminfo_sem))
252                         break;
253
254                 /* Eat up any pending events */
255                 while (!down_trylock(&gator_meminfo_sem))
256                         ;
257
258                 if (!gator_meminfo_run)
259                         break;
260
261                 do_read();
262         }
263
264         return 0;
265 }
266
267 #else
268
269 /* Must be run in process context as the kernel function si_meminfo() can sleep */
270 static void wq_sched_handler(struct work_struct *wsptr)
271 {
272         do_read();
273 }
274
275 static void meminfo_wake_up_handler(unsigned long unused_data)
276 {
277         /* had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater */
278         schedule_work(&work);
279 }
280
281 #endif
282
283 static int gator_events_meminfo_read(long long **buffer, bool sched_switch)
284 {
285 #if !USE_THREAD
286         static unsigned int last_mem_event;
287 #endif
288
289         if (!on_primary_core() || !meminfo_global_enabled)
290                 return 0;
291
292 #if !USE_THREAD
293         if (last_mem_event != mem_event) {
294                 last_mem_event = mem_event;
295                 mod_timer(&meminfo_wake_up_timer, jiffies + 1);
296         }
297 #endif
298
299         if (!new_data_avail)
300                 return 0;
301
302         new_data_avail = false;
303
304         if (buffer)
305                 *buffer = meminfo_buffer;
306
307         return meminfo_length;
308 }
309
310 static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct *task)
311 {
312         struct mm_struct *mm;
313         u64 share = 0;
314         int i;
315         long long value;
316         int len = 0;
317         int cpu = get_physical_cpu();
318         long long *buf = per_cpu(proc_buffer, cpu);
319
320         if (!proc_global_enabled)
321                 return 0;
322
323         /* Collect the memory stats of the process instead of the thread */
324         if (task->group_leader != NULL)
325                 task = task->group_leader;
326
327         /* 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 */
328         mm = task->mm;
329         if (mm == NULL)
330                 return 0;
331
332         /* Derived from task_statm in fs/proc/task_mmu.c */
333         if (meminfo_enabled[MEMINFO_MEMUSED] || proc_enabled[PROC_SHARE]) {
334                 share = get_mm_counter(mm, MM_FILEPAGES);
335         }
336
337         /* key of 1 indicates a pid */
338         buf[len++] = 1;
339         buf[len++] = task->pid;
340
341         for (i = 0; i < PROC_COUNT; ++i) {
342                 if (proc_enabled[i]) {
343                         switch (i) {
344                         case PROC_SIZE:
345                                 value = mm->total_vm;
346                                 break;
347                         case PROC_SHARE:
348                                 value = share;
349                                 break;
350                         case PROC_TEXT:
351                                 value = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) >> PAGE_SHIFT;
352                                 break;
353                         case PROC_DATA:
354                                 value = mm->total_vm - mm->shared_vm;
355                                 break;
356                         }
357
358                         buf[len++] = proc_keys[i];
359                         buf[len++] = value * PAGE_SIZE;
360                 }
361         }
362
363         if (meminfo_enabled[MEMINFO_MEMUSED]) {
364                 value = share + get_mm_counter(mm, MM_ANONPAGES);
365                 /* Send resident for this pid */
366                 buf[len++] = meminfo_keys[MEMINFO_MEMUSED];
367                 buf[len++] = value * PAGE_SIZE;
368         }
369
370         /* Clear pid */
371         buf[len++] = 1;
372         buf[len++] = 0;
373
374         if (buffer)
375                 *buffer = buf;
376
377         return len;
378 }
379
380 static struct gator_interface gator_events_meminfo_interface = {
381         .name = "meminfo",
382         .create_files = gator_events_meminfo_create_files,
383         .start = gator_events_meminfo_start,
384         .stop = gator_events_meminfo_stop,
385         .read64 = gator_events_meminfo_read,
386         .read_proc = gator_events_meminfo_read_proc,
387 };
388
389 int gator_events_meminfo_init(void)
390 {
391         int i;
392
393         meminfo_global_enabled = 0;
394         for (i = 0; i < MEMINFO_TOTAL; i++) {
395                 meminfo_enabled[i] = 0;
396                 meminfo_keys[i] = gator_events_get_key();
397         }
398
399         proc_global_enabled = 0;
400         for (i = 0; i < PROC_COUNT; ++i) {
401                 proc_enabled[i] = 0;
402                 proc_keys[i] = gator_events_get_key();
403         }
404
405         return gator_events_install(&gator_events_meminfo_interface);
406 }