Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include	<stdio.h>
2
#include	<stdlib.h>
3
#include	<string.h>
4
#include	<unistd.h>
5
#include	<errno.h>
6
#include	<sys/types.h>
7
#include	<fcntl.h>
8
#include	"sys9.h"
9
 
10
enum {
11
	Profoff,			/* No profiling */
12
	Profuser,			/* Measure user time only (default) */
13
	Profkernel,			/* Measure user + kernel time */
14
	Proftime,			/* Measure total time */
15
	Profsample,			/* Use clock interrupt to sample (default when there is no cycle counter) */
16
}; /* what */
17
 
18
typedef long long vlong;
19
typedef unsigned long ulong;
20
typedef unsigned long long uvlong;
21
 
22
#include	"/sys/include/tos.h"
23
 
24
extern	void*	sbrk(ulong);
25
extern	long	_callpc(void**);
26
extern	long	_savearg(void);
27
extern	void	_cycles(uvlong*);	/* 64-bit value of the cycle counter if there is one, 0 if there isn't */
28
 
29
static ulong	khz;
30
static ulong	perr;
31
static int	havecycles;
32
 
33
typedef	struct	Plink	Plink;
34
struct	Plink
35
{
36
	Plink	*old;
37
	Plink	*down;
38
	Plink	*link;
39
	long	pc;
40
	long	count;
41
	vlong	time;
42
};
43
 
44
#pragma profile off
45
 
46
ulong
47
_profin(void)
48
{
49
	void *dummy;
50
	long pc;
51
	Plink *pp, *p;
52
	ulong arg;
53
	vlong t;
54
 
55
	arg = _savearg();
56
	pc = _callpc(&dummy);
57
	pp = _tos->prof.pp;
58
	if(pp == 0 || (_tos->prof.pid && _tos->pid != _tos->prof.pid))
59
		return arg;
60
 
61
	for(p=pp->down; p; p=p->link)
62
		if(p->pc == pc)
63
			goto out;
64
	p = _tos->prof.next + 1;
65
	if(p >= _tos->prof.last){
66
		_tos->prof.pp = 0;
67
		perr++;
68
		return arg;
69
	}
70
	_tos->prof.next = p;
71
	p->link = pp->down;
72
	pp->down = p;
73
	p->pc = pc;
74
	p->old = pp;
75
	p->down = 0;
76
	p->count = 0;
77
	p->time = 0LL;
78
 
79
out:
80
	_tos->prof.pp = p;
81
	p->count++;
82
	switch(_tos->prof.what){
83
	case Profkernel:
84
		p->time = p->time - _tos->pcycles;
85
		goto proftime;
86
	case Profuser:
87
		/* Add kernel cycles on proc entry */
88
		p->time = p->time + _tos->kcycles;
89
		/* fall through */
90
	case Proftime:	
91
	proftime:		/* Subtract cycle counter on proc entry */
92
		_cycles((uvlong*)&t);
93
		p->time = p->time - t;
94
		break;
95
	case Profsample:
96
		p->time = p->time - _tos->clock;
97
		break;
98
	}
99
	return arg;		/* disgusting linkage */
100
}
101
 
102
ulong
103
_profout(void)
104
{
105
	Plink *p;
106
	ulong arg;
107
	vlong t;
108
 
109
	arg = _savearg();
110
	p = _tos->prof.pp;
111
	if (p == NULL || (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid))
112
		return arg;	/* Not our process */
113
	switch(_tos->prof.what){
114
	case Profkernel:		/* Add proc cycles on proc entry */
115
		p->time = p->time + _tos->pcycles;
116
		goto proftime;
117
	case Profuser:			/* Subtract kernel cycles on proc entry */
118
		p->time = p->time - _tos->kcycles;
119
		/* fall through */
120
	case Proftime:	
121
	proftime:				/* Add cycle counter on proc entry */
122
		_cycles((uvlong*)&t);
123
		p->time = p->time + t;
124
		break;
125
	case Profsample:
126
		p->time = p->time + _tos->clock;
127
		break;
128
	}
129
	_tos->prof.pp = p->old;
130
	return arg;
131
}
132
 
133
/* stdio may not be ready for us yet */
134
static void
135
err(char *fmt, ...)
136
{
137
	int fd;
138
	va_list arg;
139
	char buf[128];
140
 
141
	if((fd = open("/dev/cons", OWRITE)) == -1)
142
		return;
143
	va_start(arg, fmt);
144
	/*
145
	 * C99 now requires *snprintf to return the number of characters
146
	 * that *would* have been emitted, had there been room for them,
147
	 * or a negative value on an `encoding error'.  Arrgh!
148
	 */
149
	vsnprintf(buf, sizeof buf, fmt, arg);
150
	va_end(arg);
151
	write(fd, buf, strlen(buf));
152
	close(fd);
153
}
154
 
