1 #include <u.h> 2 #include <libc.h> 3 #include <tos.h> 4 5 extern long _callpc(void**); 6 extern long _savearg(void); 7 8 ulong khz; 9 ulong perr; 10 uvlong cyclefreq; 11 int havecycles; 12 13 typedef struct Plink Plink; 14 struct Plink 15 { 16 Plink *old; 17 Plink *down; 18 Plink *link; 19 long pc; 20 long count; 21 vlong time; 22 }; 23 24 #pragma profile off 25 26 ulong 27 _profin(void) 28 { 29 void *dummy; 30 long pc; 31 Plink *pp, *p; 32 ulong arg; 33 vlong t; 34 35 arg = _savearg(); 36 pc = _callpc(&dummy); 37 pp = _tos->prof.pp; 38 if(pp == 0 || (_tos->prof.pid && _tos->pid != _tos->prof.pid)) 39 return arg; 40 41 for(p=pp->down; p; p=p->link) 42 if(p->pc == pc) 43 goto out; 44 p = _tos->prof.next + 1; 45 if(p >= _tos->prof.last) { 46 _tos->prof.pp = 0; 47 perr++; 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 p->time = p->time - _tos->pcycles; 65 goto proftime; 66 case Profuser: 67 /* Add kernel cycles on proc entry */ 68 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 p->time = p->time - t; 74 break; 75 case Profsample: 76 p->time = p->time - _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 p->time = p->time + _tos->pcycles; 96 goto proftime; 97 case Profuser: /* Subtract kernel cycles on proc entry */ 98 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 p->time = p->time + t; 104 break; 105 case Profsample: 106 p->time = p->time + _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 if(perr) 127 fprint(2, "%lud Prof errors\n", perr); 128 _tos->prof.pp = nil; 129 if (_tos->prof.pid) 130 snprint(filename, sizeof filename - 1, "prof.%ld", _tos->prof.pid); 131 else 132 snprint(filename, sizeof filename - 1, "prof.out"); 133 f = create(filename, 1, 0666); 134 if(f < 0) { 135 perror("create prof.out"); 136 return; 137 } 138 _tos->prof.pid = ~0; /* make sure data gets dumped once */ 139 switch(_tos->prof.what){ 140 case Profkernel: 141 cycles((uvlong*)&_tos->prof.first->time); 142 _tos->prof.first->time = _tos->prof.first->time + _tos->pcycles; 143 break; 144 case Profuser: 145 cycles((uvlong*)&_tos->prof.first->time); 146 _tos->prof.first->time = _tos->prof.first->time + _tos->kcycles; 147 break; 148 case Proftime: 149 cycles((uvlong*)&_tos->prof.first->time); 150 break; 151 case Profsample: 152 _tos->prof.first->time = _tos->clock; 153 break; 154 } 155 vp = (char*)_tos->prof.first; 156 157 for(p = _tos->prof.first; p <= _tos->prof.next; p++) { 158 159 /* 160 * short down 161 */ 162 n = 0xffff; 163 if(p->down) 164 n = p->down - _tos->prof.first; 165 vp[0] = n>>8; 166 vp[1] = n; 167 168 /* 169 * short right 170 */ 171 n = 0xffff; 172 if(p->link) 173 n = p->link - _tos->prof.first; 174 vp[2] = n>>8; 175 vp[3] = n; 176 vp += 4; 177 178 /* 179 * long pc 180 */ 181 n = p->pc; 182 vp[0] = n>>24; 183 vp[1] = n>>16; 184 vp[2] = n>>8; 185 vp[3] = n; 186 vp += 4; 187 188 /* 189 * long count 190 */ 191 n = p->count; 192 vp[0] = n>>24; 193 vp[1] = n>>16; 194 vp[2] = n>>8; 195 vp[3] = n; 196 vp += 4; 197 198 /* 199 * vlong time 200 */ 201 if (havecycles){ 202 n = (vlong)(p->time / (vlong)khz); 203 }else 204 n = p->time; 205 206 vp[0] = n>>24; 207 vp[1] = n>>16; 208 vp[2] = n>>8; 209 vp[3] = n; 210 vp += 4; 211 } 212 write(f, (char*)_tos->prof.first, vp - (char*)_tos->prof.first); 213 close(f); 214 } 215 216 void 217 _profinit(int entries, int what) 218 { 219 if (_tos->prof.what == 0) 220 return; /* Profiling not linked in */ 221 _tos->prof.pp = nil; 222 _tos->prof.first = mallocz(entries*sizeof(Plink),1); 223 _tos->prof.last = _tos->prof.first + entries; 224 _tos->prof.next = _tos->prof.first; 225 _tos->prof.pid = _tos->pid; 226 _tos->prof.what = what; 227 _tos->clock = 1; 228 } 229 230 void 231 _profmain(void) 232 { 233 char ename[50]; 234 int n, f; 235 236 n = 2000; 237 if (_tos->cyclefreq != 0LL){ 238 khz = _tos->cyclefreq / 1000; /* Report times in milliseconds */ 239 havecycles = 1; 240 } 241 f = open("/env/profsize", OREAD); 242 if(f >= 0) { 243 memset(ename, 0, sizeof(ename)); 244 read(f, ename, sizeof(ename)-1); 245 close(f); 246 n = atol(ename); 247 } 248 _tos->prof.what = Profuser; 249 f = open("/env/proftype", OREAD); 250 if(f >= 0) { 251 memset(ename, 0, sizeof(ename)); 252 read(f, ename, sizeof(ename)-1); 253 close(f); 254 if (strcmp(ename, "user") == 0) 255 _tos->prof.what = Profuser; 256 else if (strcmp(ename, "kernel") == 0) 257 _tos->prof.what = Profkernel; 258 else if (strcmp(ename, "elapsed") == 0 || strcmp(ename, "time") == 0) 259 _tos->prof.what = Proftime; 260 else if (strcmp(ename, "sample") == 0) 261 _tos->prof.what = Profsample; 262 } 263 _tos->prof.first = sbrk(n*sizeof(Plink)); 264 _tos->prof.last = sbrk(0); 265 _tos->prof.next = _tos->prof.first; 266 _tos->prof.pp = nil; 267 _tos->prof.pid = _tos->pid; 268 atexit(_profdump); 269 _tos->clock = 1; 270 } 271 272 void prof(void (*fn)(void*), void *arg, int entries, int what) 273 { 274 _profinit(entries, what); 275 _tos->prof.pp = _tos->prof.next; 276 fn(arg); 277 _profdump(); 278 } 279 280 #pragma profile on 281 282