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