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 8e288d156SDavid du Colombier ulong khz; 9*7e2bd6dcSDavid du Colombier ulong perr; 10e288d156SDavid du Colombier uvlong cyclefreq; 11e288d156SDavid du Colombier int havecycles; 123e12c5d1SDavid du Colombier 133e12c5d1SDavid du Colombier typedef struct Plink Plink; 143e12c5d1SDavid du Colombier struct Plink 153e12c5d1SDavid du Colombier { 16e288d156SDavid du Colombier Plink *old; 173e12c5d1SDavid du Colombier Plink *down; 183e12c5d1SDavid du Colombier Plink *link; 193e12c5d1SDavid du Colombier long pc; 203e12c5d1SDavid du Colombier long count; 21e288d156SDavid du Colombier vlong time; 223e12c5d1SDavid du Colombier }; 233e12c5d1SDavid du Colombier 24e288d156SDavid du Colombier #pragma profile off 253e12c5d1SDavid du Colombier 263e12c5d1SDavid du Colombier ulong 273e12c5d1SDavid du Colombier _profin(void) 283e12c5d1SDavid du Colombier { 293e12c5d1SDavid du Colombier void *dummy; 303e12c5d1SDavid du Colombier long pc; 313e12c5d1SDavid du Colombier Plink *pp, *p; 323e12c5d1SDavid du Colombier ulong arg; 33e288d156SDavid du Colombier vlong t; 343e12c5d1SDavid du Colombier 353e12c5d1SDavid du Colombier arg = _savearg(); 363e12c5d1SDavid du Colombier pc = _callpc(&dummy); 37e288d156SDavid du Colombier pp = _tos->prof.pp; 38e288d156SDavid du Colombier if(pp == 0 || (_tos->prof.pid && _tos->pid != _tos->prof.pid)) 393e12c5d1SDavid du Colombier return arg; 403e12c5d1SDavid du Colombier 413e12c5d1SDavid du Colombier for(p=pp->down; p; p=p->link) 423e12c5d1SDavid du Colombier if(p->pc == pc) 433e12c5d1SDavid du Colombier goto out; 44e288d156SDavid du Colombier p = _tos->prof.next + 1; 45e288d156SDavid du Colombier if(p >= _tos->prof.last) { 46e288d156SDavid du Colombier _tos->prof.pp = 0; 47*7e2bd6dcSDavid du Colombier perr++; 483e12c5d1SDavid du Colombier return arg; 493e12c5d1SDavid du Colombier } 50e288d156SDavid du Colombier _tos->prof.next = p; 513e12c5d1SDavid du Colombier p->link = pp->down; 523e12c5d1SDavid du Colombier pp->down = p; 533e12c5d1SDavid du Colombier p->pc = pc; 543e12c5d1SDavid du Colombier p->old = pp; 553e12c5d1SDavid du Colombier p->down = 0; 563e12c5d1SDavid du Colombier p->count = 0; 57e288d156SDavid du Colombier p->time = 0LL; 583e12c5d1SDavid du Colombier 593e12c5d1SDavid du Colombier out: 60e288d156SDavid du Colombier _tos->prof.pp = p; 613e12c5d1SDavid du Colombier p->count++; 62e288d156SDavid du Colombier switch(_tos->prof.what){ 63e288d156SDavid du Colombier case Profkernel: 64e7d29567SDavid du Colombier p->time = p->time - _tos->pcycles; 65e288d156SDavid du Colombier goto proftime; 66e288d156SDavid du Colombier case Profuser: 67e288d156SDavid du Colombier /* Add kernel cycles on proc entry */ 68e7d29567SDavid du Colombier p->time = p->time + _tos->kcycles; 69e288d156SDavid du Colombier /* fall through */ 70e288d156SDavid du Colombier case Proftime: 71e288d156SDavid du Colombier proftime: /* Subtract cycle counter on proc entry */ 72e288d156SDavid du Colombier cycles((uvlong*)&t); 73e7d29567SDavid du Colombier p->time = p->time - t; 74e288d156SDavid du Colombier break; 75e288d156SDavid du Colombier case Profsample: 76e7d29567SDavid du Colombier p->time = p->time - _tos->clock; 77e288d156SDavid du Colombier break; 78e288d156SDavid du Colombier } 793e12c5d1SDavid du Colombier return arg; /* disgusting linkage */ 803e12c5d1SDavid du Colombier } 813e12c5d1SDavid du Colombier 823e12c5d1SDavid du Colombier ulong 833e12c5d1SDavid du Colombier _profout(void) 843e12c5d1SDavid du Colombier { 853e12c5d1SDavid du Colombier Plink *p; 863e12c5d1SDavid du Colombier ulong arg; 87e288d156SDavid du Colombier vlong t; 883e12c5d1SDavid du Colombier 893e12c5d1SDavid du Colombier arg = _savearg(); 90e288d156SDavid du Colombier p = _tos->prof.pp; 91e288d156SDavid du Colombier if (p == nil || (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid)) 92e288d156SDavid du Colombier return arg; /* Not our process */ 93e288d156SDavid du Colombier switch(_tos->prof.what){ 94e288d156SDavid du Colombier case Profkernel: /* Add proc cycles on proc entry */ 95e7d29567SDavid du Colombier p->time = p->time + _tos->pcycles; 96e288d156SDavid du Colombier goto proftime; 97e288d156SDavid du Colombier case Profuser: /* Subtract kernel cycles on proc entry */ 98e7d29567SDavid du Colombier p->time = p->time - _tos->kcycles; 99e288d156SDavid du Colombier /* fall through */ 100e288d156SDavid du Colombier case Proftime: 101e288d156SDavid du Colombier proftime: /* Add cycle counter on proc entry */ 102e288d156SDavid du Colombier cycles((uvlong*)&t); 103e7d29567SDavid du Colombier p->time = p->time + t; 104e288d156SDavid du Colombier break; 105e288d156SDavid du Colombier case Profsample: 106e7d29567SDavid du Colombier p->time = p->time + _tos->clock; 107e288d156SDavid du Colombier break; 1083e12c5d1SDavid du Colombier } 109e288d156SDavid du Colombier _tos->prof.pp = p->old; 1103e12c5d1SDavid du Colombier return arg; 1113e12c5d1SDavid du Colombier } 1123e12c5d1SDavid du Colombier 1133e12c5d1SDavid du Colombier void 1143e12c5d1SDavid du Colombier _profdump(void) 1153e12c5d1SDavid du Colombier { 1163e12c5d1SDavid du Colombier int f; 1173e12c5d1SDavid du Colombier long n; 1183e12c5d1SDavid du Colombier Plink *p; 1193e12c5d1SDavid du Colombier char *vp; 120e288d156SDavid du Colombier char filename[64]; 1213e12c5d1SDavid du Colombier 122e288d156SDavid du Colombier if (_tos->prof.what == 0) 123e288d156SDavid du Colombier return; /* No profiling */ 124e288d156SDavid du Colombier if (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid) 125e288d156SDavid du Colombier return; /* Not our process */ 126*7e2bd6dcSDavid du Colombier if(perr) 127*7e2bd6dcSDavid du Colombier fprint(2, "%lud Prof errors\n", perr); 128e288d156SDavid du Colombier _tos->prof.pp = nil; 129e288d156SDavid du Colombier if (_tos->prof.pid) 130e288d156SDavid du Colombier snprint(filename, sizeof filename - 1, "prof.%ld", _tos->prof.pid); 131e288d156SDavid du Colombier else 132e288d156SDavid du Colombier snprint(filename, sizeof filename - 1, "prof.out"); 133e288d156SDavid du Colombier f = create(filename, 1, 0666); 1343e12c5d1SDavid du Colombier if(f < 0) { 1353e12c5d1SDavid du Colombier perror("create prof.out"); 1363e12c5d1SDavid du Colombier return; 1373e12c5d1SDavid du Colombier } 138e288d156SDavid du Colombier _tos->prof.pid = ~0; /* make sure data gets dumped once */ 139e288d156SDavid du Colombier switch(_tos->prof.what){ 140e288d156SDavid du Colombier case Profkernel: 141e288d156SDavid du Colombier cycles((uvlong*)&_tos->prof.first->time); 142e7d29567SDavid du Colombier _tos->prof.first->time = _tos->prof.first->time + _tos->pcycles; 143e288d156SDavid du Colombier break; 144e288d156SDavid du Colombier case Profuser: 145e288d156SDavid du Colombier cycles((uvlong*)&_tos->prof.first->time); 146e7d29567SDavid du Colombier _tos->prof.first->time = _tos->prof.first->time + _tos->kcycles; 147e288d156SDavid du Colombier break; 148e288d156SDavid du Colombier case Proftime: 149e288d156SDavid du Colombier cycles((uvlong*)&_tos->prof.first->time); 150e288d156SDavid du Colombier break; 151e288d156SDavid du Colombier case Profsample: 152e288d156SDavid du Colombier _tos->prof.first->time = _tos->clock; 153e288d156SDavid du Colombier break; 154e288d156SDavid du Colombier } 155e288d156SDavid du Colombier vp = (char*)_tos->prof.first; 156e288d156SDavid du Colombier 157e288d156SDavid du Colombier for(p = _tos->prof.first; p <= _tos->prof.next; p++) { 158e288d156SDavid du Colombier 1593e12c5d1SDavid du Colombier /* 1603e12c5d1SDavid du Colombier * short down 1613e12c5d1SDavid du Colombier */ 1623e12c5d1SDavid du Colombier n = 0xffff; 1633e12c5d1SDavid du Colombier if(p->down) 164e288d156SDavid du Colombier n = p->down - _tos->prof.first; 1653e12c5d1SDavid du Colombier vp[0] = n>>8; 1663e12c5d1SDavid du Colombier vp[1] = n; 1673e12c5d1SDavid du Colombier 1683e12c5d1SDavid du Colombier /* 1693e12c5d1SDavid du Colombier * short right 1703e12c5d1SDavid du Colombier */ 1713e12c5d1SDavid du Colombier n = 0xffff; 1723e12c5d1SDavid du Colombier if(p->link) 173e288d156SDavid du Colombier n = p->link - _tos->prof.first; 1743e12c5d1SDavid du Colombier vp[2] = n>>8; 1753e12c5d1SDavid du Colombier vp[3] = n; 1763e12c5d1SDavid du Colombier vp += 4; 1773e12c5d1SDavid du Colombier 1783e12c5d1SDavid du Colombier /* 1793e12c5d1SDavid du Colombier * long pc 1803e12c5d1SDavid du Colombier */ 1813e12c5d1SDavid du Colombier n = p->pc; 1823e12c5d1SDavid du Colombier vp[0] = n>>24; 1833e12c5d1SDavid du Colombier vp[1] = n>>16; 1843e12c5d1SDavid du Colombier vp[2] = n>>8; 1853e12c5d1SDavid du Colombier vp[3] = n; 1863e12c5d1SDavid du Colombier vp += 4; 1873e12c5d1SDavid du Colombier 1883e12c5d1SDavid du Colombier /* 1893e12c5d1SDavid du Colombier * long count 1903e12c5d1SDavid du Colombier */ 1913e12c5d1SDavid du Colombier n = p->count; 1923e12c5d1SDavid du Colombier vp[0] = n>>24; 1933e12c5d1SDavid du Colombier vp[1] = n>>16; 1943e12c5d1SDavid du Colombier vp[2] = n>>8; 1953e12c5d1SDavid du Colombier vp[3] = n; 1963e12c5d1SDavid du Colombier vp += 4; 1973e12c5d1SDavid du Colombier 1983e12c5d1SDavid du Colombier /* 199e288d156SDavid du Colombier * vlong time 2003e12c5d1SDavid du Colombier */ 201e288d156SDavid du Colombier if (havecycles){ 202e288d156SDavid du Colombier n = (vlong)(p->time / (vlong)khz); 203e288d156SDavid du Colombier }else 204e288d156SDavid du Colombier n = p->time; 205e288d156SDavid du Colombier 2063e12c5d1SDavid du Colombier vp[0] = n>>24; 2073e12c5d1SDavid du Colombier vp[1] = n>>16; 2083e12c5d1SDavid du Colombier vp[2] = n>>8; 2093e12c5d1SDavid du Colombier vp[3] = n; 2103e12c5d1SDavid du Colombier vp += 4; 2113e12c5d1SDavid du Colombier } 212e288d156SDavid du Colombier write(f, (char*)_tos->prof.first, vp - (char*)_tos->prof.first); 2133e12c5d1SDavid du Colombier close(f); 2143e12c5d1SDavid du Colombier } 2153e12c5d1SDavid du Colombier 2163e12c5d1SDavid du Colombier void 217e288d156SDavid du Colombier _profinit(int entries, int what) 218e288d156SDavid du Colombier { 219e288d156SDavid du Colombier if (_tos->prof.what == 0) 220e288d156SDavid du Colombier return; /* Profiling not linked in */ 221e288d156SDavid du Colombier _tos->prof.pp = nil; 222e288d156SDavid du Colombier _tos->prof.first = mallocz(entries*sizeof(Plink),1); 223e288d156SDavid du Colombier _tos->prof.last = _tos->prof.first + entries; 224e288d156SDavid du Colombier _tos->prof.next = _tos->prof.first; 225e288d156SDavid du Colombier _tos->prof.pid = _tos->pid; 226e288d156SDavid du Colombier _tos->prof.what = what; 227e288d156SDavid du Colombier _tos->clock = 1; 228e288d156SDavid du Colombier } 229e288d156SDavid du Colombier 230e288d156SDavid du Colombier void 2313e12c5d1SDavid du Colombier _profmain(void) 2323e12c5d1SDavid du Colombier { 2333e12c5d1SDavid du Colombier char ename[50]; 2343e12c5d1SDavid du Colombier int n, f; 2353e12c5d1SDavid du Colombier 2363e12c5d1SDavid du Colombier n = 2000; 237e288d156SDavid du Colombier if (_tos->cyclefreq != 0LL){ 238e288d156SDavid du Colombier khz = _tos->cyclefreq / 1000; /* Report times in milliseconds */ 239e288d156SDavid du Colombier havecycles = 1; 240e288d156SDavid du Colombier } 2413e12c5d1SDavid du Colombier f = open("/env/profsize", OREAD); 2423e12c5d1SDavid du Colombier if(f >= 0) { 2433e12c5d1SDavid du Colombier memset(ename, 0, sizeof(ename)); 2443e12c5d1SDavid du Colombier read(f, ename, sizeof(ename)-1); 2453e12c5d1SDavid du Colombier close(f); 2463e12c5d1SDavid du Colombier n = atol(ename); 2473e12c5d1SDavid du Colombier } 248e288d156SDavid du Colombier _tos->prof.what = Profuser; 249e288d156SDavid du Colombier f = open("/env/proftype", OREAD); 250e288d156SDavid du Colombier if(f >= 0) { 251e288d156SDavid du Colombier memset(ename, 0, sizeof(ename)); 252e288d156SDavid du Colombier read(f, ename, sizeof(ename)-1); 253e288d156SDavid du Colombier close(f); 254e288d156SDavid du Colombier if (strcmp(ename, "user") == 0) 255e288d156SDavid du Colombier _tos->prof.what = Profuser; 256e288d156SDavid du Colombier else if (strcmp(ename, "kernel") == 0) 257e288d156SDavid du Colombier _tos->prof.what = Profkernel; 258e288d156SDavid du Colombier else if (strcmp(ename, "elapsed") == 0 || strcmp(ename, "time") == 0) 259e288d156SDavid du Colombier _tos->prof.what = Proftime; 260e288d156SDavid du Colombier else if (strcmp(ename, "sample") == 0) 261e288d156SDavid du Colombier _tos->prof.what = Profsample; 2623e12c5d1SDavid du Colombier } 263e288d156SDavid du Colombier _tos->prof.first = sbrk(n*sizeof(Plink)); 264e288d156SDavid du Colombier _tos->prof.last = sbrk(0); 265e288d156SDavid du Colombier _tos->prof.next = _tos->prof.first; 266e288d156SDavid du Colombier _tos->prof.pp = nil; 267e288d156SDavid du Colombier _tos->prof.pid = _tos->pid; 268e288d156SDavid du Colombier atexit(_profdump); 269e288d156SDavid du Colombier _tos->clock = 1; 270e288d156SDavid du Colombier } 271e288d156SDavid du Colombier 272e288d156SDavid du Colombier void 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