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
_profin(void)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
_profout(void)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
_profdump(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
_profinit(int entries,int what)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
_profmain(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 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