Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
[fw/altos] / src / kernel / ao_sample_profile.c
1 /*
2  * Copyright © 2012 Keith Packard <keithp@keithp.com>
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 as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include <ao.h>
20 #include <ao_sample_profile.h>
21 #include <ao_task.h>
22
23 #ifndef AO_SAMPLE_PROFILE_LOW_PC
24 #define AO_SAMPLE_PROFILE_LOW_PC        0x08002000
25 #endif
26
27 #ifndef AO_SAMPLE_PROFILE_HIGH_PC
28 #define AO_SAMPLE_PROFILE_HIGH_PC       0x0800f000
29 #endif
30
31 #ifndef AO_SAMPLE_PROFILE_SHIFT
32 #define AO_SAMPLE_PROFILE_SHIFT         6
33 #endif
34
35 #define AO_SAMPLE_PROFILE_RANGE         (AO_SAMPLE_PROFILE_HIGH_PC - AO_SAMPLE_PROFILE_LOW_PC)
36 #define AO_SAMPLE_PROFILE_NUM           (AO_SAMPLE_PROFILE_RANGE >> AO_SAMPLE_PROFILE_SHIFT)
37
38 static uint16_t prev_tick;
39 static uint16_t samples[AO_SAMPLE_PROFILE_NUM];
40 static uint8_t missed[AO_SAMPLE_PROFILE_NUM/8];
41 static uint16_t max_miss;
42 static uint32_t task, isr, os, idle;
43
44 extern uint8_t ao_idle_loc;
45
46 void
47 ao_sample_profile_point(uint32_t pc, uint16_t tick, uint8_t in_isr)
48 {
49         uint16_t        delta = tick - prev_tick;
50
51         if (pc < AO_SAMPLE_PROFILE_LOW_PC)
52                 return;
53         if (pc >= AO_SAMPLE_PROFILE_HIGH_PC)
54                 return;
55         if (ao_cur_task) {
56                 uint8_t         *sp;
57                 int32_t         sp_delta;
58                 
59                 asm("mov %0,sp" : "=&r" (sp));
60                 sp_delta = sp - (uint8_t *) ao_cur_task->stack;
61                 if (-96 < sp_delta && sp_delta < 16)
62                         ao_panic(AO_PANIC_STACK);
63         }
64
65         if (in_isr)
66                 isr += delta;
67         else if (ao_cur_task) {
68                 ao_cur_task->ticks += delta;
69                 task += delta;
70         } else if (pc == (uint32_t) &ao_idle_loc)
71                 idle += delta;
72         else
73                 os += delta;
74
75         pc -= AO_SAMPLE_PROFILE_LOW_PC;
76         pc >>= AO_SAMPLE_PROFILE_SHIFT;
77         samples[pc] += delta;
78
79         if (delta > 1)
80                 missed[pc >> 3] |= (1 << (pc & 7));
81         if (delta > max_miss)
82                 max_miss = delta;
83         prev_tick = tick;
84 }
85
86 static void
87 ao_sample_profile_start(void)
88 {
89         prev_tick = ao_sample_profile_timer_start();
90 }
91
92 static void
93 ao_sample_profile_stop(void)
94 {
95         ao_sample_profile_timer_stop();
96 }
97
98 static void
99 ao_sample_profile_dump(void)
100 {
101         uint16_t        a;
102         uint8_t         t;
103
104         printf ("task %6d\n", task);
105         printf ("isr  %6d\n", isr);
106         printf ("os   %6d\n", os);
107         printf ("idle %6d\n", idle);
108         printf ("irq blocked %d\n", max_miss);
109         for (t = 0; t < ao_num_tasks; t++)
110                 printf ("task %6d %6d %6d %s\n",
111                         ao_tasks[t]->ticks,
112                         ao_tasks[t]->yields,
113                         ao_tasks[t]->max_run,
114                         ao_tasks[t]->name);
115         for (a = 0; a < AO_SAMPLE_PROFILE_NUM; a++) {
116                 if (samples[a])
117                         printf ("%04x %c %u\n",
118                                 (a << AO_SAMPLE_PROFILE_SHIFT) + AO_SAMPLE_PROFILE_LOW_PC,
119                                 missed[a >> 3] & (1 << (a & 7)) ? '*' : ' ',
120                                 samples[a]);
121         }
122 }
123
124 static void
125 ao_sample_profile_clear(void)
126 {
127         int t;
128
129         task = isr = os = idle = 0;
130         max_miss = 0;
131         memset(samples, '\0', sizeof (samples));
132         memset(missed, '\0', sizeof (missed));
133         for (t = 0; t < ao_num_tasks; t++) {
134                 ao_tasks[t]->ticks = 0;
135                 ao_tasks[t]->yields = 0;
136                 ao_tasks[t]->max_run = 0;
137         }
138 }
139
140 static void
141 ao_sample_profile_cmd(void)
142 {
143         ao_cmd_white();
144         switch (ao_cmd_lex_c) {
145         case '1':
146                 ao_sample_profile_start();
147                 break;
148         case '0':
149                 ao_sample_profile_stop();
150                 break;
151         case 'd':
152                 ao_sample_profile_dump();
153                 break;
154         case 'c':
155                 ao_sample_profile_clear();
156                 break;
157         default:
158                 ao_cmd_status = ao_cmd_syntax_error;
159                 break;
160         }
161 }
162
163 static const struct ao_cmds ao_sample_profile_cmds[] = {
164         { ao_sample_profile_cmd,        "S <1 start,0 stop, d dump,c clear>\0Sample profile" },
165         { 0, NULL }
166 };
167
168 void
169 ao_sample_profile_init(void)
170 {
171         ao_sample_profile_timer_init();
172         ao_cmd_register(&ao_sample_profile_cmds[0]);
173         ao_sample_profile_clear();
174 }