1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <unistd.h> 5 #include <errno.h> 6 #include <sys/types.h> 7 #include <fcntl.h> 8 #include "sys9.h" 9 10 enum { 11 Profoff, /* No profiling */ 12 Profuser, /* Measure user time only (default) */ 13 Profkernel, /* Measure user + kernel time */ 14 Proftime, /* Measure total time */ 15 Profsample, /* Use clock interrupt to sample (default when there is no cycle counter) */ 16 }; /* what */ 17 18 typedef long long vlong; 19 typedef unsigned long ulong; 20 typedef unsigned long long uvlong; 21 22 #include "/sys/include/tos.h" 23 24 extern void* sbrk(ulong); 25 extern long _callpc(void**); 26 extern long _savearg(void); 27 extern void _cycles(uvlong*); /* 64-bit value of the cycle counter if there is one, 0 if there isn't */ 28 29 static ulong khz; 30 static ulong perr; 31 static int havecycles; 32 33 typedef struct Plink Plink; 34 struct Plink 35 { 36 Plink *old; 37 Plink *down; 38 Plink *link; 39 long pc; 40 long count; 41 vlong time; 42 }; 43 44 #pragma profile off 45 46 ulong 47 _profin(void) 48 { 49 void *dummy; 50 long pc; 51 Plink *pp, *p; 52 ulong arg; 53 vlong t; 54 55 arg = _savearg(); 56 pc = _callpc(&dummy); 57 pp = _tos->prof.pp; 58 if(pp == 0 || (_tos->prof.pid && _tos->pid != _tos->prof.pid)) 59 return arg; 60 61 for(p=pp->down; p; p=p->link) 62 if(p->pc == pc) 63 goto out; 64 p = _tos->prof.next + 1; 65 if(p >= _tos->prof.last){ 66 _tos->prof.pp = 0; 67 perr++; 68 return arg; 69 } 70 _tos->prof.next = p; 71 p->link = pp->down; 72 pp->down = p; 73 p->pc = pc; 74 p->old = pp; 75 p->down = 0; 76 p->count = 0; 77 p->time = 0LL; 78 79 out: 80 _tos->prof.pp = p; 81 p->count++; 82 switch(_tos->prof.what){ 83 case Profkernel: 84 p->time = p->time - _tos->pcycles; 85 goto proftime; 86 case Profuser: 87 /* Add kernel cycles on proc entry */ 88 p->time = p->time + _tos->kcycles; 89 /* fall through */ 90 case Proftime: 91 proftime: /* Subtract cycle counter on proc entry */ 92 _cycles((uvlong*)&t); 93 p->time = p->time - t; 94 break; 95 case Profsample: 96 p->time = p->time - _tos->clock; 97 break; 98 } 99 return arg; /* disgusting linkage */ 100 } 101 102 ulong 103 _profout(void) 104 { 105 Plink *p; 106 ulong arg; 107 vlong t; 108 109 arg = _savearg(); 110 p = _tos->prof.pp; 111 if (p == NULL || (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid)) 112 return arg; /* Not our process */ 113 switch(_tos->prof.what){ 114 case Profkernel: /* Add proc cycles on proc entry */ 115 p->time = p->time + _tos->pcycles; 116 goto proftime; 117 case Profuser: /* Subtract kernel cycles on proc entry */ 118 p->time = p->time - _tos->kcycles; 119 /* fall through */ 120 case Proftime: 121 proftime: /* Add cycle counter on proc entry */ 122 _cycles((uvlong*)&t); 123 p->time = p->time + t; 124 break; 125 case Profsample: 126 p->time = p->time + _tos->clock; 127 break; 128 } 129 _tos->prof.pp = p->old; 130 return arg; 131 } 132 133 /* stdio may not be ready for us yet */ 134 static void 135 err(char *fmt, ...) 136 { 137 int fd; 138 va_list arg; 139 char buf[128]; 140 141 if((fd = open("/dev/cons", OWRITE)) == -1) 142 return; 143 va_start(arg, fmt); 144 /* 145 * C99 now requires *snprintf to return the number of characters 146 * that *would* have been emitted, had there been room for them, 147 * or a negative value on an `encoding error'. Arrgh! 148 */ 149 vsnprintf(buf, sizeof buf, fmt, arg); 150 va_end(arg); 151 write(fd, buf, strlen(buf)); 152 close(fd); 153 } 154 155 void 156 _profdump(void) 157 { 158 int f; 159 long n; 160 Plink *p; 161 char *vp; 162 char filename[64]; 163 164 if (_tos->prof.what == 0) 165 return; /* No profiling */ 166 if (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid) 167 return; /* Not our process */ 168 if(perr) 169 err("%lud Prof errors\n", perr); 170 _tos->prof.pp = NULL; 171 if (_tos->prof.pid) 172 snprintf(filename, sizeof filename - 1, "prof.%ld", _tos->prof.pid); 173 else 174 snprintf(filename, sizeof filename - 1, "prof.out"); 175 f = creat(filename, 0666); 176 if(f < 0) { 177 err("%s: cannot create - %s\n", filename, strerror(errno)); 178 return; 179 } 180 _tos->prof.pid = ~0; /* make sure data gets dumped once */ 181 switch(_tos->prof.what){ 182 case Profkernel: 183 _cycles((uvlong*)&_tos->prof.first->time); 184 _tos->prof.first->time = _tos->prof.first->time + _tos->pcycles; 185 break; 186 case Profuser: 187 _cycles((uvlong*)&_tos->prof.first->time); 188 _tos->prof.first->time = _tos->prof.first->time - _tos->kcycles; 189 break; 190 case Proftime: 191 _cycles((uvlong*)&_tos->prof.first->time); 192 break; 193 case Profsample: 194 _tos->prof.first->time = _tos->clock; 195 break; 196 } 197 vp = (char*)_tos->prof.first; 198 199 for(p = _tos->prof.first; p <= _tos->prof.next; p++) { 200 201 /* 202 * short down 203 */ 204 n = 0xffff; 205 if(p->down) 206 n = p->down - _tos->prof.first; 207 vp[0] = n>>8; 208 vp[1] = n; 209 210 /* 211 * short right 212 */ 213 n = 0xffff; 214 if(p->link) 215 n = p->link - _tos->prof.first; 216 vp[2] = n>>8; 217 vp[3] = n; 218 vp += 4; 219 220 /* 221 * long pc 222 */ 223 n = p->pc; 224 vp[0] = n>>24; 225 vp[1] = n>>16; 226 vp[2] = n>>8; 227 vp[3] = n; 228 vp += 4; 229 230 /* 231 * long count 232 */ 233 n = p->count; 234 vp[0] = n>>24; 235 vp[1] = n>>16; 236 vp[2] = n>>8; 237 vp[3] = n; 238 vp += 4; 239 240 /* 241 * vlong time 242 */ 243 if (havecycles){ 244 n = (vlong)(p->time / (vlong)khz); 245 }else 246 n = p->time; 247 248 vp[0] = n>>24; 249 vp[1] = n>>16; 250 vp[2] = n>>8; 251 vp[3] = n; 252 vp += 4; 253 } 254 write(f, (char*)_tos->prof.first, vp - (char*)_tos->prof.first); 255 close(f); 256 257 } 258 259 void 260 _profinit(int entries, int what) 261 { 262 if (_tos->prof.what == 0) 263 return; /* Profiling not linked in */ 264 _tos->prof.pp = NULL; 265 _tos->prof.first = calloc(entries*sizeof(Plink),1); 266 _tos->prof.last = _tos->prof.first + entries; 267 _tos->prof.next = _tos->prof.first; 268 _tos->prof.pid = _tos->pid; 269 _tos->prof.what = what; 270 _tos->clock = 1; 271 } 272 273 void 274 _profmain(void) 275 { 276 char ename[50]; 277 int n, f; 278 279 n = 2000; 280 if (_tos->cyclefreq != 0LL){ 281 khz = _tos->cyclefreq / 1000; /* Report times in milliseconds */ 282 havecycles = 1; 283 } 284 f = open("/env/profsize", OREAD); 285 if(f >= 0) { 286 memset(ename, 0, sizeof(ename)); 287 read(f, ename, sizeof(ename)-1); 288 close(f); 289 n = atol(ename); 290 } 291 _tos->prof.what = Profuser; 292 f = open("/env/proftype", OREAD); 293 if(f >= 0) { 294 memset(ename, 0, sizeof(ename)); 295 read(f, ename, sizeof(ename)-1); 296 close(f); 297 if (strcmp(ename, "user") == 0) 298 _tos->prof.what = Profuser; 299 else if (strcmp(ename, "kernel") == 0) 300 _tos->prof.what = Profkernel; 301 else if (strcmp(ename, "elapsed") == 0 || strcmp(ename, "time") == 0) 302 _tos->prof.what = Proftime; 303 else if (strcmp(ename, "sample") == 0) 304 _tos->prof.what = Profsample; 305 } 306 _tos->prof.first = sbrk(n*sizeof(Plink)); 307 _tos->prof.last = sbrk(0); 308 _tos->prof.next = _tos->prof.first; 309 _tos->prof.pp = NULL; 310 _tos->prof.pid = _tos->pid; 311 atexit(_profdump); 312 _tos->clock = 1; 313 } 314 315 void prof(void (*fn)(void*), void *arg, int entries, int what) 316 { 317 _profinit(entries, what); 318 _tos->prof.pp = _tos->prof.next; 319 fn(arg); 320 _profdump(); 321 } 322 323 #pragma profile on 324 325