xref: /plan9/sys/src/libc/port/profile.c (revision 8c04328423b2322742bda0a2bec3fb1145ef1037)
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