a1a203171704d0844279d1c279b1a7d90f93792b
1 /**
2 * Copyright (C) ARM Limited 2010-2011. 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 "gator.h"
11 #include <linux/workqueue.h>
12 #include <trace/events/kmem.h>
14 #define MEMINFO_MEMFREE 0
15 #define MEMINFO_MEMUSED 1
16 #define MEMINFO_BUFFERRAM 2
17 #define MEMINFO_TOTAL 3
19 static ulong meminfo_global_enabled;
20 static ulong meminfo_enabled[MEMINFO_TOTAL];
21 static ulong meminfo_key[MEMINFO_TOTAL];
22 static unsigned long long meminfo_buffer[MEMINFO_TOTAL * 2];
23 static int meminfo_length = 0;
24 static unsigned int mem_event = 0;
25 static bool new_data_avail;
27 static void wq_sched_handler(struct work_struct *wsptr);
29 DECLARE_WORK(work, wq_sched_handler);
31 GATOR_DEFINE_PROBE(mm_page_free_direct, TP_PROTO(struct page *page, unsigned int order)) {
32 mem_event++;
33 }
35 GATOR_DEFINE_PROBE(mm_pagevec_free, TP_PROTO(struct page *page, int cold)) {
36 mem_event++;
37 }
39 GATOR_DEFINE_PROBE(mm_page_alloc, TP_PROTO(struct page *page, unsigned int order, gfp_t gfp_flags, int migratetype)) {
40 mem_event++;
41 }
43 static int gator_events_meminfo_create_files(struct super_block *sb, struct dentry *root)
44 {
45 struct dentry *dir;
46 int i;
48 for (i = 0; i < MEMINFO_TOTAL; i++) {
49 switch (i) {
50 case MEMINFO_MEMFREE:
51 dir = gatorfs_mkdir(sb, root, "Linux_meminfo_memfree");
52 break;
53 case MEMINFO_MEMUSED:
54 dir = gatorfs_mkdir(sb, root, "Linux_meminfo_memused");
55 break;
56 case MEMINFO_BUFFERRAM:
57 dir = gatorfs_mkdir(sb, root, "Linux_meminfo_bufferram");
58 break;
59 default:
60 return -1;
61 }
62 if (!dir) {
63 return -1;
64 }
65 gatorfs_create_ulong(sb, dir, "enabled", &meminfo_enabled[i]);
66 gatorfs_create_ro_ulong(sb, dir, "key", &meminfo_key[i]);
67 }
69 return 0;
70 }
72 static int gator_events_meminfo_start(void)
73 {
74 int i;
76 new_data_avail = true;
77 for (i = 0; i < MEMINFO_TOTAL; i++) {
78 if (meminfo_enabled[i]) {
79 meminfo_global_enabled = 1;
80 }
81 }
83 if (meminfo_global_enabled == 0)
84 return 0;
86 if (GATOR_REGISTER_TRACE(mm_page_free_direct))
87 goto mm_page_free_direct_exit;
88 if (GATOR_REGISTER_TRACE(mm_pagevec_free))
89 goto mm_pagevec_free_exit;
90 if (GATOR_REGISTER_TRACE(mm_page_alloc))
91 goto mm_page_alloc_exit;
93 return 0;
95 mm_page_alloc_exit:
96 GATOR_UNREGISTER_TRACE(mm_pagevec_free);
97 mm_pagevec_free_exit:
98 GATOR_UNREGISTER_TRACE(mm_page_free_direct);
99 mm_page_free_direct_exit:
100 return -1;
101 }
103 static void gator_events_meminfo_stop(void)
104 {
105 int i;
107 if (meminfo_global_enabled) {
108 GATOR_UNREGISTER_TRACE(mm_page_free_direct);
109 GATOR_UNREGISTER_TRACE(mm_pagevec_free);
110 GATOR_UNREGISTER_TRACE(mm_page_alloc);
111 }
113 meminfo_global_enabled = 0;
114 for (i = 0; i < MEMINFO_TOTAL; i++) {
115 meminfo_enabled[i] = 0;
116 }
117 }
119 // Must be run in a work queue as the kernel function si_meminfo() can sleep
120 static void wq_sched_handler(struct work_struct *wsptr)
121 {
122 struct sysinfo info;
123 int i, len;
124 unsigned long long value;
126 meminfo_length = len = 0;
128 si_meminfo(&info);
129 for (i = 0; i < MEMINFO_TOTAL; i++) {
130 if (meminfo_enabled[i]) {
131 switch (i) {
132 case MEMINFO_MEMFREE:
133 value = info.freeram * PAGE_SIZE;
134 break;
135 case MEMINFO_MEMUSED:
136 value = (info.totalram - info.freeram) * PAGE_SIZE;
137 break;
138 case MEMINFO_BUFFERRAM:
139 value = info.bufferram * PAGE_SIZE;
140 break;
141 default:
142 value = 0;
143 break;
144 }
145 meminfo_buffer[len++] = (unsigned long long)meminfo_key[i];
146 meminfo_buffer[len++] = value;
147 }
148 }
150 meminfo_length = len;
151 new_data_avail = true;
152 }
154 static int gator_events_meminfo_read(long long **buffer)
155 {
156 static unsigned int last_mem_event = 0;
158 if (smp_processor_id() || !meminfo_global_enabled)
159 return 0;
161 if (last_mem_event != mem_event) {
162 last_mem_event = mem_event;
163 schedule_work(&work);
164 }
166 if (!new_data_avail)
167 return 0;
169 new_data_avail = false;
171 if (buffer)
172 *buffer = meminfo_buffer;
174 return meminfo_length;
175 }
177 static struct gator_interface gator_events_meminfo_interface = {
178 .create_files = gator_events_meminfo_create_files,
179 .start = gator_events_meminfo_start,
180 .stop = gator_events_meminfo_stop,
181 .read64 = gator_events_meminfo_read,
182 };
184 int gator_events_meminfo_init(void)
185 {
186 int i;
188 meminfo_global_enabled = 0;
189 for (i = 0; i < MEMINFO_TOTAL; i++) {
190 meminfo_enabled[i] = 0;
191 meminfo_key[i] = gator_events_get_key();
192 }
194 return gator_events_install(&gator_events_meminfo_interface);
195 }
196 gator_events_init(gator_events_meminfo_init);