diff options
author | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2008-09-17 13:29:37 -0400 |
---|---|---|
committer | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2008-09-17 13:29:37 -0400 |
commit | 364619e98672692ad1f58d96ffab531a304868e5 (patch) | |
tree | 8d076778d883efbcc7a32f562f5e822dad92ca5d | |
parent | cc5954a935380af2cf0bec81386f10eb4b425a25 (diff) |
Feather-Trace: use ftdev for overhead tracing
Much cleaner code now.
-rw-r--r-- | include/litmus/trace.h | 4 | ||||
-rw-r--r-- | litmus/trace.c | 290 |
2 files changed, 22 insertions, 272 deletions
diff --git a/include/litmus/trace.h b/include/litmus/trace.h index 2c8e1419de..b8157e88d8 100644 --- a/include/litmus/trace.h +++ b/include/litmus/trace.h | |||
@@ -23,10 +23,6 @@ struct timestamp { | |||
23 | uint8_t task_type; | 23 | uint8_t task_type; |
24 | }; | 24 | }; |
25 | 25 | ||
26 | |||
27 | /* buffer holding time stamps - will be provided by driver */ | ||
28 | extern struct ft_buffer* trace_ts_buf; | ||
29 | |||
30 | /* tracing callbacks */ | 26 | /* tracing callbacks */ |
31 | feather_callback void save_timestamp(unsigned long event); | 27 | feather_callback void save_timestamp(unsigned long event); |
32 | feather_callback void save_timestamp_def(unsigned long event, unsigned long type); | 28 | feather_callback void save_timestamp_def(unsigned long event, unsigned long type); |
diff --git a/litmus/trace.c b/litmus/trace.c index dadb09d863..6162bb3716 100644 --- a/litmus/trace.c +++ b/litmus/trace.c | |||
@@ -5,6 +5,8 @@ | |||
5 | #include <asm/uaccess.h> | 5 | #include <asm/uaccess.h> |
6 | #include <linux/module.h> | 6 | #include <linux/module.h> |
7 | 7 | ||
8 | #include <litmus/ftdev.h> | ||
9 | |||
8 | #include <litmus/litmus.h> | 10 | #include <litmus/litmus.h> |
9 | #include <litmus/trace.h> | 11 | #include <litmus/trace.h> |
10 | 12 | ||
@@ -12,7 +14,9 @@ | |||
12 | /* Allocation */ | 14 | /* Allocation */ |
13 | /******************************************************************************/ | 15 | /******************************************************************************/ |
14 | 16 | ||
15 | struct ft_buffer* trace_ts_buf = NULL; | 17 | static struct ftdev overhead_dev; |
18 | |||
19 | #define trace_ts_buf overhead_dev.minor[0].buf | ||
16 | 20 | ||
17 | static unsigned int ts_seq_no = 0; | 21 | static unsigned int ts_seq_no = 0; |
18 | 22 | ||
@@ -47,289 +51,39 @@ feather_callback void save_timestamp_task(unsigned long event, unsigned long t_p | |||
47 | __save_timestamp(event, rt ? TSK_RT : TSK_BE); | 51 | __save_timestamp(event, rt ? TSK_RT : TSK_BE); |
48 | } | 52 | } |
49 | 53 | ||
50 | static struct ft_buffer* alloc_ft_buffer(unsigned int count, size_t size) | ||
51 | { | ||
52 | struct ft_buffer* buf; | ||
53 | size_t total = (size + 1) * count; | ||
54 | char* mem; | ||
55 | int order = 0, pages = 1; | ||
56 | |||
57 | buf = kmalloc(sizeof(struct ft_buffer), GFP_KERNEL); | ||
58 | if (!buf) | ||
59 | return NULL; | ||
60 | |||
61 | total = (total / PAGE_SIZE) + (total % PAGE_SIZE != 0); | ||
62 | while (pages < total) { | ||
63 | order++; | ||
64 | pages *= 2; | ||
65 | } | ||
66 | |||
67 | mem = (char*) __get_free_pages(GFP_KERNEL, order); | ||
68 | if (!mem) { | ||
69 | kfree(buf); | ||
70 | return NULL; | ||
71 | } | ||
72 | |||
73 | if (!init_ft_buffer(buf, count, size, | ||
74 | mem + (count * size), /* markers at the end */ | ||
75 | mem)) { /* buffer objects */ | ||
76 | free_pages((unsigned long) mem, order); | ||
77 | kfree(buf); | ||
78 | return NULL; | ||
79 | } | ||
80 | return buf; | ||
81 | } | ||
82 | |||
83 | static void free_ft_buffer(struct ft_buffer* buf) | ||
84 | { | ||
85 | int order = 0, pages = 1; | ||
86 | size_t total; | ||
87 | |||
88 | if (buf) { | ||
89 | total = (buf->slot_size + 1) * buf->slot_count; | ||
90 | total = (total / PAGE_SIZE) + (total % PAGE_SIZE != 0); | ||
91 | while (pages < total) { | ||
92 | order++; | ||
93 | pages *= 2; | ||
94 | } | ||
95 | free_pages((unsigned long) buf->buffer_mem, order); | ||
96 | kfree(buf); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | |||
101 | /******************************************************************************/ | 54 | /******************************************************************************/ |
102 | /* DEVICE FILE DRIVER */ | 55 | /* DEVICE FILE DRIVER */ |
103 | /******************************************************************************/ | 56 | /******************************************************************************/ |
104 | 57 | ||
105 | #define NO_TIMESTAMPS (2 << 19) /* that should be 8 megs of ram, we may not get | 58 | #define NO_TIMESTAMPS (2 << 19) /* that should be 8 megs of ram, we may not get |
106 | * as much */ | 59 | * as much */ |
60 | #define FT_TRACE_MAJOR 252 | ||
107 | 61 | ||
108 | static DECLARE_MUTEX(feather_lock); | 62 | static int alloc_timestamp_buffer(struct ftdev* ftdev, unsigned int idx) |
109 | static int use_count = 0; | ||
110 | |||
111 | /* used for draining the FT buffers */ | ||
112 | static int enabled_events = 0; | ||
113 | |||
114 | static int trace_release(struct inode *in, struct file *filp) | ||
115 | { | ||
116 | int err = -EINVAL; | ||
117 | |||
118 | if (down_interruptible(&feather_lock)) { | ||
119 | err = -ERESTARTSYS; | ||
120 | goto out; | ||
121 | } | ||
122 | |||
123 | printk(KERN_ALERT "%s/%d disconnects from feather trace device. " | ||
124 | "use_count=%d\n", | ||
125 | current->comm, current->pid, use_count); | ||
126 | |||
127 | if (use_count == 1) { | ||
128 | /* disable events */ | ||
129 | ft_disable_all_events(); | ||
130 | enabled_events = 0; | ||
131 | |||
132 | /* wait for any pending events to complete */ | ||
133 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
134 | schedule_timeout(HZ); | ||
135 | |||
136 | printk(KERN_ALERT "Failed trace writes: %u\n", | ||
137 | trace_ts_buf->failed_writes); | ||
138 | |||
139 | free_ft_buffer(trace_ts_buf); | ||
140 | trace_ts_buf = NULL; | ||
141 | } | ||
142 | |||
143 | /* dummy entry to make linker happy */ | ||
144 | ft_event0(666, save_timestamp); | ||
145 | |||
146 | use_count--; | ||
147 | up(&feather_lock); | ||
148 | out: | ||
149 | return err; | ||
150 | } | ||
151 | |||
152 | static ssize_t trace_read(struct file *filp, char __user *to, size_t len, | ||
153 | loff_t *f_pos) | ||
154 | { | ||
155 | /* we ignore f_pos, this is strictly sequential */ | ||
156 | ssize_t error = 0; | ||
157 | struct timestamp ts; | ||
158 | |||
159 | if (down_interruptible(&feather_lock)) { | ||
160 | error = -ERESTARTSYS; | ||
161 | goto out; | ||
162 | } | ||
163 | |||
164 | |||
165 | while (len >= sizeof(struct timestamp)) { | ||
166 | if (ft_buffer_read(trace_ts_buf, &ts)) { | ||
167 | /* FIXME: avoid double copy */ | ||
168 | if (copy_to_user(to, &ts, sizeof(struct timestamp))) { | ||
169 | error = -EFAULT; | ||
170 | break; | ||
171 | } else { | ||
172 | len -= sizeof(struct timestamp); | ||
173 | to += sizeof(struct timestamp); | ||
174 | error += sizeof(struct timestamp); | ||
175 | } | ||
176 | } else if (enabled_events) { | ||
177 | /* only wait if there are any events enabled */ | ||
178 | set_current_state(TASK_INTERRUPTIBLE); | ||
179 | schedule_timeout(50); | ||
180 | if (signal_pending(current)) { | ||
181 | error = -ERESTARTSYS; | ||
182 | break; | ||
183 | } | ||
184 | } else | ||
185 | /* nothing left to get, return to user space */ | ||
186 | break; | ||
187 | } | ||
188 | up(&feather_lock); | ||
189 | out: | ||
190 | return error; | ||
191 | } | ||
192 | |||
193 | #define ENABLE_CMD 0 | ||
194 | #define DISABLE_CMD 1 | ||
195 | |||
196 | typedef uint32_t cmd_t; | ||
197 | |||
198 | static ssize_t trace_write(struct file *filp, const char __user *from, | ||
199 | size_t len, loff_t *f_pos) | ||
200 | { | ||
201 | ssize_t error = -EINVAL; | ||
202 | cmd_t cmd; | ||
203 | cmd_t id; | ||
204 | |||
205 | if (len % sizeof(cmd_t) || len < 2 * sizeof(cmd_t)) | ||
206 | goto out; | ||
207 | |||
208 | if (copy_from_user(&cmd, from, sizeof(cmd_t))) { | ||
209 | error = -EFAULT; | ||
210 | goto out; | ||
211 | } | ||
212 | len -= sizeof(cmd_t); | ||
213 | from += sizeof(cmd_t); | ||
214 | |||
215 | if (cmd != ENABLE_CMD && cmd != DISABLE_CMD) | ||
216 | goto out; | ||
217 | |||
218 | if (down_interruptible(&feather_lock)) { | ||
219 | error = -ERESTARTSYS; | ||
220 | goto out; | ||
221 | } | ||
222 | |||
223 | error = sizeof(cmd_t); | ||
224 | while (len) { | ||
225 | if (copy_from_user(&id, from, sizeof(cmd_t))) { | ||
226 | error = -EFAULT; | ||
227 | goto out; | ||
228 | } | ||
229 | len -= sizeof(cmd_t); | ||
230 | from += sizeof(cmd_t); | ||
231 | if (cmd) { | ||
232 | printk(KERN_INFO | ||
233 | "Disabling feather-trace event %d.\n", (int) id); | ||
234 | ft_disable_event(id); | ||
235 | enabled_events--; | ||
236 | } else { | ||
237 | printk(KERN_INFO | ||
238 | "Enabling feather-trace event %d.\n", (int) id); | ||
239 | ft_enable_event(id); | ||
240 | enabled_events++; | ||
241 | } | ||
242 | error += sizeof(cmd_t); | ||
243 | } | ||
244 | |||
245 | up(&feather_lock); | ||
246 | out: | ||
247 | return error; | ||
248 | } | ||
249 | |||
250 | static int trace_open(struct inode *in, struct file *filp) | ||
251 | { | 63 | { |
252 | int err = 0; | 64 | unsigned int count = NO_TIMESTAMPS; |
253 | unsigned int count = NO_TIMESTAMPS; | ||
254 | |||
255 | if (down_interruptible(&feather_lock)) { | ||
256 | err = -ERESTARTSYS; | ||
257 | goto out; | ||
258 | } | ||
259 | |||
260 | while (count && !trace_ts_buf) { | 65 | while (count && !trace_ts_buf) { |
261 | printk("trace: trying to allocate %u time stamps.\n", count); | 66 | printk("time stamp buffer: trying to allocate %u time stamps.\n", count); |
262 | trace_ts_buf = alloc_ft_buffer(count, sizeof(struct timestamp)); | 67 | ftdev->minor[idx].buf = alloc_ft_buffer(count, sizeof(struct timestamp)); |
263 | count /= 2; | 68 | count /= 2; |
264 | } | 69 | } |
265 | if (!trace_ts_buf) | 70 | return ftdev->minor[idx].buf ? 0 : -ENOMEM; |
266 | err = -ENOMEM; | ||
267 | else | ||
268 | use_count++; | ||
269 | |||
270 | up(&feather_lock); | ||
271 | out: | ||
272 | return err; | ||
273 | } | 71 | } |
274 | 72 | ||
275 | /******************************************************************************/ | 73 | static void free_timestamp_buffer(struct ftdev* ftdev, unsigned int idx) |
276 | /* Device Registration */ | ||
277 | /******************************************************************************/ | ||
278 | |||
279 | #define FT_TRACE_MAJOR 252 | ||
280 | |||
281 | struct file_operations ft_trace_fops = { | ||
282 | .owner = THIS_MODULE, | ||
283 | .open = trace_open, | ||
284 | .release = trace_release, | ||
285 | .write = trace_write, | ||
286 | .read = trace_read, | ||
287 | }; | ||
288 | |||
289 | |||
290 | static int __init register_buffer_dev(const char* name, | ||
291 | struct file_operations* fops, | ||
292 | int major, int count) | ||
293 | { | 74 | { |
294 | dev_t trace_dev; | 75 | free_ft_buffer(ftdev->minor[idx].buf); |
295 | struct cdev *cdev; | 76 | ftdev->minor[idx].buf = NULL; |
296 | int error = 0; | ||
297 | |||
298 | trace_dev = MKDEV(major, 0); | ||
299 | error = register_chrdev_region(trace_dev, count, name); | ||
300 | if (error) | ||
301 | { | ||
302 | printk(KERN_WARNING "trace: " | ||
303 | "Could not register major/minor number %d\n", major); | ||
304 | return error; | ||
305 | } | ||
306 | cdev = cdev_alloc(); | ||
307 | if (!cdev) { | ||
308 | printk(KERN_WARNING "trace: " | ||
309 | "Could not get a cdev for %s.\n", name); | ||
310 | return -ENOMEM; | ||
311 | } | ||
312 | cdev->owner = THIS_MODULE; | ||
313 | cdev->ops = fops; | ||
314 | error = cdev_add(cdev, trace_dev, count); | ||
315 | if (error) { | ||
316 | printk(KERN_WARNING "trace: " | ||
317 | "add_cdev failed for %s.\n", name); | ||
318 | return -ENOMEM; | ||
319 | } | ||
320 | return error; | ||
321 | |||
322 | } | 77 | } |
323 | 78 | ||
324 | static int __init init_sched_trace(void) | 79 | static int __init init_ft_overhead_trace(void) |
325 | { | 80 | { |
326 | int error = 0; | 81 | printk("Initializing Feather-Trace overhead tracing device.\n"); |
327 | 82 | ftdev_init(&overhead_dev); | |
328 | printk("Initializing Feather-Trace device\n"); | 83 | overhead_dev.minor_cnt = 1; /* only one buffer */ |
329 | 84 | overhead_dev.alloc = alloc_timestamp_buffer; | |
330 | error = register_buffer_dev("ft_trace", &ft_trace_fops, | 85 | overhead_dev.free = free_timestamp_buffer; |
331 | FT_TRACE_MAJOR, 1); | 86 | return register_ftdev(&overhead_dev, "ft_trace", FT_TRACE_MAJOR); |
332 | return error; | ||
333 | } | 87 | } |
334 | 88 | ||
335 | module_init(init_sched_trace); | 89 | module_init(init_ft_overhead_trace); |