13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3e288d156SDavid du Colombier #include <tos.h>
43e12c5d1SDavid du Colombier
53e12c5d1SDavid du Colombier extern long _callpc(void**);
63e12c5d1SDavid du Colombier extern long _savearg(void);
7e288d156SDavid du Colombier
8208510e1SDavid du Colombier static ulong khz;
9208510e1SDavid du Colombier static ulong perr;
10208510e1SDavid du Colombier static int havecycles;
113e12c5d1SDavid du Colombier
123e12c5d1SDavid du Colombier typedef struct Plink Plink;
133e12c5d1SDavid du Colombier struct Plink
143e12c5d1SDavid du Colombier {
15e288d156SDavid du Colombier Plink *old;
163e12c5d1SDavid du Colombier Plink *down;
173e12c5d1SDavid du Colombier Plink *link;
183e12c5d1SDavid du Colombier long pc;
193e12c5d1SDavid du Colombier long count;
20e288d156SDavid du Colombier vlong time;
213e12c5d1SDavid du Colombier };
223e12c5d1SDavid du Colombier
23e288d156SDavid du Colombier #pragma profile off
243e12c5d1SDavid du Colombier
253e12c5d1SDavid du Colombier ulong
_profin(void)263e12c5d1SDavid du Colombier _profin(void)
273e12c5d1SDavid du Colombier {
283e12c5d1SDavid du Colombier void *dummy;
293e12c5d1SDavid du Colombier long pc;
303e12c5d1SDavid du Colombier Plink *pp, *p;
313e12c5d1SDavid du Colombier ulong arg;
32e288d156SDavid du Colombier vlong t;
333e12c5d1SDavid du Colombier
343e12c5d1SDavid du Colombier arg = _savearg();
353e12c5d1SDavid du Colombier pc = _callpc(&dummy);
36e288d156SDavid du Colombier pp = _tos->prof.pp;
37e288d156SDavid du Colombier if(pp == 0 || (_tos->prof.pid && _tos->pid != _tos->prof.pid))
383e12c5d1SDavid du Colombier return arg;
393e12c5d1SDavid du Colombier
403e12c5d1SDavid du Colombier for(p=pp->down; p; p=p->link)
413e12c5d1SDavid du Colombier if(p->pc == pc)
423e12c5d1SDavid du Colombier goto out;
43e288d156SDavid du Colombier p = _tos->prof.next + 1;
44e288d156SDavid du Colombier if(p >= _tos->prof.last) {
45e288d156SDavid du Colombier _tos->prof.pp = 0;
467e2bd6dcSDavid du Colombier perr++;
473e12c5d1SDavid du Colombier return arg;
483e12c5d1SDavid du Colombier }
49e288d156SDavid du Colombier _tos->prof.next = p;
503e12c5d1SDavid du Colombier p->link = pp->down;
513e12c5d1SDavid du Colombier pp->down = p;
523e12c5d1SDavid du Colombier p->pc = pc;
533e12c5d1SDavid du Colombier p->old = pp;
543e12c5d1SDavid du Colombier p->down = 0;
553e12c5d1SDavid du Colombier p->count = 0;
56e288d156SDavid du Colombier p->time = 0LL;
573e12c5d1SDavid du Colombier
583e12c5d1SDavid du Colombier out:
59e288d156SDavid du Colombier _tos->prof.pp = p;
603e12c5d1SDavid du Colombier p->count++;
61e288d156SDavid du Colombier switch(_tos->prof.what){
62e288d156SDavid du Colombier case Profkernel:
63e7d29567SDavid du Colombier p->time = p->time - _tos->pcycles;
64e288d156SDavid du Colombier goto proftime;
65e288d156SDavid du Colombier case Profuser:
66e288d156SDavid du Colombier /* Add kernel cycles on proc entry */
67e7d29567SDavid du Colombier p->time = p->time + _tos->kcycles;
68e288d156SDavid du Colombier /* fall through */
69e288d156SDavid du Colombier case Proftime:
70e288d156SDavid du Colombier proftime: /* Subtract cycle counter on proc entry */
71e288d156SDavid du Colombier cycles((uvlong*)&t);
72e7d29567SDavid du Colombier p->time = p->time - t;
73e288d156SDavid du Colombier break;
74e288d156SDavid du Colombier case Profsample:
75e7d29567SDavid du Colombier p->time = p->time - _tos->clock;
76e288d156SDavid du Colombier break;
77e288d156SDavid du Colombier }
783e12c5d1SDavid du Colombier return arg; /* disgusting linkage */
793e12c5d1SDavid du Colombier }
803e12c5d1SDavid du Colombier
813e12c5d1SDavid du Colombier ulong
_profout(void)823e12c5d1SDavid du Colombier _profout(void)
833e12c5d1SDavid du Colombier {
843e12c5d1SDavid du Colombier Plink *p;
853e12c5d1SDavid du Colombier ulong arg;
86e288d156SDavid du Colombier vlong t;
873e12c5d1SDavid du Colombier
883e12c5d1SDavid du Colombier arg = _savearg();
89e288d156SDavid du Colombier p = _tos->prof.pp;
90e288d156SDavid du Colombier if (p == nil || (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid))
91e288d156SDavid du Colombier return arg; /* Not our process */
92e288d156SDavid du Colombier switch(_tos->prof.what){
93e288d156SDavid du Colombier case Profkernel: /* Add proc cycles on proc entry */
94e7d29567SDavid du Colombier p->time = p->time + _tos->pcycles;
95e288d156SDavid du Colombier goto proftime;
96e288d156SDavid du Colombier case Profuser: /* Subtract kernel cycles on proc entry */
97e7d29567SDavid du Colombier p->time = p->time - _tos->kcycles;
98e288d156SDavid du Colombier /* fall through */
99e288d156SDavid du Colombier case Proftime:
100e288d156SDavid du Colombier proftime: /* Add cycle counter on proc entry */
101e288d156SDavid du Colombier cycles((uvlong*)&t);
102e7d29567SDavid du Colombier p->time = p->time + t;
103e288d156SDavid du Colombier break;
104e288d156SDavid du Colombier case Profsample:
105e7d29567SDavid du Colombier p->time = p->time + _tos->clock;
106e288d156SDavid du Colombier break;
1073e12c5d1SDavid du Colombier }
108e288d156SDavid du Colombier _tos->prof.pp = p->old;
1093e12c5d1SDavid du Colombier return arg;
1103e12c5d1SDavid du Colombier }
1113e12c5d1SDavid du Colombier
1123e12c5d1SDavid du Colombier void
_profdump(void)1133e12c5d1SDavid du Colombier _profdump(void)
1143e12c5d1SDavid du Colombier {
1153e12c5d1SDavid du Colombier int f;
1163e12c5d1SDavid du Colombier long n;
1173e12c5d1SDavid du Colombier Plink *p;
1183e12c5d1SDavid du Colombier char *vp;
119e288d156SDavid du Colombier char filename[64];
1203e12c5d1SDavid du Colombier
121e288d156SDavid du Colombier if (_tos->prof.what == 0)
122e288d156SDavid du Colombier return; /* No profiling */
123e288d156SDavid du Colombier if (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid)
124e288d156SDavid du Colombier return; /* Not our process */
1257e2bd6dcSDavid du Colombier if(perr)
1267e2bd6dcSDavid du Colombier fprint(2, "%lud Prof errors\n", perr);
127e288d156SDavid du Colombier _tos->prof.pp = nil;
128e288d156SDavid du Colombier if (_tos->prof.pid)
129e288d156SDavid du Colombier snprint(filename, sizeof filename - 1, "prof.%ld", _tos->prof.pid);
130e288d156SDavid du Colombier else
131e288d156SDavid du Colombier snprint(filename, sizeof filename - 1, "prof.out");
132e288d156SDavid du Colombier f = create(filename, 1, 0666);
1333e12c5d1SDavid du Colombier if(f < 0) {
1343e12c5d1SDavid du Colombier perror("create prof.out");
1353e12c5d1SDavid du Colombier return;
1363e12c5d1SDavid du Colombier }
137e288d156SDavid du Colombier _tos->prof.pid = ~0; /* make sure data gets dumped once */
138e288d156SDavid du Colombier switch(_tos->prof.what){
139e288d156SDavid du Colombier case Profkernel:
140e288d156SDavid du Colombier cycles((uvlong*)&_tos->prof.first->time);
141e7d29567SDavid du Colombier _tos->prof.first->time = _tos->prof.first->time + _tos->pcycles;
142e288d156SDavid du Colombier break;
143e288d156SDavid du Colombier case Profuser:
144e288d156SDavid du Colombier cycles((uvlong*)&_tos->prof.first->time);
1453801c5d3SDavid du Colombier _tos->prof.first->time = _tos->prof.first->time - _tos->kcycles;
146e288d156SDavid du Colombier break;
147e288d156SDavid du Colombier case Proftime:
148e288d156SDavid du Colombier cycles((uvlong*)&_tos->prof.first->time);
149e288d156SDavid du Colombier break;
150e288d156SDavid du Colombier case Profsample:
151e288d156SDavid du Colombier _tos->prof.first->time = _tos->clock;
152e288d156SDavid du Colombier break;
153e288d156SDavid du Colombier }
154e288d156SDavid du Colombier vp = (char*)_tos->prof.first;
155e288d156SDavid du Colombier
156e288d156SDavid du Colombier for(p = _tos->prof.first; p <= _tos->prof.next; p++) {
157e288d156SDavid du Colombier
1583e12c5d1SDavid du Colombier /*
1593e12c5d1SDavid du Colombier * short down
1603e12c5d1SDavid du Colombier */
1613e12c5d1SDavid du Colombier n = 0xffff;
1623e12c5d1SDavid du Colombier if(p->down)
163e288d156SDavid du Colombier n = p->down - _tos->prof.first;
1643e12c5d1SDavid du Colombier vp[0] = n>>8;
1653e12c5d1SDavid du Colombier vp[1] = n;
1663e12c5d1SDavid du Colombier
1673e12c5d1SDavid du Colombier /*
1683e12c5d1SDavid du Colombier * short right
1693e12c5d1SDavid du Colombier */
1703e12c5d1SDavid du Colombier n = 0xffff;
1713e12c5d1SDavid du Colombier if(p->link)
172e288d156SDavid du Colombier n = p->link - _tos->prof.first;
1733e12c5d1SDavid du Colombier vp[2] = n>>8;
1743e12c5d1SDavid du Colombier vp[3] = n;
1753e12c5d1SDavid du Colombier vp += 4;
1763e12c5d1SDavid du Colombier
1773e12c5d1SDavid du Colombier /*
1783e12c5d1SDavid du Colombier * long pc
1793e12c5d1SDavid du Colombier */
1803e12c5d1SDavid du Colombier n = p->pc;
1813e12c5d1SDavid du Colombier vp[0] = n>>24;
1823e12c5d1SDavid du Colombier vp[1] = n>>16;
1833e12c5d1SDavid du Colombier vp[2] = n>>8;
1843e12c5d1SDavid du Colombier vp[3] = n;
1853e12c5d1SDavid du Colombier vp += 4;
1863e12c5d1SDavid du Colombier
1873e12c5d1SDavid du Colombier /*
1883e12c5d1SDavid du Colombier * long count
1893e12c5d1SDavid du Colombier */
1903e12c5d1SDavid du Colombier n = p->count;
1913e12c5d1SDavid du Colombier vp[0] = n>>24;
1923e12c5d1SDavid du Colombier vp[1] = n>>16;
1933e12c5d1SDavid du Colombier vp[2] = n>>8;
1943e12c5d1SDavid du Colombier vp[3] = n;
1953e12c5d1SDavid du Colombier vp += 4;
1963e12c5d1SDavid du Colombier
1973e12c5d1SDavid du Colombier /*
198e288d156SDavid du Colombier * vlong time
1993e12c5d1SDavid du Colombier */
200e288d156SDavid du Colombier if (havecycles){
201e288d156SDavid du Colombier n = (vlong)(p->time / (vlong)khz);
202e288d156SDavid du Colombier }else
203e288d156SDavid du Colombier n = p->time;
204e288d156SDavid du Colombier
2053e12c5d1SDavid du Colombier vp[0] = n>>24;
2063e12c5d1SDavid du Colombier vp[1] = n>>16;
2073e12c5d1SDavid du Colombier vp[2] = n>>8;
2083e12c5d1SDavid du Colombier vp[3] = n;
2093e12c5d1SDavid du Colombier vp += 4;
2103e12c5d1SDavid du Colombier }
211e288d156SDavid du Colombier write(f, (char*)_tos->prof.first, vp - (char*)_tos->prof.first);
2123e12c5d1SDavid du Colombier close(f);
2133e12c5d1SDavid du Colombier }
2143e12c5d1SDavid du Colombier
2153e12c5d1SDavid du Colombier void
_profinit(int entries,int what)216e288d156SDavid du Colombier _profinit(int entries, int what)
217e288d156SDavid du Colombier {
218e288d156SDavid du Colombier if (_tos->prof.what == 0)
219e288d156SDavid du Colombier return; /* Profiling not linked in */
220e288d156SDavid du Colombier _tos->prof.pp = nil;
221e288d156SDavid du Colombier _tos->prof.first = mallocz(entries*sizeof(Plink),1);
222e288d156SDavid du Colombier _tos->prof.last = _tos->prof.first + entries;
223e288d156SDavid du Colombier _tos->prof.next = _tos->prof.first;
224e288d156SDavid du Colombier _tos->prof.pid = _tos->pid;
225e288d156SDavid du Colombier _tos->prof.what = what;
226e288d156SDavid du Colombier _tos->clock = 1;
227e288d156SDavid du Colombier }
228e288d156SDavid du Colombier
229e288d156SDavid du Colombier void
_profmain(void)2303e12c5d1SDavid du Colombier _profmain(void)
2313e12c5d1SDavid du Colombier {
2323e12c5d1SDavid du Colombier char ename[50];
2333e12c5d1SDavid du Colombier int n, f;
2343e12c5d1SDavid du Colombier
2353e12c5d1SDavid du Colombier n = 2000;
236e288d156SDavid du Colombier if (_tos->cyclefreq != 0LL){
237e288d156SDavid du Colombier khz = _tos->cyclefreq / 1000; /* Report times in milliseconds */
238e288d156SDavid du Colombier havecycles = 1;
239e288d156SDavid du Colombier }
2403e12c5d1SDavid du Colombier f = open("/env/profsize", OREAD);
2413e12c5d1SDavid du Colombier if(f >= 0) {
2423e12c5d1SDavid du Colombier memset(ename, 0, sizeof(ename));
2433e12c5d1SDavid du Colombier read(f, ename, sizeof(ename)-1);
2443e12c5d1SDavid du Colombier close(f);
2453e12c5d1SDavid du Colombier n = atol(ename);
2463e12c5d1SDavid du Colombier }
247e288d156SDavid du Colombier _tos->prof.what = Profuser;
248e288d156SDavid du Colombier f = open("/env/proftype", OREAD);
249e288d156SDavid du Colombier if(f >= 0) {
250e288d156SDavid du Colombier memset(ename, 0, sizeof(ename));
251e288d156SDavid du Colombier read(f, ename, sizeof(ename)-1);
252e288d156SDavid du Colombier close(f);
253e288d156SDavid du Colombier if (strcmp(ename, "user") == 0)
254e288d156SDavid du Colombier _tos->prof.what = Profuser;
255e288d156SDavid du Colombier else if (strcmp(ename, "kernel") == 0)
256e288d156SDavid du Colombier _tos->prof.what = Profkernel;
257e288d156SDavid du Colombier else if (strcmp(ename, "elapsed") == 0 || strcmp(ename, "time") == 0)
258e288d156SDavid du Colombier _tos->prof.what = Proftime;
259e288d156SDavid du Colombier else if (strcmp(ename, "sample") == 0)
260e288d156SDavid du Colombier _tos->prof.what = Profsample;
2613e12c5d1SDavid du Colombier }
262e288d156SDavid du Colombier _tos->prof.first = sbrk(n*sizeof(Plink));
263e288d156SDavid du Colombier _tos->prof.last = sbrk(0);
264e288d156SDavid du Colombier _tos->prof.next = _tos->prof.first;
265e288d156SDavid du Colombier _tos->prof.pp = nil;
266e288d156SDavid du Colombier _tos->prof.pid = _tos->pid;
267e288d156SDavid du Colombier atexit(_profdump);
268e288d156SDavid du Colombier _tos->clock = 1;
269e288d156SDavid du Colombier }
270e288d156SDavid du Colombier
271*8c043284SDavid du Colombier void
prof(void (* fn)(void *),void * arg,int entries,int what)272*8c043284SDavid du Colombier prof(void (*fn)(void*), void *arg, int entries, int what)
273e288d156SDavid du Colombier {
274e288d156SDavid du Colombier _profinit(entries, what);
275e288d156SDavid du Colombier _tos->prof.pp = _tos->prof.next;
276e288d156SDavid du Colombier fn(arg);
277e288d156SDavid du Colombier _profdump();
278e288d156SDavid du Colombier }
279e288d156SDavid du Colombier
280e288d156SDavid du Colombier #pragma profile on
281e288d156SDavid du Colombier
282