2 * arch/ubicom32/mach-common/profile.c
3 * Implementation for Ubicom32 Profiler
5 * (C) Copyright 2009, Ubicom, Inc.
7 * This file is part of the Ubicom32 Linux Kernel Port.
9 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
10 * it and/or modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation, either version 2 of the
12 * License, or (at your option) any later version.
14 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
15 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
16 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with the Ubicom32 Linux Kernel Port. If not,
21 * see <http://www.gnu.org/licenses/>.
24 #include <linux/platform_device.h>
26 #include <linux/seq_file.h>
27 #include <linux/proc_fs.h>
29 #include <linux/mmzone.h>
31 #include <linux/page-flags.h>
32 #include <asm/uaccess.h>
33 #include <asm/devtree.h>
34 #include <asm/profilesample.h>
35 #include <asm/memory_map.h>
37 #include <asm/ip5000.h>
40 * spacs for all memory blocks so we can hold locks for short time when walking tables
42 #define PROFILE_NUM_MAPS 5000
43 static struct profile_map profile_pm[PROFILE_NUM_MAPS];
45 static struct profilenode *node = NULL;
46 static int profile_first_packet = 1;
48 static int profile_open(struct inode *inode, struct file *filp)
57 profile_first_packet = 1;
64 static int profile_sequence_num;
67 * make a packet full of sample data
69 static int profile_make_data_packet(char *buf, int count)
71 int samples; /* number of samples requested */
73 struct profile_header ph;
76 if (count < sizeof(struct profile_header) + sizeof(struct profile_sample)) {
81 * fill in the packet header
83 memset(&ph, 0, sizeof(struct profile_header));
84 ph.magic = PROF_MAGIC + PROFILE_VERSION;
85 ph.header_size = sizeof(struct profile_header);
86 ph.clocks = node->clocks;
87 for (i = 0; i < PROFILE_MAX_THREADS; ++i) {
88 ph.instruction_count[i] = node->inst_count[i];
90 ph.profile_instructions = 0;
91 ph.enabled = node->enabled_threads;
94 ph.profiler_thread = node->profiler_thread;
95 ph.clock_freq = node->clock_freq;
96 ph.seq_num = profile_sequence_num++;
97 ph.cpu_id = node->cpu_id;
98 ph.perf_counters[0] = node->stats[0];
99 ph.perf_counters[1] = node->stats[1];
100 ph.perf_counters[2] = node->stats[2];
101 ph.perf_counters[3] = node->stats[3];
102 ph.ddr_freq = node->ddr_freq;
104 ptr = buf + sizeof(struct profile_header);
106 samples = (count - sizeof(struct profile_header)) / sizeof(struct profile_sample);
107 for (i = 0; i < samples && node->count; ++i) {
108 if (copy_to_user(ptr, &node->samples[node->tail], sizeof(struct profile_sample)) != 0) {
113 if (node->tail >= node->max_samples) {
116 ptr += sizeof(struct profile_sample);
119 if (copy_to_user(buf, &ph, sizeof(struct profile_header)) != 0) {
122 if (ph.sample_count == 0)
125 return sizeof(struct profile_header) + ph.sample_count * sizeof(struct profile_sample);
128 static void profile_get_memory_stats(unsigned int *total_free, unsigned int *max_free)
138 * get all the free regions. In each zone, the array of free_area lists contains the first page of each frame of size 1 << order
140 for_each_zone(zone) {
141 unsigned long order, flags, i;
143 if (!populated_zone(zone))
146 if (!is_normal(zone))
149 spin_lock_irqsave(&zone->lock, flags);
150 for_each_migratetype_order(order, i) {
151 size = ((1 << order) << PAGE_SHIFT) >> 10;
152 list_for_each(p, &(zone->free_area[order].free_list[i])) {
153 if (size > *max_free) {
159 spin_unlock_irqrestore(&zone->lock, flags);
163 struct profile_counter_pkt profile_builtin_stats[] =
169 "Max free Block(KB)", 0
174 * make a packet full of performance counters
176 static char prof_pkt[PROFILE_MAX_PACKET_SIZE];
177 static int profile_make_stats_packet(char *buf, int count)
179 char *ptr = prof_pkt;
180 struct profile_header_counters hdr;
183 unsigned int total_free, max_free;
184 int builtin_count = sizeof(profile_builtin_stats) / sizeof(struct profile_counter_pkt);
186 if (count > PROFILE_MAX_PACKET_SIZE) {
187 count = PROFILE_MAX_PACKET_SIZE;
189 stat_count = (count - sizeof(struct profile_header_counters)) / sizeof (struct profile_counter_pkt);
190 stat_count -= builtin_count;
192 if (stat_count <= 0) {
196 if (stat_count > node->num_counters) {
197 stat_count = node->num_counters;
200 hdr.magic = PROF_MAGIC_COUNTERS;
201 hdr.ultra_sample_time = node->clocks;
202 hdr.ultra_count = stat_count;
203 hdr.linux_sample_time = UBICOM32_IO_TIMER->sysval;
204 hdr.linux_count = builtin_count;
205 memcpy(ptr, (void *)&hdr, sizeof(struct profile_header_counters));
206 ptr += sizeof(struct profile_header_counters);
209 for (i = 0; i < stat_count; ++i) {
210 memcpy(ptr, (void *)(&(node->counters[i])), sizeof(struct profile_counter));
211 ptr += sizeof(struct profile_counter);
215 * built in statistics
217 profile_get_memory_stats(&total_free, &max_free);
218 profile_builtin_stats[0].value = total_free;
219 profile_builtin_stats[1].value = max_free;
220 memcpy(ptr, (void *)profile_builtin_stats, sizeof(profile_builtin_stats));
221 ptr += sizeof(profile_builtin_stats);
223 if (copy_to_user(buf, prof_pkt, ptr - prof_pkt) != 0) {
226 return ptr - prof_pkt;
230 * return a udp packet ready to send to the profiler tool
231 * when there are no packets left to make, return 0
233 static int profile_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
240 if (!node->enabled) {
244 if (!node->samples) {
249 if (profile_first_packet) {
250 result = profile_make_stats_packet(buf, count);
251 profile_first_packet = 0;
254 result = profile_make_data_packet(buf, count);
256 profile_first_packet = 1;
264 static int profile_release(struct inode *inode, struct file *filp)
273 node->tail = node->head;
278 profile_first_packet = 1;
282 static const struct file_operations profile_fops = {
283 .open = profile_open,
284 .read = profile_read,
285 .release = profile_release,
288 static int page_aligned(void *x)
290 return !((unsigned int)x & ((1 << PAGE_SHIFT) - 1));
293 static int profile_maps_open(struct inode *inode, struct file *filp)
298 struct vm_area_struct *vma;
299 int type = PROFILE_MAP_TYPE_UNKNOWN;
305 * get the slab data (first so dups will show up as vmas)
308 num += kmem_cache_block_info("size-512", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
309 num += kmem_cache_block_info("size-1024", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
310 num += kmem_cache_block_info("size-2048", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
311 num += kmem_cache_block_info("size-4096", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
312 num += kmem_cache_block_info("size-8192", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
314 for (i = slab_start; i < num; ++i) {
315 profile_pm[i].type_size |= PROFILE_MAP_TYPE_SMALL << PROFILE_MAP_TYPE_SHIFT;
319 num += kmem_cache_block_info("dentry", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
320 num += kmem_cache_block_info("inode_cache", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
321 num += kmem_cache_block_info("sysfs_dir_cache", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
322 num += kmem_cache_block_info("proc_inode_cache", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
324 for (i = slab_start; i < num; ++i) {
325 profile_pm[i].type_size |= PROFILE_MAP_TYPE_FS << PROFILE_MAP_TYPE_SHIFT;
329 * get all the vma regions (allocated by mmap, most likely
332 down_read(&nommu_vma_sem);
333 for (rb = rb_first(&nommu_vma_tree); rb && num < PROFILE_NUM_MAPS; rb = rb_next(rb)) {
334 vma = rb_entry(rb, struct vm_area_struct, vm_rb);
335 profile_pm[num].start = (vma->vm_start - SDRAMSTART) >> PAGE_SHIFT;
336 profile_pm[num].type_size = (vma->vm_end - vma->vm_start + (1 << PAGE_SHIFT) - 1) >> PAGE_SHIFT;
337 flags = vma->vm_flags & 0xf;
338 if (flags == (VM_READ | VM_EXEC)) {
339 type = PROFILE_MAP_TYPE_TEXT;
340 } else if (flags == (VM_READ | VM_WRITE | VM_EXEC)) {
341 type = PROFILE_MAP_TYPE_STACK;
342 } else if (flags == (VM_READ | VM_WRITE)) {
343 type = PROFILE_MAP_TYPE_APP_DATA;
345 profile_pm[num].type_size |= type << PROFILE_MAP_TYPE_SHIFT;
348 up_read(&nommu_vma_sem);
355 * get all the free regions. In each zone, the array of free_area lists contains the first page of each frame of size 1 << order
357 for_each_zone(zone) {
358 unsigned long order, flags, i;
361 if (!populated_zone(zone))
364 if (!is_normal(zone))
367 spin_lock_irqsave(&zone->lock, flags);
368 for_each_migratetype_order(order, i) {
369 list_for_each(p, &(zone->free_area[order].free_list[i])) {
370 page = list_entry(p, struct page, lru);
371 profile_pm[num].start = ((page_to_phys(page) - SDRAMSTART) >> PAGE_SHIFT) - 0x40;
372 profile_pm[num].type_size = (PROFILE_MAP_TYPE_FREE << PROFILE_MAP_TYPE_SHIFT) | order;
374 if (num >= PROFILE_NUM_MAPS) {
375 spin_unlock_irqrestore(&zone->lock, flags);
380 spin_unlock_irqrestore(&zone->lock, flags);
384 * get the filesystem inodes
386 list_for_each(p, &(super_blocks)) {
387 struct super_block *sb;
389 if (num >= PROFILE_NUM_MAPS)
391 sb = list_entry(p, struct super_block, s_list);
392 if (page_aligned(sb)) {
393 profile_pm[num].start = ((unsigned int)sb - SDRAMSTART) >> PAGE_SHIFT;
394 profile_pm[num].type_size = (PROFILE_MAP_TYPE_FS << PROFILE_MAP_TYPE_SHIFT);
397 list_for_each(q, &(sb->s_inodes)) {
399 if (num >= PROFILE_NUM_MAPS)
401 in = list_entry(q, struct inode, i_sb_list);
402 if (page_aligned(in)) {
403 profile_pm[num].start = ((unsigned int)in - SDRAMSTART) >> PAGE_SHIFT;
404 profile_pm[num].type_size = (PROFILE_MAP_TYPE_FS << PROFILE_MAP_TYPE_SHIFT);
411 * get the buffer cache pages
413 for (i = 0; i < num_physpages && num < PROFILE_NUM_MAPS; ++i) {
414 if ((mem_map + i)->flags & (1 << PG_lru)) {
416 while ((mem_map + i)->flags & (1 << PG_lru) && i < num_physpages)
418 profile_pm[num].start = start;
419 profile_pm[num].type_size = (i - start) | (PROFILE_MAP_TYPE_CACHE << PROFILE_MAP_TYPE_SHIFT);
424 filp->private_data = (void *)num;
429 * return one packet of map data, or 0 if all maps have been returned already
431 static int profile_maps_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
433 struct profile_header_maps header;
434 char *p = buf + sizeof(header);
435 int total = (int)filp->private_data;
437 header.count = (count - sizeof(header)) / sizeof(struct profile_map);
438 if (header.count > PROFILE_MAX_MAPS) {
439 header.count = PROFILE_MAX_MAPS;;
441 if (header.count > total - *f_pos) {
442 header.count = total - *f_pos;
445 if (header.count == 0) {
449 header.magic = PROF_MAGIC_MAPS;
450 header.page_shift = PAGE_SHIFT;
452 if (copy_to_user(buf, &header, sizeof(header)) != 0) {
455 if (copy_to_user(p, (void *)&profile_pm[*f_pos], sizeof(struct profile_map) * header.count) != 0) {
458 *f_pos += header.count;
460 return sizeof(header) + sizeof(struct profile_map) * header.count;
463 static int profile_maps_release(struct inode *inode, struct file *filp)
468 static const struct file_operations profile_maps_fops = {
469 .open = profile_maps_open,
470 .read = profile_maps_read,
471 .release = profile_maps_release,
474 static int profile_rate_show(struct seq_file *m, void *v)
477 seq_printf(m, "%d samples per second. %d virtual counters.\n", node->rate, node->num_counters);
479 seq_printf(m, "Profiler is not initialized.\n");
484 static int profile_rate_open(struct inode *inode, struct file *filp)
486 return single_open(filp, profile_rate_show, NULL);
489 static int profile_rate_write(struct file *filp, const char *buf, size_t len, loff_t *off)
495 static const struct file_operations profile_rate_fops = {
496 .open = profile_rate_open,
499 .release = single_release,
500 .write = profile_rate_write,
503 int ubi32_profile_init_module(void)
505 struct proc_dir_entry *pdir;
510 node = (struct profilenode *)devtree_find_node("profiler");
512 printk(KERN_INFO "Profiler does not exist.\n");
517 * allocate the sample buffer
519 node->max_samples = PROFILE_MAX_SAMPLES;
520 node->samples = kmalloc(node->max_samples * sizeof(struct profile_sample), GFP_KERNEL);
521 if (!node->samples) {
522 printk(KERN_INFO "Profiler sample buffer kmalloc failed.\n");
527 * connect to the file system
529 pdir = proc_mkdir("profile", NULL);
533 if (!proc_create("data", 0, pdir, &profile_fops)) {
536 if (!proc_create("rate", 0, pdir, &profile_rate_fops)) {
539 if (!proc_create("maps", 0, pdir, &profile_maps_fops)) {
546 module_init(ubi32_profile_init_module);
548 MODULE_AUTHOR("David Fotland");
549 MODULE_LICENSE("GPL");