xref: /minix3/minix/commands/profile/profile.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /* profile - profile operating system
2*433d6423SLionel Sambuc  *
3*433d6423SLionel Sambuc  * The profile command is used to control Statistical and Call Profiling.
4*433d6423SLionel Sambuc  * It writes the profiling data collected by the kernel to a file.
5*433d6423SLionel Sambuc  *
6*433d6423SLionel Sambuc  * Changes:
7*433d6423SLionel Sambuc  *   14 Aug, 2006   Created (Rogier Meurs)
8*433d6423SLionel Sambuc  */
9*433d6423SLionel Sambuc 
10*433d6423SLionel Sambuc #include <errno.h>
11*433d6423SLionel Sambuc #include <fcntl.h>
12*433d6423SLionel Sambuc #include <stdio.h>
13*433d6423SLionel Sambuc #include <stdlib.h>
14*433d6423SLionel Sambuc #include <string.h>
15*433d6423SLionel Sambuc #include <unistd.h>
16*433d6423SLionel Sambuc #include <sys/stat.h>
17*433d6423SLionel Sambuc #undef SPROFILE
18*433d6423SLionel Sambuc #define SPROFILE 1
19*433d6423SLionel Sambuc #include <minix/profile.h>
20*433d6423SLionel Sambuc 
21*433d6423SLionel Sambuc #define EHELP			1
22*433d6423SLionel Sambuc #define ESYNTAX			2
23*433d6423SLionel Sambuc #define EMEM			3
24*433d6423SLionel Sambuc #define EOUTFILE		4
25*433d6423SLionel Sambuc #define EFREQ			5
26*433d6423SLionel Sambuc #define EACTION			6
27*433d6423SLionel Sambuc 
28*433d6423SLionel Sambuc #define START			1
29*433d6423SLionel Sambuc #define STOP			2
30*433d6423SLionel Sambuc #define GET			3
31*433d6423SLionel Sambuc #define RESET			4
32*433d6423SLionel Sambuc 
33*433d6423SLionel Sambuc #define SPROF			(action==START||action==STOP)
34*433d6423SLionel Sambuc #define CPROF			(!SPROF)
35*433d6423SLionel Sambuc #define DEF_OUTFILE_S		"profile.stat.out"
36*433d6423SLionel Sambuc #define DEF_OUTFILE_C		"profile.call.out"
37*433d6423SLionel Sambuc #define DEF_OUTFILE		(SPROF?DEF_OUTFILE_S:DEF_OUTFILE_C)
38*433d6423SLionel Sambuc #define NPIPE			"/tmp/profile.npipe"
39*433d6423SLionel Sambuc #define MIN_MEMSIZE		1
40*433d6423SLionel Sambuc #define DEF_MEMSIZE		64
41*433d6423SLionel Sambuc #define MIN_FREQ		3
42*433d6423SLionel Sambuc #define MAX_FREQ		15
43*433d6423SLionel Sambuc #define DEF_FREQ		6
44*433d6423SLionel Sambuc #define BUFSIZE			1024
45*433d6423SLionel Sambuc #define MB			(1024*1024)
46*433d6423SLionel Sambuc #define SYNCING			"SYNC"
47*433d6423SLionel Sambuc #define DEV_LOG			"/dev/log"
48*433d6423SLionel Sambuc 
49*433d6423SLionel Sambuc int action = 0;
50*433d6423SLionel Sambuc int mem_size = 0;
51*433d6423SLionel Sambuc int mem_used = 0;
52*433d6423SLionel Sambuc int freq = 0;
53*433d6423SLionel Sambuc int intr_type = PROF_RTC;
54*433d6423SLionel Sambuc char *outfile = "";
55*433d6423SLionel Sambuc char *mem_ptr;
56*433d6423SLionel Sambuc int outfile_fd, npipe_fd;
57*433d6423SLionel Sambuc struct sprof_info_s sprof_info;
58*433d6423SLionel Sambuc struct cprof_info_s cprof_info;
59*433d6423SLionel Sambuc 
60*433d6423SLionel Sambuc #define HASH_MOD	128
61*433d6423SLionel Sambuc struct sproc {
62*433d6423SLionel Sambuc 	endpoint_t	ep;
63*433d6423SLionel Sambuc 	char		name[8];
64*433d6423SLionel Sambuc 	struct sproc *	next;
65*433d6423SLionel Sambuc };
66*433d6423SLionel Sambuc 
67*433d6423SLionel Sambuc static struct sproc * proc_hash[HASH_MOD];
68*433d6423SLionel Sambuc 
69*433d6423SLionel Sambuc int handle_args(int argc, char *argv[]);
70*433d6423SLionel Sambuc int start(void);
71*433d6423SLionel Sambuc int stop(void);
72*433d6423SLionel Sambuc int get(void);
73*433d6423SLionel Sambuc int reset(void);
74*433d6423SLionel Sambuc int create_named_pipe(void);
75*433d6423SLionel Sambuc int alloc_mem(void);
76*433d6423SLionel Sambuc int init_outfile(void);
77*433d6423SLionel Sambuc int write_outfile(void);
78*433d6423SLionel Sambuc int write_outfile_cprof(void);
79*433d6423SLionel Sambuc int write_outfile_sprof(void);
80*433d6423SLionel Sambuc void detach(void);
81*433d6423SLionel Sambuc 
82*433d6423SLionel Sambuc int main(int argc, char *argv[])
83*433d6423SLionel Sambuc {
84*433d6423SLionel Sambuc   int res;
85*433d6423SLionel Sambuc 
86*433d6423SLionel Sambuc   if ((res = handle_args(argc, argv))) {
87*433d6423SLionel Sambuc 	switch(res) {
88*433d6423SLionel Sambuc 		case ESYNTAX:
89*433d6423SLionel Sambuc 			printf("Error in parameters.\n");
90*433d6423SLionel Sambuc 			return 1;
91*433d6423SLionel Sambuc 			break;
92*433d6423SLionel Sambuc 		case EACTION:
93*433d6423SLionel Sambuc 			printf("Specify one of start|stop|get|reset.\n");
94*433d6423SLionel Sambuc 			return 1;
95*433d6423SLionel Sambuc 			break;
96*433d6423SLionel Sambuc 		case EMEM:
97*433d6423SLionel Sambuc 			printf("Incorrect memory size.\n");
98*433d6423SLionel Sambuc 			return 1;
99*433d6423SLionel Sambuc 			break;
100*433d6423SLionel Sambuc 		case EFREQ:
101*433d6423SLionel Sambuc 			printf("Incorrect frequency.\n");
102*433d6423SLionel Sambuc 			return 1;
103*433d6423SLionel Sambuc 			break;
104*433d6423SLionel Sambuc 		case EOUTFILE:
105*433d6423SLionel Sambuc 			printf("Output filename missing.\n");
106*433d6423SLionel Sambuc 			return 1;
107*433d6423SLionel Sambuc 			break;
108*433d6423SLionel Sambuc 		default:
109*433d6423SLionel Sambuc 			break;
110*433d6423SLionel Sambuc 	}
111*433d6423SLionel Sambuc 
112*433d6423SLionel Sambuc 	/*
113*433d6423SLionel Sambuc 	 * Check the frequency when we know the intr type. Only selected values
114*433d6423SLionel Sambuc 	 * are correct for RTC
115*433d6423SLionel Sambuc 	 */
116*433d6423SLionel Sambuc 	if (action == START && intr_type == PROF_RTC &&
117*433d6423SLionel Sambuc 			(freq < MIN_FREQ || freq > MAX_FREQ)) {
118*433d6423SLionel Sambuc 		printf("Incorrect frequency.\n");
119*433d6423SLionel Sambuc 		return 1;
120*433d6423SLionel Sambuc 	}
121*433d6423SLionel Sambuc 
122*433d6423SLionel Sambuc         printf("Statistical Profiling:\n");
123*433d6423SLionel Sambuc 	printf("  profile start [--rtc | --nmi] "
124*433d6423SLionel Sambuc 			"[-m memsize] [-o outfile] [-f frequency]\n");
125*433d6423SLionel Sambuc         printf("  profile stop\n\n");
126*433d6423SLionel Sambuc 	printf("   --rtc is default, --nmi allows kernel profiling\n");
127*433d6423SLionel Sambuc         printf("Call Profiling:\n");
128*433d6423SLionel Sambuc 	printf("  profile get   [-m memsize] [-o outfile]\n");
129*433d6423SLionel Sambuc         printf("  profile reset\n\n");
130*433d6423SLionel Sambuc 	printf("   - memsize in MB, default: %u\n", DEF_MEMSIZE);
131*433d6423SLionel Sambuc 	printf("   - default output file: profile.{stat|call}.out\n");
132*433d6423SLionel Sambuc 	printf( "   - sample frequencies for --rtc (default: %u):\n", DEF_FREQ);
133*433d6423SLionel Sambuc 	printf("      3    8192 Hz          10     64 Hz\n");
134*433d6423SLionel Sambuc 	printf("      4    4096 Hz          11     32 Hz\n");
135*433d6423SLionel Sambuc 	printf("      5    2048 Hz          12     16 Hz\n");
136*433d6423SLionel Sambuc 	printf("      6    1024 Hz          13      8 Hz\n");
137*433d6423SLionel Sambuc 	printf("      7     512 Hz          14      4 Hz\n");
138*433d6423SLionel Sambuc 	printf("      8     256 Hz          15      2 Hz\n");
139*433d6423SLionel Sambuc 	printf("      9     128 Hz\n\n");
140*433d6423SLionel Sambuc 	printf("Use [sc]profalyze.pl to analyze output file.\n");
141*433d6423SLionel Sambuc 	return 1;
142*433d6423SLionel Sambuc   }
143*433d6423SLionel Sambuc 
144*433d6423SLionel Sambuc   switch(action) {
145*433d6423SLionel Sambuc 	  case START:
146*433d6423SLionel Sambuc 	  	if (start()) return 1;
147*433d6423SLionel Sambuc 		break;
148*433d6423SLionel Sambuc 	  case STOP:
149*433d6423SLionel Sambuc 	  	if (stop()) return 1;
150*433d6423SLionel Sambuc 		break;
151*433d6423SLionel Sambuc 	  case GET:
152*433d6423SLionel Sambuc 	  	if (get()) return 1;
153*433d6423SLionel Sambuc 		break;
154*433d6423SLionel Sambuc 	  case RESET:
155*433d6423SLionel Sambuc 	  	if (reset()) return 1;
156*433d6423SLionel Sambuc 		break;
157*433d6423SLionel Sambuc 	  default:
158*433d6423SLionel Sambuc 		break;
159*433d6423SLionel Sambuc   }
160*433d6423SLionel Sambuc   return 0;
161*433d6423SLionel Sambuc }
162*433d6423SLionel Sambuc 
163*433d6423SLionel Sambuc 
164*433d6423SLionel Sambuc int handle_args(int argc, char *argv[])
165*433d6423SLionel Sambuc {
166*433d6423SLionel Sambuc   while (--argc) {
167*433d6423SLionel Sambuc 	++argv;
168*433d6423SLionel Sambuc 
169*433d6423SLionel Sambuc 	if (strcmp(*argv, "-h") == 0 || strcmp(*argv, "help") == 0 ||
170*433d6423SLionel Sambuc 		strcmp(*argv, "--help") == 0) {
171*433d6423SLionel Sambuc 		return EHELP;
172*433d6423SLionel Sambuc 	} else
173*433d6423SLionel Sambuc 	if (strcmp(*argv, "-m") == 0) {
174*433d6423SLionel Sambuc 		if (--argc == 0) return ESYNTAX;
175*433d6423SLionel Sambuc 		if (sscanf(*++argv, "%u", &mem_size) != 1 ||
176*433d6423SLionel Sambuc 			mem_size < MIN_MEMSIZE ) return EMEM;
177*433d6423SLionel Sambuc 	} else
178*433d6423SLionel Sambuc 	if (strcmp(*argv, "-f") == 0) {
179*433d6423SLionel Sambuc 		if (--argc == 0) return ESYNTAX;
180*433d6423SLionel Sambuc 		if (sscanf(*++argv, "%u", &freq) != 1)
181*433d6423SLionel Sambuc 			return EFREQ;
182*433d6423SLionel Sambuc 	} else
183*433d6423SLionel Sambuc 	if (strcmp(*argv, "-o") == 0) {
184*433d6423SLionel Sambuc 		if (--argc == 0) return ESYNTAX;
185*433d6423SLionel Sambuc 		outfile = *++argv;
186*433d6423SLionel Sambuc 	} else
187*433d6423SLionel Sambuc 	if (strcmp(*argv, "--rtc") == 0) {
188*433d6423SLionel Sambuc 		intr_type = PROF_RTC;
189*433d6423SLionel Sambuc 	} else
190*433d6423SLionel Sambuc 	if (strcmp(*argv, "--nmi") == 0) {
191*433d6423SLionel Sambuc 		intr_type = PROF_NMI;
192*433d6423SLionel Sambuc 	} else
193*433d6423SLionel Sambuc 	if (strcmp(*argv, "start") == 0) {
194*433d6423SLionel Sambuc 		if (action) return EACTION;
195*433d6423SLionel Sambuc 	       	action = START;
196*433d6423SLionel Sambuc 	} else
197*433d6423SLionel Sambuc 	if (strcmp(*argv, "stop") == 0) {
198*433d6423SLionel Sambuc 		if (action) return EACTION;
199*433d6423SLionel Sambuc 	       	action = STOP;
200*433d6423SLionel Sambuc 	} else
201*433d6423SLionel Sambuc 	if (strcmp(*argv, "get") == 0) {
202*433d6423SLionel Sambuc 		if (action) return EACTION;
203*433d6423SLionel Sambuc 	       	action = GET;
204*433d6423SLionel Sambuc 	} else
205*433d6423SLionel Sambuc 	if (strcmp(*argv, "reset") == 0) {
206*433d6423SLionel Sambuc 		if (action) return EACTION;
207*433d6423SLionel Sambuc 	       	action = RESET;
208*433d6423SLionel Sambuc 	}
209*433d6423SLionel Sambuc   }
210*433d6423SLionel Sambuc 
211*433d6423SLionel Sambuc   /* No action specified. */
212*433d6423SLionel Sambuc   if (!action) return EHELP;
213*433d6423SLionel Sambuc 
214*433d6423SLionel Sambuc   /* Init unspecified parameters. */
215*433d6423SLionel Sambuc   if (action == START || action == GET) {
216*433d6423SLionel Sambuc 	if (strcmp(outfile, "") == 0) outfile = DEF_OUTFILE;
217*433d6423SLionel Sambuc 	if (mem_size == 0) mem_size = DEF_MEMSIZE;
218*433d6423SLionel Sambuc 	mem_size *= MB;				   /* mem_size in bytes */
219*433d6423SLionel Sambuc   }
220*433d6423SLionel Sambuc   if (action == START) {
221*433d6423SLionel Sambuc 	mem_size -= mem_size % sizeof(struct sprof_sample); /* align to sample size */
222*433d6423SLionel Sambuc 	if (freq == 0) freq = DEF_FREQ;		   /* default frequency */
223*433d6423SLionel Sambuc   }
224*433d6423SLionel Sambuc   return 0;
225*433d6423SLionel Sambuc }
226*433d6423SLionel Sambuc 
227*433d6423SLionel Sambuc 
228*433d6423SLionel Sambuc int start()
229*433d6423SLionel Sambuc {
230*433d6423SLionel Sambuc  /* This is the "starter process" for statistical profiling.
231*433d6423SLionel Sambuc   *
232*433d6423SLionel Sambuc   * Create output file for profiling data.  Create named pipe to
233*433d6423SLionel Sambuc   * synchronize with stopper process.  Fork so the parent can exit.
234*433d6423SLionel Sambuc   * Allocate memory for profiling data.  Start profiling in kernel.
235*433d6423SLionel Sambuc   * Complete detachment from terminal.  Write known string to named
236*433d6423SLionel Sambuc   * pipe, which blocks until read by stopper process.  Redirect
237*433d6423SLionel Sambuc   * stdout/stderr to the named pipe.  Write profiling data to file.
238*433d6423SLionel Sambuc   * Clean up.
239*433d6423SLionel Sambuc   */
240*433d6423SLionel Sambuc   int log_fd;
241*433d6423SLionel Sambuc 
242*433d6423SLionel Sambuc   if (init_outfile() || create_named_pipe()) return 1;
243*433d6423SLionel Sambuc 
244*433d6423SLionel Sambuc   printf("Starting statistical profiling.\n");
245*433d6423SLionel Sambuc 
246*433d6423SLionel Sambuc   if (fork() != 0) exit(0);
247*433d6423SLionel Sambuc 
248*433d6423SLionel Sambuc   if (alloc_mem()) return 1;
249*433d6423SLionel Sambuc 
250*433d6423SLionel Sambuc   if (sprofile(PROF_START, mem_size, freq, intr_type, &sprof_info, mem_ptr)) {
251*433d6423SLionel Sambuc 	perror("sprofile");
252*433d6423SLionel Sambuc 	fprintf(stderr, "Error starting profiling.\n");
253*433d6423SLionel Sambuc 	return 1;
254*433d6423SLionel Sambuc   }
255*433d6423SLionel Sambuc 
256*433d6423SLionel Sambuc   detach();
257*433d6423SLionel Sambuc 
258*433d6423SLionel Sambuc   /* Temporarily redirect to system log to catch errors. */
259*433d6423SLionel Sambuc   log_fd = open(DEV_LOG, O_WRONLY);
260*433d6423SLionel Sambuc   dup2(log_fd, 1);
261*433d6423SLionel Sambuc   dup2(log_fd, 2);
262*433d6423SLionel Sambuc 
263*433d6423SLionel Sambuc   if ((npipe_fd = open(NPIPE, O_WRONLY)) < 0) {
264*433d6423SLionel Sambuc 	fprintf(stderr, "Unable to open named pipe %s.\n", NPIPE);
265*433d6423SLionel Sambuc 	return 1;
266*433d6423SLionel Sambuc   } else
267*433d6423SLionel Sambuc 	/* Synchronize with stopper process. */
268*433d6423SLionel Sambuc 	write(npipe_fd, SYNCING, strlen(SYNCING));
269*433d6423SLionel Sambuc 
270*433d6423SLionel Sambuc   /* Now redirect to named pipe. */
271*433d6423SLionel Sambuc   dup2(npipe_fd, 1);
272*433d6423SLionel Sambuc   dup2(npipe_fd, 2);
273*433d6423SLionel Sambuc 
274*433d6423SLionel Sambuc   mem_used = sprof_info.mem_used;
275*433d6423SLionel Sambuc 
276*433d6423SLionel Sambuc   if (mem_used == -1) {
277*433d6423SLionel Sambuc 	  fprintf(stderr, "WARNING: Profiling was stopped prematurely due to ");
278*433d6423SLionel Sambuc 	  fprintf(stderr, "insufficient memory.\n");
279*433d6423SLionel Sambuc 	  fprintf(stderr, "Try increasing available memory using the -m switch.\n");
280*433d6423SLionel Sambuc   }
281*433d6423SLionel Sambuc 
282*433d6423SLionel Sambuc   if (write_outfile()) return 1;
283*433d6423SLionel Sambuc 
284*433d6423SLionel Sambuc   close(log_fd);
285*433d6423SLionel Sambuc   close(npipe_fd);
286*433d6423SLionel Sambuc   unlink(NPIPE);
287*433d6423SLionel Sambuc   close(outfile_fd);
288*433d6423SLionel Sambuc   free(mem_ptr);
289*433d6423SLionel Sambuc 
290*433d6423SLionel Sambuc   return 0;
291*433d6423SLionel Sambuc }
292*433d6423SLionel Sambuc 
293*433d6423SLionel Sambuc 
294*433d6423SLionel Sambuc int stop()
295*433d6423SLionel Sambuc {
296*433d6423SLionel Sambuc   /* This is the "stopper" process for statistical profiling.
297*433d6423SLionel Sambuc    *
298*433d6423SLionel Sambuc    * Stop profiling in kernel.  Read known string from named pipe
299*433d6423SLionel Sambuc    * to synchronize with starter proces.  Read named pipe until EOF
300*433d6423SLionel Sambuc    * and write to stdout, this allows feedback from started process
301*433d6423SLionel Sambuc    * to be printed.
302*433d6423SLionel Sambuc    */
303*433d6423SLionel Sambuc   int n;
304*433d6423SLionel Sambuc   char buf[BUFSIZE];
305*433d6423SLionel Sambuc 
306*433d6423SLionel Sambuc   if (sprofile(PROF_STOP, 0, 0, 0, 0, 0)) {
307*433d6423SLionel Sambuc 	perror("sprofile");
308*433d6423SLionel Sambuc 	fprintf(stderr, "Error stopping profiling.\n");
309*433d6423SLionel Sambuc   	return 1;
310*433d6423SLionel Sambuc   } else printf("Statistical profiling stopped.\n");
311*433d6423SLionel Sambuc 
312*433d6423SLionel Sambuc   if ((npipe_fd = open(NPIPE, O_RDONLY)) < 0) {
313*433d6423SLionel Sambuc 	fprintf(stderr, "Unable to open named pipe %s.\n", NPIPE);
314*433d6423SLionel Sambuc 	return 1;
315*433d6423SLionel Sambuc   } else
316*433d6423SLionel Sambuc 	/* Synchronize with starter process. */
317*433d6423SLionel Sambuc 	read(npipe_fd, buf, strlen(SYNCING));
318*433d6423SLionel Sambuc 
319*433d6423SLionel Sambuc   while ((n = read(npipe_fd, buf, BUFSIZE)) > 0)
320*433d6423SLionel Sambuc 	write(1, buf, n);
321*433d6423SLionel Sambuc 
322*433d6423SLionel Sambuc   close(npipe_fd);
323*433d6423SLionel Sambuc 
324*433d6423SLionel Sambuc   return 0;
325*433d6423SLionel Sambuc }
326*433d6423SLionel Sambuc 
327*433d6423SLionel Sambuc 
328*433d6423SLionel Sambuc int get()
329*433d6423SLionel Sambuc {
330*433d6423SLionel Sambuc  /* Get function for call profiling.
331*433d6423SLionel Sambuc   *
332*433d6423SLionel Sambuc   * Create output file.  Allocate memory.  Perform system call to get
333*433d6423SLionel Sambuc   * profiling table and write it to file.  Clean up.
334*433d6423SLionel Sambuc   */
335*433d6423SLionel Sambuc   if (init_outfile()) return 1;
336*433d6423SLionel Sambuc 
337*433d6423SLionel Sambuc   printf("Getting call profiling data.\n");
338*433d6423SLionel Sambuc 
339*433d6423SLionel Sambuc   if (alloc_mem()) return 1;
340*433d6423SLionel Sambuc 
341*433d6423SLionel Sambuc   if (cprofile(PROF_GET, mem_size, &cprof_info, mem_ptr)) {
342*433d6423SLionel Sambuc 	perror("cprofile");
343*433d6423SLionel Sambuc 	fprintf(stderr, "Error getting data.\n");
344*433d6423SLionel Sambuc 	return 1;
345*433d6423SLionel Sambuc   }
346*433d6423SLionel Sambuc 
347*433d6423SLionel Sambuc   mem_used = cprof_info.mem_used;
348*433d6423SLionel Sambuc 
349*433d6423SLionel Sambuc   if (mem_used == -1) {
350*433d6423SLionel Sambuc 	fprintf(stderr, "ERROR: unable to get data due to insufficient memory.\n");
351*433d6423SLionel Sambuc 	fprintf(stderr, "Try increasing available memory using the -m switch.\n");
352*433d6423SLionel Sambuc   } else
353*433d6423SLionel Sambuc   if (cprof_info.err) {
354*433d6423SLionel Sambuc 	fprintf(stderr, "ERROR: the following error(s) happened during profiling:\n");
355*433d6423SLionel Sambuc 	if (cprof_info.err & CPROF_CPATH_OVERRUN)
356*433d6423SLionel Sambuc 		fprintf(stderr, " call path overrun\n");
357*433d6423SLionel Sambuc 	if (cprof_info.err & CPROF_STACK_OVERRUN)
358*433d6423SLionel Sambuc 		fprintf(stderr, " call stack overrun\n");
359*433d6423SLionel Sambuc 	if (cprof_info.err & CPROF_TABLE_OVERRUN)
360*433d6423SLionel Sambuc 		fprintf(stderr, " hash table overrun\n");
361*433d6423SLionel Sambuc 	fprintf(stderr, "Try changing values in /usr/src/include/minix/profile.h ");
362*433d6423SLionel Sambuc 	fprintf(stderr, "and then rebuild the system.\n");
363*433d6423SLionel Sambuc   } else
364*433d6423SLionel Sambuc   if (write_outfile()) return 1;
365*433d6423SLionel Sambuc 
366*433d6423SLionel Sambuc   close(outfile_fd);
367*433d6423SLionel Sambuc   free(mem_ptr);
368*433d6423SLionel Sambuc 
369*433d6423SLionel Sambuc   return 0;
370*433d6423SLionel Sambuc }
371*433d6423SLionel Sambuc 
372*433d6423SLionel Sambuc 
373*433d6423SLionel Sambuc int reset()
374*433d6423SLionel Sambuc {
375*433d6423SLionel Sambuc  /* Reset function for call profiling.
376*433d6423SLionel Sambuc   *
377*433d6423SLionel Sambuc   * Perform system call to reset profiling table.
378*433d6423SLionel Sambuc   */
379*433d6423SLionel Sambuc   printf("Resetting call profiling data.\n");
380*433d6423SLionel Sambuc 
381*433d6423SLionel Sambuc   if (cprofile(PROF_RESET, 0, 0, 0)) {
382*433d6423SLionel Sambuc 	perror("cprofile");
383*433d6423SLionel Sambuc 	fprintf(stderr, "Error resetting data.\n");
384*433d6423SLionel Sambuc 	return 1;
385*433d6423SLionel Sambuc   }
386*433d6423SLionel Sambuc 
387*433d6423SLionel Sambuc   return 0;
388*433d6423SLionel Sambuc }
389*433d6423SLionel Sambuc 
390*433d6423SLionel Sambuc 
391*433d6423SLionel Sambuc int alloc_mem()
392*433d6423SLionel Sambuc {
393*433d6423SLionel Sambuc   if ((mem_ptr = malloc(mem_size)) == 0) {
394*433d6423SLionel Sambuc 	fprintf(stderr, "Unable to allocate memory.\n");
395*433d6423SLionel Sambuc 	fprintf(stderr, "Used chmem to increase available proces memory?\n");
396*433d6423SLionel Sambuc 	return 1;
397*433d6423SLionel Sambuc   } else memset(mem_ptr, '\0', mem_size);
398*433d6423SLionel Sambuc 
399*433d6423SLionel Sambuc   return 0;
400*433d6423SLionel Sambuc }
401*433d6423SLionel Sambuc 
402*433d6423SLionel Sambuc 
403*433d6423SLionel Sambuc int init_outfile()
404*433d6423SLionel Sambuc {
405*433d6423SLionel Sambuc   if ((outfile_fd = open(outfile, O_CREAT | O_TRUNC | O_WRONLY)) <= 0) {
406*433d6423SLionel Sambuc 	fprintf(stderr, "Unable to create outfile %s.\n", outfile);
407*433d6423SLionel Sambuc 	return 1;
408*433d6423SLionel Sambuc   } else chmod(outfile, S_IRUSR | S_IWUSR);
409*433d6423SLionel Sambuc 
410*433d6423SLionel Sambuc   return 0;
411*433d6423SLionel Sambuc }
412*433d6423SLionel Sambuc 
413*433d6423SLionel Sambuc 
414*433d6423SLionel Sambuc int create_named_pipe()
415*433d6423SLionel Sambuc {
416*433d6423SLionel Sambuc   if ((mkfifo(NPIPE, S_IRUSR | S_IWUSR) == -1) && (errno != EEXIST)) {
417*433d6423SLionel Sambuc 	fprintf(stderr, "Unable to create named pipe %s.\n", NPIPE);
418*433d6423SLionel Sambuc 	return 1;
419*433d6423SLionel Sambuc   } else
420*433d6423SLionel Sambuc 	return 0;
421*433d6423SLionel Sambuc }
422*433d6423SLionel Sambuc 
423*433d6423SLionel Sambuc 
424*433d6423SLionel Sambuc void detach()
425*433d6423SLionel Sambuc {
426*433d6423SLionel Sambuc   setsid();
427*433d6423SLionel Sambuc   (void) chdir("/");
428*433d6423SLionel Sambuc   close(0);
429*433d6423SLionel Sambuc   close(1);
430*433d6423SLionel Sambuc   close(2);
431*433d6423SLionel Sambuc }
432*433d6423SLionel Sambuc 
433*433d6423SLionel Sambuc static void add_proc(struct sprof_proc * p)
434*433d6423SLionel Sambuc {
435*433d6423SLionel Sambuc 	struct sproc * n;
436*433d6423SLionel Sambuc 	int slot = ((unsigned)(p->proc)) % HASH_MOD;
437*433d6423SLionel Sambuc 
438*433d6423SLionel Sambuc 	n = malloc(sizeof(struct sproc));
439*433d6423SLionel Sambuc 	if (!n)
440*433d6423SLionel Sambuc 		abort();
441*433d6423SLionel Sambuc 	n->ep = p->proc;
442*433d6423SLionel Sambuc 	memcpy(n->name, p->name, 8);
443*433d6423SLionel Sambuc 	n->next = proc_hash[slot];
444*433d6423SLionel Sambuc 	proc_hash[slot] = n;
445*433d6423SLionel Sambuc }
446*433d6423SLionel Sambuc 
447*433d6423SLionel Sambuc static char * get_proc_name(endpoint_t ep)
448*433d6423SLionel Sambuc {
449*433d6423SLionel Sambuc 	struct sproc * p;
450*433d6423SLionel Sambuc 
451*433d6423SLionel Sambuc 	for (p = proc_hash[((unsigned)ep) % HASH_MOD]; p; p = p->next) {
452*433d6423SLionel Sambuc 		if (p->ep == ep)
453*433d6423SLionel Sambuc 			return p->name;
454*433d6423SLionel Sambuc 	}
455*433d6423SLionel Sambuc 
456*433d6423SLionel Sambuc 	return NULL;
457*433d6423SLionel Sambuc }
458*433d6423SLionel Sambuc 
459*433d6423SLionel Sambuc int write_outfile()
460*433d6423SLionel Sambuc {
461*433d6423SLionel Sambuc   ssize_t n;
462*433d6423SLionel Sambuc   int written;
463*433d6423SLionel Sambuc   char header[80];
464*433d6423SLionel Sambuc 
465*433d6423SLionel Sambuc   printf("Writing to %s ...", outfile);
466*433d6423SLionel Sambuc 
467*433d6423SLionel Sambuc   /* Write header. */
468*433d6423SLionel Sambuc   if (SPROF)
469*433d6423SLionel Sambuc 	sprintf(header, "stat\n%u %u %u\n",	sizeof(struct sprof_info_s),
470*433d6423SLionel Sambuc 						sizeof(struct sprof_sample),
471*433d6423SLionel Sambuc 					  	sizeof(struct sprof_proc));
472*433d6423SLionel Sambuc   else
473*433d6423SLionel Sambuc 	sprintf(header, "call\n%u %u\n",
474*433d6423SLionel Sambuc 				CPROF_CPATH_MAX_LEN, CPROF_PROCNAME_LEN);
475*433d6423SLionel Sambuc 
476*433d6423SLionel Sambuc   n = write(outfile_fd, header, strlen(header));
477*433d6423SLionel Sambuc 
478*433d6423SLionel Sambuc   if (n < 0) {
479*433d6423SLionel Sambuc 	fprintf(stderr, "Error writing to outfile %s.\n", outfile);
480*433d6423SLionel Sambuc 	return 1;
481*433d6423SLionel Sambuc   }
482*433d6423SLionel Sambuc 
483*433d6423SLionel Sambuc   /* for sprofile, raw data will do; cprofile is handled by a script that needs
484*433d6423SLionel Sambuc    * some preprocessing to be done by us
485*433d6423SLionel Sambuc    */
486*433d6423SLionel Sambuc   if (SPROF) {
487*433d6423SLionel Sambuc 	written = write_outfile_sprof();
488*433d6423SLionel Sambuc   } else {
489*433d6423SLionel Sambuc 	written = write_outfile_cprof();
490*433d6423SLionel Sambuc   }
491*433d6423SLionel Sambuc   if (written < 0) return -1;
492*433d6423SLionel Sambuc 
493*433d6423SLionel Sambuc   printf(" header %d bytes, data %d bytes.\n", strlen(header), written);
494*433d6423SLionel Sambuc   return 0;
495*433d6423SLionel Sambuc }
496*433d6423SLionel Sambuc 
497*433d6423SLionel Sambuc int write_outfile_cprof()
498*433d6423SLionel Sambuc {
499*433d6423SLionel Sambuc   int towrite, written = 0;
500*433d6423SLionel Sambuc   struct sprof_sample *sample;
501*433d6423SLionel Sambuc 
502*433d6423SLionel Sambuc   /* Write data. */
503*433d6423SLionel Sambuc   towrite = mem_used == -1 ? mem_size : mem_used;
504*433d6423SLionel Sambuc 
505*433d6423SLionel Sambuc   sample = (struct sprof_sample *) mem_ptr;
506*433d6423SLionel Sambuc   while (towrite > 0) {
507*433d6423SLionel Sambuc 	  unsigned bytes;
508*433d6423SLionel Sambuc 	  char	entry[12];
509*433d6423SLionel Sambuc 	  char * name;
510*433d6423SLionel Sambuc 
511*433d6423SLionel Sambuc 	  name = get_proc_name(sample->proc);
512*433d6423SLionel Sambuc 	  if (!name) {
513*433d6423SLionel Sambuc 		  add_proc((struct sprof_proc *)sample);
514*433d6423SLionel Sambuc 		  bytes = sizeof(struct sprof_proc);
515*433d6423SLionel Sambuc 		  towrite -= bytes;
516*433d6423SLionel Sambuc 		  sample = (struct sprof_sample *)(((char *) sample) + bytes);
517*433d6423SLionel Sambuc 		  continue;
518*433d6423SLionel Sambuc 	  }
519*433d6423SLionel Sambuc 
520*433d6423SLionel Sambuc 	  memset(entry, 0, 12);
521*433d6423SLionel Sambuc 	  memcpy(entry, name, strlen(name));
522*433d6423SLionel Sambuc 	  memcpy(entry + 8, &sample->pc, 4);
523*433d6423SLionel Sambuc 
524*433d6423SLionel Sambuc 	  if (write(outfile_fd, entry, 12) != 12) {
525*433d6423SLionel Sambuc 		  fprintf(stderr, "Error writing to outfile %s.\n", outfile);
526*433d6423SLionel Sambuc 		  return -1;
527*433d6423SLionel Sambuc 	  }
528*433d6423SLionel Sambuc 	  towrite -= sizeof(struct sprof_sample);
529*433d6423SLionel Sambuc 	  sample++;
530*433d6423SLionel Sambuc 
531*433d6423SLionel Sambuc 	  written += 12;
532*433d6423SLionel Sambuc   }
533*433d6423SLionel Sambuc 
534*433d6423SLionel Sambuc   return written;
535*433d6423SLionel Sambuc }
536*433d6423SLionel Sambuc 
537*433d6423SLionel Sambuc int write_outfile_sprof()
538*433d6423SLionel Sambuc {
539*433d6423SLionel Sambuc   int towrite;
540*433d6423SLionel Sambuc   ssize_t written, written_total = 0;
541*433d6423SLionel Sambuc 
542*433d6423SLionel Sambuc   /* write profiling totals */
543*433d6423SLionel Sambuc   written = write(outfile_fd, &sprof_info, sizeof(sprof_info));
544*433d6423SLionel Sambuc   if (written != sizeof(sprof_info)) goto error;
545*433d6423SLionel Sambuc   written_total += written;
546*433d6423SLionel Sambuc 
547*433d6423SLionel Sambuc   /* write raw samples */
548*433d6423SLionel Sambuc   towrite = mem_used == -1 ? mem_size : mem_used;
549*433d6423SLionel Sambuc   written = write(outfile_fd, mem_ptr, towrite);
550*433d6423SLionel Sambuc   if (written != towrite) goto error;
551*433d6423SLionel Sambuc   written_total += written;
552*433d6423SLionel Sambuc 
553*433d6423SLionel Sambuc   return written_total;
554*433d6423SLionel Sambuc 
555*433d6423SLionel Sambuc error:
556*433d6423SLionel Sambuc   fprintf(stderr, "Error writing to outfile %s.\n", outfile);
557*433d6423SLionel Sambuc   return -1;
558*433d6423SLionel Sambuc }
559