1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <errno.h>
6 #include <sys/types.h>
7 #include <fcntl.h>
8 #include "sys9.h"
9
10 enum {
11 Profoff, /* No profiling */
12 Profuser, /* Measure user time only (default) */
13 Profkernel, /* Measure user + kernel time */
14 Proftime, /* Measure total time */
15 Profsample, /* Use clock interrupt to sample (default when there is no cycle counter) */
16 }; /* what */
17
18 typedef long long vlong;
19 typedef unsigned long ulong;
20 typedef unsigned long long uvlong;
21
22 #include "/sys/include/tos.h"
23
24 extern void* sbrk(ulong);
25 extern long _callpc(void**);
26 extern long _savearg(void);
27 extern void _cycles(uvlong*); /* 64-bit value of the cycle counter if there is one, 0 if there isn't */
28
29 static ulong khz;
30 static ulong perr;
31 static int havecycles;
32
33 typedef struct Plink Plink;
34 struct Plink
35 {
36 Plink *old;
37 Plink *down;
38 Plink *link;
39 long pc;
40 long count;
41 vlong time;
42 };
43
44 #pragma profile off
45
46 ulong
_profin(void)47 _profin(void)
48 {
49 void *dummy;
50 long pc;
51 Plink *pp, *p;
52 ulong arg;
53 vlong t;
54
55 arg = _savearg();
56 pc = _callpc(&dummy);
57 pp = _tos->prof.pp;
58 if(pp == 0 || (_tos->prof.pid && _tos->pid != _tos->prof.pid))
59 return arg;
60
61 for(p=pp->down; p; p=p->link)
62 if(p->pc == pc)
63 goto out;
64 p = _tos->prof.next + 1;
65 if(p >= _tos->prof.last){
66 _tos->prof.pp = 0;
67 perr++;
68 return arg;
69 }
70 _tos->prof.next = p;
71 p->link = pp->down;
72 pp->down = p;
73 p->pc = pc;
74 p->old = pp;
75 p->down = 0;
76 p->count = 0;
77 p->time = 0LL;
78
79 out:
80 _tos->prof.pp = p;
81 p->count++;
82 switch(_tos->prof.what){
83 case Profkernel:
84 p->time = p->time - _tos->pcycles;
85 goto proftime;
86 case Profuser:
87 /* Add kernel cycles on proc entry */
88 p->time = p->time + _tos->kcycles;
89 /* fall through */
90 case Proftime:
91 proftime: /* Subtract cycle counter on proc entry */
92 _cycles((uvlong*)&t);
93 p->time = p->time - t;
94 break;
95 case Profsample:
96 p->time = p->time - _tos->clock;
97 break;
98 }
99 return arg; /* disgusting linkage */
100 }
101
102 ulong
_profout(void)103 _profout(void)
104 {
105 Plink *p;
106 ulong arg;
107 vlong t;
108
109 arg = _savearg();
110 p = _tos->prof.pp;
111 if (p == NULL || (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid))
112 return arg; /* Not our process */
113 switch(_tos->prof.what){
114 case Profkernel: /* Add proc cycles on proc entry */
115 p->time = p->time + _tos->pcycles;
116 goto proftime;
117 case Profuser: /* Subtract kernel cycles on proc entry */
118 p->time = p->time - _tos->kcycles;
119 /* fall through */
120 case Proftime:
121 proftime: /* Add cycle counter on proc entry */
122 _cycles((uvlong*)&t);
123 p->time = p->time + t;
124 break;
125 case Profsample:
126 p->time = p->time + _tos->clock;
127 break;
128 }
129 _tos->prof.pp = p->old;
130 return arg;
131 }
132
133 /* stdio may not be ready for us yet */
134 static void
err(char * fmt,...)135 err(char *fmt, ...)
136 {
137 int fd;
138 va_list arg;
139 char buf[128];
140
141 if((fd = open("/dev/cons", OWRITE)) == -1)
142 return;
143 va_start(arg, fmt);
144 /*
145 * C99 now requires *snprintf to return the number of characters
146 * that *would* have been emitted, had there been room for them,
147 * or a negative value on an `encoding error'. Arrgh!
148 */
149 vsnprintf(buf, sizeof buf, fmt, arg);
150 va_end(arg);
151 write(fd, buf, strlen(buf));
152 close(fd);
153 }
154
155 void
_profdump(void)156 _profdump(void)
157 {
158 int f;
159 long n;
160 Plink *p;
161 char *vp;
162 char filename[64];
163
164 if (_tos->prof.what == 0)
165 return; /* No profiling */
166 if (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid)
167 return; /* Not our process */
168 if(perr)
169 err("%lud Prof errors\n", perr);
170 _tos->prof.pp = NULL;
171 if (_tos->prof.pid)
172 snprintf(filename, sizeof filename - 1, "prof.%ld", _tos->prof.pid);
173 else
174 snprintf(filename, sizeof filename - 1, "prof.out");
175 f = creat(filename, 0666);
176 if(f < 0) {
177 err("%s: cannot create - %s\n", filename, strerror(errno));
178 return;
179 }
180 _tos->prof.pid = ~0; /* make sure data gets dumped once */
181 switch(_tos->prof.what){
182 case Profkernel:
183 _cycles((uvlong*)&_tos->prof.first->time);
184 _tos->prof.first->time = _tos->prof.first->time + _tos->pcycles;
185 break;
186 case Profuser:
187 _cycles((uvlong*)&_tos->prof.first->time);
188 _tos->prof.first->time = _tos->prof.first->time - _tos->kcycles;
189 break;
190 case Proftime:
191 _cycles((uvlong*)&_tos->prof.first->time);
192 break;
193 case Profsample:
194 _tos->prof.first->time = _tos->clock;
195 break;
196 }
197 vp = (char*)_tos->prof.first;
198
199 for(p = _tos->prof.first; p <= _tos->prof.next; p++) {
200
201 /*
202 * short down
203 */
204 n = 0xffff;
205 if(p->down)
206 n = p->down - _tos->prof.first;
207 vp[0] = n>>8;
208 vp[1] = n;
209
210 /*
211 * short right
212 */
213 n = 0xffff;
214 if(p->link)
215 n = p->link - _tos->prof.first;
216 vp[2] = n>>8;
217 vp[3] = n;
218 vp += 4;
219
220 /*
221 * long pc
222 */
223 n = p->pc;
224 vp[0] = n>>24;
225 vp[1] = n>>16;
226 vp[2] = n>>8;
227 vp[3] = n;
228 vp += 4;
229
230 /*
231 * long count
232 */
233 n = p->count;
234 vp[0] = n>>24;
235 vp[1] = n>>16;
236 vp[2] = n>>8;
237 vp[3] = n;
238 vp += 4;
239
240 /*
241 * vlong time
242 */
243 if (havecycles){
244 n = (vlong)(p->time / (vlong)khz);
245 }else
246 n = p->time;
247
248 vp[0] = n>>24;
249 vp[1] = n>>16;
250 vp[2] = n>>8;
251 vp[3] = n;
252 vp += 4;
253 }
254 write(f, (char*)_tos->prof.first, vp - (char*)_tos->prof.first);
255 close(f);
256
257 }
258
259 void
_profinit(int entries,int what)260 _profinit(int entries, int what)
261 {
262 if (_tos->prof.what == 0)
263 return; /* Profiling not linked in */
264 _tos->prof.pp = NULL;
265 _tos->prof.first = calloc(entries*sizeof(Plink),1);
266 _tos->prof.last = _tos->prof.first + entries;
267 _tos->prof.next = _tos->prof.first;
268 _tos->prof.pid = _tos->pid;
269 _tos->prof.what = what;
270 _tos->clock = 1;
271 }
272
273 void
_profmain(void)274 _profmain(void)
275 {
276 char ename[50];
277 int n, f;
278
279 n = 2000;
280 if (_tos->cyclefreq != 0LL){
281 khz = _tos->cyclefreq / 1000; /* Report times in milliseconds */
282 havecycles = 1;
283 }
284 f = open("/env/profsize", OREAD);
285 if(f >= 0) {
286 memset(ename, 0, sizeof(ename));
287 read(f, ename, sizeof(ename)-1);
288 close(f);
289 n = atol(ename);
290 }
291 _tos->prof.what = Profuser;
292 f = open("/env/proftype", OREAD);
293 if(f >= 0) {
294 memset(ename, 0, sizeof(ename));
295 read(f, ename, sizeof(ename)-1);
296 close(f);
297 if (strcmp(ename, "user") == 0)
298 _tos->prof.what = Profuser;
299 else if (strcmp(ename, "kernel") == 0)
300 _tos->prof.what = Profkernel;
301 else if (strcmp(ename, "elapsed") == 0 || strcmp(ename, "time") == 0)
302 _tos->prof.what = Proftime;
303 else if (strcmp(ename, "sample") == 0)
304 _tos->prof.what = Profsample;
305 }
306 _tos->prof.first = sbrk(n*sizeof(Plink));
307 _tos->prof.last = sbrk(0);
308 _tos->prof.next = _tos->prof.first;
309 _tos->prof.pp = NULL;
310 _tos->prof.pid = _tos->pid;
311 atexit(_profdump);
312 _tos->clock = 1;
313 }
314
prof(void (* fn)(void *),void * arg,int entries,int what)315 void prof(void (*fn)(void*), void *arg, int entries, int what)
316 {
317 _profinit(entries, what);
318 _tos->prof.pp = _tos->prof.next;
319 fn(arg);
320 _profdump();
321 }
322
323 #pragma profile on
324
325