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