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