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 n, 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 n = vsnprintf(buf, sizeof(buf), fmt, arg); 145 va_end(arg); 146 write(fd, buf, n); 147 close(fd); 148 } 149 150 void 151 _profdump(void) 152 { 153 int f; 154 long n; 155 Plink *p; 156 char *vp; 157 char filename[64]; 158 159 if (_tos->prof.what == 0) 160 return; /* No profiling */ 161 if (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid) 162 return; /* Not our process */ 163 if(perr) 164 err("%lud Prof errors\n", perr); 165 _tos->prof.pp = NULL; 166 if (_tos->prof.pid) 167 snprintf(filename, sizeof filename - 1, "prof.%ld", _tos->prof.pid); 168 else 169 snprintf(filename, sizeof filename - 1, "prof.out"); 170 f = creat(filename, 0666); 171 if(f < 0) { 172 err("%s: cannot create - %s\n", filename, strerror(errno)); 173 return; 174 } 175 _tos->prof.pid = ~0; /* make sure data gets dumped once */ 176 switch(_tos->prof.what){ 177 case Profkernel: 178 _cycles((uvlong*)&_tos->prof.first->time); 179 _tos->prof.first->time = _tos->prof.first->time + _tos->pcycles; 180 break; 181 case Profuser: 182 _cycles((uvlong*)&_tos->prof.first->time); 183 _tos->prof.first->time = _tos->prof.first->time - _tos->kcycles; 184 break; 185 case Proftime: 186 _cycles((uvlong*)&_tos->prof.first->time); 187 break; 188 case Profsample: 189 _tos->prof.first->time = _tos->clock; 190 break; 191 } 192 vp = (char*)_tos->prof.first; 193 194 for(p = _tos->prof.first; p <= _tos->prof.next; p++) { 195 196 /* 197 * short down 198 */ 199 n = 0xffff; 200 if(p->down) 201 n = p->down - _tos->prof.first; 202 vp[0] = n>>8; 203 vp[1] = n; 204 205 /* 206 * short right 207 */ 208 n = 0xffff; 209 if(p->link) 210 n = p->link - _tos->prof.first; 211 vp[2] = n>>8; 212 vp[3] = n; 213 vp += 4; 214 215 /* 216 * long pc 217 */ 218 n = p->pc; 219 vp[0] = n>>24; 220 vp[1] = n>>16; 221 vp[2] = n>>8; 222 vp[3] = n; 223 vp += 4; 224 225 /* 226 * long count 227 */ 228 n = p->count; 229 vp[0] = n>>24; 230 vp[1] = n>>16; 231 vp[2] = n>>8; 232 vp[3] = n; 233 vp += 4; 234 235 /* 236 * vlong time 237 */ 238 if (havecycles){ 239 n = (vlong)(p->time / (vlong)khz); 240 }else 241 n = p->time; 242 243 vp[0] = n>>24; 244 vp[1] = n>>16; 245 vp[2] = n>>8; 246 vp[3] = n; 247 vp += 4; 248 } 249 write(f, (char*)_tos->prof.first, vp - (char*)_tos->prof.first); 250 close(f); 251 252 } 253 254 void 255 _profinit(int entries, int what) 256 { 257 if (_tos->prof.what == 0) 258 return; /* Profiling not linked in */ 259 _tos->prof.pp = NULL; 260 _tos->prof.first = calloc(entries*sizeof(Plink),1); 261 _tos->prof.last = _tos->prof.first + entries; 262 _tos->prof.next = _tos->prof.first; 263 _tos->prof.pid = _tos->pid; 264 _tos->prof.what = what; 265 _tos->clock = 1; 266 } 267 268 void 269 _profmain(void) 270 { 271 char ename[50]; 272 int n, f; 273 274 n = 2000; 275 if (_tos->cyclefreq != 0LL){ 276 khz = _tos->cyclefreq / 1000; /* Report times in milliseconds */ 277 havecycles = 1; 278 } 279 f = open("/env/profsize", OREAD); 280 if(f >= 0) { 281 memset(ename, 0, sizeof(ename)); 282 read(f, ename, sizeof(ename)-1); 283 close(f); 284 n = atol(ename); 285 } 286 _tos->prof.what = Profuser; 287 f = open("/env/proftype", OREAD); 288 if(f >= 0) { 289 memset(ename, 0, sizeof(ename)); 290 read(f, ename, sizeof(ename)-1); 291 close(f); 292 if (strcmp(ename, "user") == 0) 293 _tos->prof.what = Profuser; 294 else if (strcmp(ename, "kernel") == 0) 295 _tos->prof.what = Profkernel; 296 else if (strcmp(ename, "elapsed") == 0 || strcmp(ename, "time") == 0) 297 _tos->prof.what = Proftime; 298 else if (strcmp(ename, "sample") == 0) 299 _tos->prof.what = Profsample; 300 } 301 _tos->prof.first = sbrk(n*sizeof(Plink)); 302 _tos->prof.last = sbrk(0); 303 _tos->prof.next = _tos->prof.first; 304 _tos->prof.pp = NULL; 305 _tos->prof.pid = _tos->pid; 306 atexit(_profdump); 307 _tos->clock = 1; 308 } 309 310 void prof(void (*fn)(void*), void *arg, int entries, int what) 311 { 312 _profinit(entries, what); 313 _tos->prof.pp = _tos->prof.next; 314 fn(arg); 315 _profdump(); 316 } 317 318 #pragma profile on 319 320