155
void
156
_profdump(void)
157
{
158
	int f;
159
	long n;
160
	Plink *p;
161
	char *vp;
162
	char filename[64];
163
 
164
	if (_tos->prof.what == 0)
165
		return;	/* No profiling */
166
	if (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid)
167
		return;	/* Not our process */
168
	if(perr)
169
		err("%lud Prof errors\n", perr);
170
	_tos->prof.pp = NULL;
171
	if (_tos->prof.pid)
172
		snprintf(filename, sizeof filename - 1, "prof.%ld", _tos->prof.pid);
173
	else
174
		snprintf(filename, sizeof filename - 1, "prof.out");
175
	f = creat(filename, 0666);
176
	if(f < 0) {
177
		err("%s: cannot create - %s\n", filename, strerror(errno));
178
		return;
179
	}
180
	_tos->prof.pid = ~0;	/* make sure data gets dumped once */
181
	switch(_tos->prof.what){
182
	case Profkernel:
183
		_cycles((uvlong*)&_tos->prof.first->time);
184
		_tos->prof.first->time = _tos->prof.first->time + _tos->pcycles;
185
		break;
186
	case Profuser:
187
		_cycles((uvlong*)&_tos->prof.first->time);
188
		_tos->prof.first->time = _tos->prof.first->time - _tos->kcycles;
189
		break;
190
	case Proftime:
191
		_cycles((uvlong*)&_tos->prof.first->time);
192
		break;
193
	case Profsample:
194
		_tos->prof.first->time = _tos->clock;
195
		break;
196
	}
197
	vp = (char*)_tos->prof.first;
198
 
199
	for(p = _tos->prof.first; p <= _tos->prof.next; p++) {
200
 
201
		/*
202
		 * short down
203
		 */
204
		n = 0xffff;
205
		if(p->down)
206
			n = p->down - _tos->prof.first;
207
		vp[0] = n>>8;
208
		vp[1] = n;
209
 
210
		/*
211
		 * short right
212
		 */
213
		n = 0xffff;
214
		if(p->link)
215
			n = p->link - _tos->prof.first;
216
		vp[2] = n>>8;
217
		vp[3] = n;
218
		vp += 4;
219
 
220
		/*
221
		 * long pc
222
		 */
223
		n = p->pc;
224
		vp[0] = n>>24;
225
		vp[1] = n>>16;
226
		vp[2] = n>>8;
227
		vp[3] = n;
228
		vp += 4;
229
 
230
		/*
231
		 * long count
232
		 */
233
		n = p->count;
234
		vp[0] = n>>24;
235
		vp[1] = n>>16;
236
		vp[2] = n>>8;
237
		vp[3] = n;
238
		vp += 4;
239
 
240
		/*
241
		 * vlong time
242
		 */
243
		if (havecycles){
244
			n = (vlong)(p->time / (vlong)khz);
245
		}else
246
			n = p->time;
247
 
248
		vp[0] = n>>24;
249
		vp[1] = n>>16;
250
		vp[2] = n>>8;
251
		vp[3] = n;
252
		vp += 4;
253
	}
254
	write(f, (char*)_tos->prof.first, vp - (char*)_tos->prof.first);
255
	close(f);
256
 
257
}
258
 
259
void
260
_profinit(int entries, int what)
261
{
262
	if (_tos->prof.what == 0)
263
		return;	/* Profiling not linked in */
264
	_tos->prof.pp = NULL;
265
	_tos->prof.first = calloc(entries*sizeof(Plink),1);
266
	_tos->prof.last = _tos->prof.first + entries;
267
	_tos->prof.next = _tos->prof.first;
268
	_tos->prof.pid = _tos->pid;
269
	_tos->prof.what = what;
270
	_tos->clock = 1;
271
}
272
 
273
void
274
_profmain(void)
275
{
276
	char ename[50];
277
	int n, f;
278
 
279
	n = 2000;
280
	if (_tos->cyclefreq != 0LL){
281
		khz = _tos->cyclefreq / 1000;	/* Report times in milliseconds */
282
		havecycles = 1;
283
	}
284
	f = open("/env/profsize", OREAD);
285
	if(f >= 0) {
286
		memset(ename, 0, sizeof(ename));
287
		read(f, ename, sizeof(ename)-1);
288
		close(f);
289
		n = atol(ename);
290
	}
291
	_tos->prof.what = Profuser;
292
	f = open("/env/proftype", OREAD);
293
	if(f >= 0) {
294
		memset(ename, 0, sizeof(ename));
295
		read(f, ename, sizeof(ename)-1);
296
		close(f);
297
		if (strcmp(ename, "user") == 0)
298
			_tos->prof.what = Profuser;
299
		else if (strcmp(ename, "kernel") == 0)
300
			_tos->prof.what = Profkernel;
301
		else if (strcmp(ename, "elapsed") == 0 || strcmp(ename, "time") == 0)
302
			_tos->prof.what = Proftime;
303
		else if (strcmp(ename, "sample") == 0)
304
			_tos->prof.what = Profsample;
305
	}
306
	_tos->prof.first = sbrk(n*sizeof(Plink));
307
	_tos->prof.last = sbrk(0);
308
	_tos->prof.next = _tos->prof.first;
309
	_tos->prof.pp = NULL;
310
	_tos->prof.pid = _tos->pid;
311
	atexit(_profdump);
312
	_tos->clock = 1;
313
}
314
 
315
void prof(void (*fn)(void*), void *arg, int entries, int what)
316
{
317
	_profinit(entries, what);
318
	_tos->prof.pp = _tos->prof.next;
319
	fn(arg);
320
	_profdump();
321
}
322
 
323
#pragma profile on
324