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