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