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