1 #include <u.h> 2 #include <libc.h> 3 #include <tos.h> 4 5 extern long _callpc(void**); 6 extern long _savearg(void); 7 extern void _addv(vlong*,vlong,vlong); 8 extern void _subv(vlong*,vlong,vlong); 9 10 ulong khz; 11 uvlong cyclefreq; 12 int havecycles; 13 14 typedef struct Plink Plink; 15 struct Plink 16 { 17 Plink *old; 18 Plink *down; 19 Plink *link; 20 long pc; 21 long count; 22 vlong time; 23 }; 24 25 #pragma profile off 26 27 ulong 28 _profin(void) 29 { 30 void *dummy; 31 long pc; 32 Plink *pp, *p; 33 ulong arg; 34 vlong t; 35 36 arg = _savearg(); 37 pc = _callpc(&dummy); 38 pp = _tos->prof.pp; 39 if(pp == 0 || (_tos->prof.pid && _tos->pid != _tos->prof.pid)) 40 return arg; 41 42 for(p=pp->down; p; p=p->link) 43 if(p->pc == pc) 44 goto out; 45 p = _tos->prof.next + 1; 46 if(p >= _tos->prof.last) { 47 _tos->prof.pp = 0; 48 return arg; 49 } 50 _tos->prof.next = p; 51 p->link = pp->down; 52 pp->down = p; 53 p->pc = pc; 54 p->old = pp; 55 p->down = 0; 56 p->count = 0; 57 p->time = 0LL; 58 59 out: 60 _tos->prof.pp = p; 61 p->count++; 62 switch(_tos->prof.what){ 63 case Profkernel: 64 _subv(&p->time, p->time, _tos->pcycles); 65 goto proftime; 66 case Profuser: 67 /* Add kernel cycles on proc entry */ 68 _addv(&p->time, p->time, _tos->kcycles); 69 /* fall through */ 70 case Proftime: 71 proftime: /* Subtract cycle counter on proc entry */ 72 cycles((uvlong*)&t); 73 _subv(&p->time, p->time, t); 74 break; 75 case Profsample: 76 _subv(&p->time, p->time, (vlong)_tos->clock); 77 break; 78 } 79 return arg; /* disgusting linkage */ 80 } 81 82 ulong 83 _profout(void) 84 { 85 Plink *p; 86 ulong arg; 87 vlong t; 88 89 arg = _savearg(); 90 p = _tos->prof.pp; 91 if (p == nil || (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid)) 92 return arg; /* Not our process */ 93 switch(_tos->prof.what){ 94 case Profkernel: /* Add proc cycles on proc entry */ 95 _addv(&p->time, p->time, _tos->pcycles); 96 goto proftime; 97 case Profuser: /* Subtract kernel cycles on proc entry */ 98 _subv(&p->time, p->time, _tos->kcycles); 99 /* fall through */ 100 case Proftime: 101 proftime: /* Add cycle counter on proc entry */ 102 cycles((uvlong*)&t); 103 _addv(&p->time, p->time, t); 104 break; 105 case Profsample: 106 _addv(&p->time, p->time, (vlong)_tos->clock); 107 break; 108 } 109 _tos->prof.pp = p->old; 110 return arg; 111 } 112 113 void 114 _profdump(void) 115 { 116 int f; 117 long n; 118 Plink *p; 119 char *vp; 120 char filename[64]; 121 122 if (_tos->prof.what == 0) 123 return; /* No profiling */ 124 if (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid) 125 return; /* Not our process */ 126 _tos->prof.pp = nil; 127 if (_tos->prof.pid) 128 snprint(filename, sizeof filename - 1, "prof.%ld", _tos->prof.pid); 129 else 130 snprint(filename, sizeof filename - 1, "prof.out"); 131 f = create(filename, 1, 0666); 132 if(f < 0) { 133 perror("create prof.out"); 134 return; 135 } 136 _tos->prof.pid = ~0; /* make sure data gets dumped once */ 137 switch(_tos->prof.what){ 138 case Profkernel: 139 cycles((uvlong*)&_tos->prof.first->time); 140 _addv(&_tos->prof.first->time, _tos->prof.first->time, _tos->pcycles); 141 break; 142 case Profuser: 143 cycles((uvlong*)&_tos->prof.first->time); 144 _addv(&_tos->prof.first->time, _tos->prof.first->time, _tos->kcycles); 145 break; 146 case Proftime: 147 cycles((uvlong*)&_tos->prof.first->time); 148 break; 149 case Profsample: 150 _tos->prof.first->time = _tos->clock; 151 break; 152 } 153 vp = (char*)_tos->prof.first; 154 155 for(p = _tos->prof.first; p <= _tos->prof.next; p++) { 156 157 /* 158 * short down 159 */ 160 n = 0xffff; 161 if(p->down) 162 n = p->down - _tos->prof.first; 163 vp[0] = n>>8; 164 vp[1] = n; 165 166 /* 167 * short right 168 */ 169 n = 0xffff; 170 if(p->link) 171 n = p->link - _tos->prof.first; 172 vp[2] = n>>8; 173 vp[3] = n; 174 vp += 4; 175 176 /* 177 * long pc 178 */ 179 n = p->pc; 180 vp[0] = n>>24; 181 vp[1] = n>>16; 182 vp[2] = n>>8; 183 vp[3] = n; 184 vp += 4; 185 186 /* 187 * long count 188 */ 189 n = p->count; 190 vp[0] = n>>24; 191 vp[1] = n>>16; 192 vp[2] = n>>8; 193 vp[3] = n; 194 vp += 4; 195 196 /* 197 * vlong time 198 */ 199 if (havecycles){ 200 n = (vlong)(p->time / (vlong)khz); 201 }else 202 n = p->time; 203 204 vp[0] = n>>24; 205 vp[1] = n>>16; 206 vp[2] = n>>8; 207 vp[3] = n; 208 vp += 4; 209 } 210 write(f, (char*)_tos->prof.first, vp - (char*)_tos->prof.first); 211 close(f); 212 } 213 214 void 215 _profinit(int entries, int what) 216 { 217 if (_tos->prof.what == 0) 218 return; /* Profiling not linked in */ 219 _tos->prof.pp = nil; 220 _tos->prof.first = mallocz(entries*sizeof(Plink),1); 221 _tos->prof.last = _tos->prof.first + entries; 222 _tos->prof.next = _tos->prof.first; 223 _tos->prof.pid = _tos->pid; 224 _tos->prof.what = what; 225 _tos->clock = 1; 226 } 227 228 void 229 _profmain(void) 230 { 231 char ename[50]; 232 int n, f; 233 234 n = 2000; 235 if (_tos->cyclefreq != 0LL){ 236 khz = _tos->cyclefreq / 1000; /* Report times in milliseconds */ 237 havecycles = 1; 238 } 239 f = open("/env/profsize", OREAD); 240 if(f >= 0) { 241 memset(ename, 0, sizeof(ename)); 242 read(f, ename, sizeof(ename)-1); 243 close(f); 244 n = atol(ename); 245 } 246 _tos->prof.what = Profuser; 247 f = open("/env/proftype", OREAD); 248 if(f >= 0) { 249 memset(ename, 0, sizeof(ename)); 250 read(f, ename, sizeof(ename)-1); 251 close(f); 252 if (strcmp(ename, "user") == 0) 253 _tos->prof.what = Profuser; 254 else if (strcmp(ename, "kernel") == 0) 255 _tos->prof.what = Profkernel; 256 else if (strcmp(ename, "elapsed") == 0 || strcmp(ename, "time") == 0) 257 _tos->prof.what = Proftime; 258 else if (strcmp(ename, "sample") == 0) 259 _tos->prof.what = Profsample; 260 } 261 _tos->prof.first = sbrk(n*sizeof(Plink)); 262 _tos->prof.last = sbrk(0); 263 _tos->prof.next = _tos->prof.first; 264 _tos->prof.pp = nil; 265 _tos->prof.pid = _tos->pid; 266 atexit(_profdump); 267 _tos->clock = 1; 268 } 269 270 void prof(void (*fn)(void*), void *arg, int entries, int what) 271 { 272 _profinit(entries, what); 273 _tos->prof.pp = _tos->prof.next; 274 fn(arg); 275 _profdump(); 276 } 277 278 #pragma profile on 279 280