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");