1 /**
2 * Copyright (C) ARM Limited 2010. 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 */
10 #include <linux/workqueue.h>
11 #include <linux/version.h>
12 #include <linux/slab.h>
13 #include <linux/mm.h>
14 #include <linux/fs.h>
15 #include <trace/events/kmem.h>
17 #include "gator.h"
18 #include "gator_trace.h"
20 #define MEMINFO_MEMFREE 0
21 #define MEMINFO_MEMUSED 1
22 #define MEMINFO_BUFFERRAM 2
23 #define MEMINFO_TOTAL 3
25 static ulong meminfo_global_enabled;
26 static ulong meminfo_enabled[MEMINFO_TOTAL];
27 static ulong meminfo_key[MEMINFO_TOTAL];
28 static int meminfo_buffer[MEMINFO_TOTAL * 2];
29 static int meminfo_length = 0;
30 static unsigned int mem_event = 0;
31 static bool new_data_avail;
33 static void wq_sched_handler(struct work_struct *wsptr);
35 DECLARE_WORK(work, wq_sched_handler);
37 GATOR_DEFINE_PROBE(mm_page_free_direct, TP_PROTO(struct page *page, unsigned int order)) {
38 mem_event++;
39 }
41 GATOR_DEFINE_PROBE(mm_pagevec_free, TP_PROTO(struct page *page, int cold)) {
42 mem_event++;
43 }
45 GATOR_DEFINE_PROBE(mm_page_alloc, TP_PROTO(struct page *page, unsigned int order, gfp_t gfp_flags, int migratetype)) {
46 mem_event++;
47 }
49 static int gator_events_meminfo_create_files(struct super_block *sb, struct dentry *root)
50 {
51 struct dentry *dir;
52 int i;
54 for (i = 0; i < MEMINFO_TOTAL; i++) {
55 switch (i) {
56 case MEMINFO_MEMFREE:
57 dir = gatorfs_mkdir(sb, root, "Linux_meminfo_memfree");
58 break;
59 case MEMINFO_MEMUSED:
60 dir = gatorfs_mkdir(sb, root, "Linux_meminfo_memused");
61 break;
62 case MEMINFO_BUFFERRAM:
63 dir = gatorfs_mkdir(sb, root, "Linux_meminfo_bufferram");
64 break;
65 default:
66 return -1;
67 }
68 if (!dir) {
69 return -1;
70 }
71 gatorfs_create_ulong(sb, dir, "enabled", &meminfo_enabled[i]);
72 gatorfs_create_ro_ulong(sb, dir, "key", &meminfo_key[i]);
73 }
75 return 0;
76 }
78 static int gator_events_meminfo_init(int *key)
79 {
80 int i;
82 meminfo_global_enabled = 0;
83 for (i = 0; i < MEMINFO_TOTAL; i++) {
84 meminfo_enabled[i] = 0;
85 meminfo_key[i] = *key;
86 *key = *key + 1;
87 }
89 return 0;
90 }
92 static int gator_events_meminfo_start(void)
93 {
94 int i;
96 new_data_avail = true;
97 for (i = 0; i < MEMINFO_TOTAL; i++) {
98 if (meminfo_enabled[i]) {
99 meminfo_global_enabled = 1;
100 }
101 }
103 if (meminfo_global_enabled == 0)
104 return 0;
106 if (GATOR_REGISTER_TRACE(mm_page_free_direct))
107 goto mm_page_free_direct_exit;
108 if (GATOR_REGISTER_TRACE(mm_pagevec_free))
109 goto mm_pagevec_free_exit;
110 if (GATOR_REGISTER_TRACE(mm_page_alloc))
111 goto mm_page_alloc_exit;
113 return 0;
115 mm_page_alloc_exit:
116 GATOR_UNREGISTER_TRACE(mm_pagevec_free);
117 mm_pagevec_free_exit:
118 GATOR_UNREGISTER_TRACE(mm_page_free_direct);
119 mm_page_free_direct_exit:
120 return -1;
121 }
123 static void gator_events_meminfo_stop(void)
124 {
125 int i;
127 if (meminfo_global_enabled) {
128 GATOR_UNREGISTER_TRACE(mm_page_free_direct);
129 GATOR_UNREGISTER_TRACE(mm_pagevec_free);
130 GATOR_UNREGISTER_TRACE(mm_page_alloc);
131 }
133 meminfo_global_enabled = 0;
134 for (i = 0; i < MEMINFO_TOTAL; i++) {
135 meminfo_enabled[i] = 0;
136 }
137 }
139 // Must be run in a work queue as the kernel function si_meminfo() can sleep
140 static void wq_sched_handler(struct work_struct *wsptr)
141 {
142 struct sysinfo info;
143 int i, len, value;
145 meminfo_length = len = 0;
147 si_meminfo(&info);
148 for (i = 0; i < MEMINFO_TOTAL; i++) {
149 if (meminfo_enabled[i]) {
150 switch (i) {
151 case MEMINFO_MEMFREE:
152 value = info.freeram * PAGE_SIZE;
153 break;
154 case MEMINFO_MEMUSED:
155 value = (info.totalram - info.freeram) * PAGE_SIZE;
156 break;
157 case MEMINFO_BUFFERRAM:
158 value = info.bufferram * PAGE_SIZE;
159 break;
160 default:
161 value = 0;
162 break;
163 }
164 meminfo_buffer[len++] = meminfo_key[i];
165 meminfo_buffer[len++] = value;
166 }
167 }
169 meminfo_length = len;
170 new_data_avail = true;
171 }
173 static int gator_events_meminfo_read(int **buffer)
174 {
175 static unsigned int last_mem_event = 0;
177 if (smp_processor_id() || !meminfo_global_enabled)
178 return 0;
180 if (last_mem_event != mem_event) {
181 last_mem_event = mem_event;
182 schedule_work(&work);
183 }
185 if (!new_data_avail)
186 return 0;
188 new_data_avail = false;
190 if (buffer)
191 *buffer = meminfo_buffer;
193 return meminfo_length;
194 }
196 int gator_events_meminfo_install(gator_interface *gi) {
197 gi->create_files = gator_events_meminfo_create_files;
198 gi->init = gator_events_meminfo_init;
199 gi->start = gator_events_meminfo_start;
200 gi->stop = gator_events_meminfo_stop;
201 gi->read = gator_events_meminfo_read;
202 return 0;
203 }