xref: /minix3/minix/commands/profile/profile.c (revision 1dcfbcd17383a5c335ef7172dc751771716b632d)
1433d6423SLionel Sambuc /* profile - profile operating system
2433d6423SLionel Sambuc  *
3*1dcfbcd1SDavid van Moolenbroek  * The profile command is used to control statistical profiling.
4433d6423SLionel Sambuc  * It writes the profiling data collected by the kernel to a file.
5433d6423SLionel Sambuc  *
6433d6423SLionel Sambuc  * Changes:
7433d6423SLionel Sambuc  *   14 Aug, 2006   Created (Rogier Meurs)
8433d6423SLionel Sambuc  */
9433d6423SLionel Sambuc 
10433d6423SLionel Sambuc #include <errno.h>
11433d6423SLionel Sambuc #include <fcntl.h>
12433d6423SLionel Sambuc #include <stdio.h>
13433d6423SLionel Sambuc #include <stdlib.h>
14433d6423SLionel Sambuc #include <string.h>
15433d6423SLionel Sambuc #include <unistd.h>
16433d6423SLionel Sambuc #include <sys/stat.h>
17433d6423SLionel Sambuc #undef SPROFILE
18433d6423SLionel Sambuc #define SPROFILE 1
19433d6423SLionel Sambuc #include <minix/profile.h>
20433d6423SLionel Sambuc 
21433d6423SLionel Sambuc #define EHELP			1
22433d6423SLionel Sambuc #define ESYNTAX			2
23433d6423SLionel Sambuc #define EMEM			3
24433d6423SLionel Sambuc #define EOUTFILE		4
25433d6423SLionel Sambuc #define EFREQ			5
26433d6423SLionel Sambuc #define EACTION			6
27433d6423SLionel Sambuc 
28433d6423SLionel Sambuc #define START			1
29433d6423SLionel Sambuc #define STOP			2
30433d6423SLionel Sambuc 
31*1dcfbcd1SDavid van Moolenbroek #define DEF_OUTFILE		"profile.stat.out"
32433d6423SLionel Sambuc #define NPIPE			"/tmp/profile.npipe"
33433d6423SLionel Sambuc #define MIN_MEMSIZE		1
34433d6423SLionel Sambuc #define DEF_MEMSIZE		64
35433d6423SLionel Sambuc #define MIN_FREQ		3
36433d6423SLionel Sambuc #define MAX_FREQ		15
37433d6423SLionel Sambuc #define DEF_FREQ		6
38433d6423SLionel Sambuc #define BUFSIZE			1024
39433d6423SLionel Sambuc #define MB			(1024*1024)
40433d6423SLionel Sambuc #define SYNCING			"SYNC"
41433d6423SLionel Sambuc #define DEV_LOG			"/dev/log"
42433d6423SLionel Sambuc 
43433d6423SLionel Sambuc int action = 0;
44433d6423SLionel Sambuc int mem_size = 0;
45433d6423SLionel Sambuc int mem_used = 0;
46433d6423SLionel Sambuc int freq = 0;
47433d6423SLionel Sambuc int intr_type = PROF_RTC;
48433d6423SLionel Sambuc char *outfile = "";
49433d6423SLionel Sambuc char *mem_ptr;
50433d6423SLionel Sambuc int outfile_fd, npipe_fd;
51433d6423SLionel Sambuc struct sprof_info_s sprof_info;
52433d6423SLionel Sambuc 
53433d6423SLionel Sambuc #define HASH_MOD	128
54433d6423SLionel Sambuc struct sproc {
55433d6423SLionel Sambuc 	endpoint_t	ep;
56433d6423SLionel Sambuc 	char		name[8];
57433d6423SLionel Sambuc 	struct sproc *	next;
58433d6423SLionel Sambuc };
59433d6423SLionel Sambuc 
60433d6423SLionel Sambuc static struct sproc * proc_hash[HASH_MOD];
61433d6423SLionel Sambuc 
62433d6423SLionel Sambuc int handle_args(int argc, char *argv[]);
63433d6423SLionel Sambuc int start(void);
64433d6423SLionel Sambuc int stop(void);
65433d6423SLionel Sambuc int create_named_pipe(void);
66433d6423SLionel Sambuc int alloc_mem(void);
67433d6423SLionel Sambuc int init_outfile(void);
68433d6423SLionel Sambuc int write_outfile(void);
69433d6423SLionel Sambuc int write_outfile_sprof(void);
70433d6423SLionel Sambuc void detach(void);
71433d6423SLionel Sambuc 
main(int argc,char * argv[])72433d6423SLionel Sambuc int main(int argc, char *argv[])
73433d6423SLionel Sambuc {
74433d6423SLionel Sambuc   int res;
75433d6423SLionel Sambuc 
76433d6423SLionel Sambuc   if ((res = handle_args(argc, argv))) {
77433d6423SLionel Sambuc 	switch(res) {
78433d6423SLionel Sambuc 		case ESYNTAX:
79433d6423SLionel Sambuc 			printf("Error in parameters.\n");
80433d6423SLionel Sambuc 			return 1;
81433d6423SLionel Sambuc 			break;
82433d6423SLionel Sambuc 		case EACTION:
83433d6423SLionel Sambuc 			printf("Specify one of start|stop|get|reset.\n");
84433d6423SLionel Sambuc 			return 1;
85433d6423SLionel Sambuc 			break;
86433d6423SLionel Sambuc 		case EMEM:
87433d6423SLionel Sambuc 			printf("Incorrect memory size.\n");
88433d6423SLionel Sambuc 			return 1;
89433d6423SLionel Sambuc 			break;
90433d6423SLionel Sambuc 		case EFREQ:
91433d6423SLionel Sambuc 			printf("Incorrect frequency.\n");
92433d6423SLionel Sambuc 			return 1;
93433d6423SLionel Sambuc 			break;
94433d6423SLionel Sambuc 		case EOUTFILE:
95433d6423SLionel Sambuc 			printf("Output filename missing.\n");
96433d6423SLionel Sambuc 			return 1;
97433d6423SLionel Sambuc 			break;
98433d6423SLionel Sambuc 		default:
99433d6423SLionel Sambuc 			break;
100433d6423SLionel Sambuc 	}
101433d6423SLionel Sambuc 
102433d6423SLionel Sambuc 	/*
103433d6423SLionel Sambuc 	 * Check the frequency when we know the intr type. Only selected values
104433d6423SLionel Sambuc 	 * are correct for RTC
105433d6423SLionel Sambuc 	 */
106433d6423SLionel Sambuc 	if (action == START && intr_type == PROF_RTC &&
107433d6423SLionel Sambuc 			(freq < MIN_FREQ || freq > MAX_FREQ)) {
108433d6423SLionel Sambuc 		printf("Incorrect frequency.\n");
109433d6423SLionel Sambuc 		return 1;
110433d6423SLionel Sambuc 	}
111433d6423SLionel Sambuc 
112*1dcfbcd1SDavid van Moolenbroek         printf("Usage:\n");
113433d6423SLionel Sambuc 	printf("  profile start [--rtc | --nmi] "
114433d6423SLionel Sambuc 			"[-m memsize] [-o outfile] [-f frequency]\n");
115433d6423SLionel Sambuc         printf("  profile stop\n\n");
116*1dcfbcd1SDavid van Moolenbroek 	printf("   - --rtc is default, --nmi allows kernel profiling\n");
117433d6423SLionel Sambuc 	printf("   - memsize in MB, default: %u\n", DEF_MEMSIZE);
118*1dcfbcd1SDavid van Moolenbroek 	printf("   - default output file: profile.stat.out\n");
119433d6423SLionel Sambuc 	printf("   - sample frequencies for --rtc (default: %u):\n", DEF_FREQ);
120433d6423SLionel Sambuc 	printf("      3    8192 Hz          10     64 Hz\n");
121433d6423SLionel Sambuc 	printf("      4    4096 Hz          11     32 Hz\n");
122433d6423SLionel Sambuc 	printf("      5    2048 Hz          12     16 Hz\n");
123433d6423SLionel Sambuc 	printf("      6    1024 Hz          13      8 Hz\n");
124433d6423SLionel Sambuc 	printf("      7     512 Hz          14      4 Hz\n");
125433d6423SLionel Sambuc 	printf("      8     256 Hz          15      2 Hz\n");
126433d6423SLionel Sambuc 	printf("      9     128 Hz\n\n");
127*1dcfbcd1SDavid van Moolenbroek 	printf("Use sprofalyze to analyze output file.\n");
128433d6423SLionel Sambuc 	return 1;
129433d6423SLionel Sambuc   }
130433d6423SLionel Sambuc 
131433d6423SLionel Sambuc   switch(action) {
132433d6423SLionel Sambuc 	  case START:
133433d6423SLionel Sambuc 	  	if (start()) return 1;
134433d6423SLionel Sambuc 		break;
135433d6423SLionel Sambuc 	  case STOP:
136433d6423SLionel Sambuc 	  	if (stop()) return 1;
137433d6423SLionel Sambuc 		break;
138433d6423SLionel Sambuc 	  default:
139433d6423SLionel Sambuc 		break;
140433d6423SLionel Sambuc   }
141433d6423SLionel Sambuc   return 0;
142433d6423SLionel Sambuc }
143433d6423SLionel Sambuc 
144433d6423SLionel Sambuc 
handle_args(int argc,char * argv[])145433d6423SLionel Sambuc int handle_args(int argc, char *argv[])
146433d6423SLionel Sambuc {
147433d6423SLionel Sambuc   while (--argc) {
148433d6423SLionel Sambuc 	++argv;
149433d6423SLionel Sambuc 
150433d6423SLionel Sambuc 	if (strcmp(*argv, "-h") == 0 || strcmp(*argv, "help") == 0 ||
151433d6423SLionel Sambuc 		strcmp(*argv, "--help") == 0) {
152433d6423SLionel Sambuc 		return EHELP;
153433d6423SLionel Sambuc 	} else
154433d6423SLionel Sambuc 	if (strcmp(*argv, "-m") == 0) {
155433d6423SLionel Sambuc 		if (--argc == 0) return ESYNTAX;
156433d6423SLionel Sambuc 		if (sscanf(*++argv, "%u", &mem_size) != 1 ||
157433d6423SLionel Sambuc 			mem_size < MIN_MEMSIZE ) return EMEM;
158433d6423SLionel Sambuc 	} else
159433d6423SLionel Sambuc 	if (strcmp(*argv, "-f") == 0) {
160433d6423SLionel Sambuc 		if (--argc == 0) return ESYNTAX;
161433d6423SLionel Sambuc 		if (sscanf(*++argv, "%u", &freq) != 1)
162433d6423SLionel Sambuc 			return EFREQ;
163433d6423SLionel Sambuc 	} else
164433d6423SLionel Sambuc 	if (strcmp(*argv, "-o") == 0) {
165433d6423SLionel Sambuc 		if (--argc == 0) return ESYNTAX;
166433d6423SLionel Sambuc 		outfile = *++argv;
167433d6423SLionel Sambuc 	} else
168433d6423SLionel Sambuc 	if (strcmp(*argv, "--rtc") == 0) {
169433d6423SLionel Sambuc 		intr_type = PROF_RTC;
170433d6423SLionel Sambuc 	} else
171433d6423SLionel Sambuc 	if (strcmp(*argv, "--nmi") == 0) {
172433d6423SLionel Sambuc 		intr_type = PROF_NMI;
173433d6423SLionel Sambuc 	} else
174433d6423SLionel Sambuc 	if (strcmp(*argv, "start") == 0) {
175433d6423SLionel Sambuc 		if (action) return EACTION;
176433d6423SLionel Sambuc 	       	action = START;
177433d6423SLionel Sambuc 	} else
178433d6423SLionel Sambuc 	if (strcmp(*argv, "stop") == 0) {
179433d6423SLionel Sambuc 		if (action) return EACTION;
180433d6423SLionel Sambuc 	       	action = STOP;
181433d6423SLionel Sambuc 	}
182433d6423SLionel Sambuc   }
183433d6423SLionel Sambuc 
184433d6423SLionel Sambuc   /* No action specified. */
185433d6423SLionel Sambuc   if (!action) return EHELP;
186433d6423SLionel Sambuc 
187433d6423SLionel Sambuc   /* Init unspecified parameters. */
188*1dcfbcd1SDavid van Moolenbroek   if (action == START) {
189433d6423SLionel Sambuc 	if (strcmp(outfile, "") == 0) outfile = DEF_OUTFILE;
190433d6423SLionel Sambuc 	if (mem_size == 0) mem_size = DEF_MEMSIZE;
191433d6423SLionel Sambuc 	mem_size *= MB;				   /* mem_size in bytes */
192433d6423SLionel Sambuc 	mem_size -= mem_size % sizeof(struct sprof_sample); /* align to sample size */
193433d6423SLionel Sambuc 	if (freq == 0) freq = DEF_FREQ;		   /* default frequency */
194433d6423SLionel Sambuc   }
195433d6423SLionel Sambuc   return 0;
196433d6423SLionel Sambuc }
197433d6423SLionel Sambuc 
198433d6423SLionel Sambuc 
start()199433d6423SLionel Sambuc int start()
200433d6423SLionel Sambuc {
201433d6423SLionel Sambuc  /* This is the "starter process" for statistical profiling.
202433d6423SLionel Sambuc   *
203433d6423SLionel Sambuc   * Create output file for profiling data.  Create named pipe to
204433d6423SLionel Sambuc   * synchronize with stopper process.  Fork so the parent can exit.
205433d6423SLionel Sambuc   * Allocate memory for profiling data.  Start profiling in kernel.
206433d6423SLionel Sambuc   * Complete detachment from terminal.  Write known string to named
207433d6423SLionel Sambuc   * pipe, which blocks until read by stopper process.  Redirect
208433d6423SLionel Sambuc   * stdout/stderr to the named pipe.  Write profiling data to file.
209433d6423SLionel Sambuc   * Clean up.
210433d6423SLionel Sambuc   */
211433d6423SLionel Sambuc   int log_fd;
212433d6423SLionel Sambuc 
213433d6423SLionel Sambuc   if (init_outfile() || create_named_pipe()) return 1;
214433d6423SLionel Sambuc 
215433d6423SLionel Sambuc   printf("Starting statistical profiling.\n");
216433d6423SLionel Sambuc 
217433d6423SLionel Sambuc   if (fork() != 0) exit(0);
218433d6423SLionel Sambuc 
219433d6423SLionel Sambuc   if (alloc_mem()) return 1;
220433d6423SLionel Sambuc 
221433d6423SLionel Sambuc   if (sprofile(PROF_START, mem_size, freq, intr_type, &sprof_info, mem_ptr)) {
222433d6423SLionel Sambuc 	perror("sprofile");
223433d6423SLionel Sambuc 	fprintf(stderr, "Error starting profiling.\n");
224433d6423SLionel Sambuc 	return 1;
225433d6423SLionel Sambuc   }
226433d6423SLionel Sambuc 
227433d6423SLionel Sambuc   detach();
228433d6423SLionel Sambuc 
229433d6423SLionel Sambuc   /* Temporarily redirect to system log to catch errors. */
230433d6423SLionel Sambuc   log_fd = open(DEV_LOG, O_WRONLY);
231433d6423SLionel Sambuc   dup2(log_fd, 1);
232433d6423SLionel Sambuc   dup2(log_fd, 2);
233433d6423SLionel Sambuc 
234433d6423SLionel Sambuc   if ((npipe_fd = open(NPIPE, O_WRONLY)) < 0) {
235433d6423SLionel Sambuc 	fprintf(stderr, "Unable to open named pipe %s.\n", NPIPE);
236433d6423SLionel Sambuc 	return 1;
237433d6423SLionel Sambuc   } else
238433d6423SLionel Sambuc 	/* Synchronize with stopper process. */
239433d6423SLionel Sambuc 	write(npipe_fd, SYNCING, strlen(SYNCING));
240433d6423SLionel Sambuc 
241433d6423SLionel Sambuc   /* Now redirect to named pipe. */
242433d6423SLionel Sambuc   dup2(npipe_fd, 1);
243433d6423SLionel Sambuc   dup2(npipe_fd, 2);
244433d6423SLionel Sambuc 
245433d6423SLionel Sambuc   mem_used = sprof_info.mem_used;
246433d6423SLionel Sambuc 
247433d6423SLionel Sambuc   if (mem_used == -1) {
248433d6423SLionel Sambuc 	  fprintf(stderr, "WARNING: Profiling was stopped prematurely due to ");
249433d6423SLionel Sambuc 	  fprintf(stderr, "insufficient memory.\n");
250433d6423SLionel Sambuc 	  fprintf(stderr, "Try increasing available memory using the -m switch.\n");
251433d6423SLionel Sambuc   }
252433d6423SLionel Sambuc 
253433d6423SLionel Sambuc   if (write_outfile()) return 1;
254433d6423SLionel Sambuc 
255433d6423SLionel Sambuc   close(log_fd);
256433d6423SLionel Sambuc   close(npipe_fd);
257433d6423SLionel Sambuc   unlink(NPIPE);
258433d6423SLionel Sambuc   close(outfile_fd);
259433d6423SLionel Sambuc   free(mem_ptr);
260433d6423SLionel Sambuc 
261433d6423SLionel Sambuc   return 0;
262433d6423SLionel Sambuc }
263433d6423SLionel Sambuc 
264433d6423SLionel Sambuc 
stop()265433d6423SLionel Sambuc int stop()
266433d6423SLionel Sambuc {
267433d6423SLionel Sambuc   /* This is the "stopper" process for statistical profiling.
268433d6423SLionel Sambuc    *
269433d6423SLionel Sambuc    * Stop profiling in kernel.  Read known string from named pipe
270433d6423SLionel Sambuc    * to synchronize with starter proces.  Read named pipe until EOF
271433d6423SLionel Sambuc    * and write to stdout, this allows feedback from started process
272433d6423SLionel Sambuc    * to be printed.
273433d6423SLionel Sambuc    */
274433d6423SLionel Sambuc   int n;
275433d6423SLionel Sambuc   char buf[BUFSIZE];
276433d6423SLionel Sambuc 
277433d6423SLionel Sambuc   if (sprofile(PROF_STOP, 0, 0, 0, 0, 0)) {
278433d6423SLionel Sambuc 	perror("sprofile");
279433d6423SLionel Sambuc 	fprintf(stderr, "Error stopping profiling.\n");
280433d6423SLionel Sambuc   	return 1;
281433d6423SLionel Sambuc   } else printf("Statistical profiling stopped.\n");
282433d6423SLionel Sambuc 
283433d6423SLionel Sambuc   if ((npipe_fd = open(NPIPE, O_RDONLY)) < 0) {
284433d6423SLionel Sambuc 	fprintf(stderr, "Unable to open named pipe %s.\n", NPIPE);
285433d6423SLionel Sambuc 	return 1;
286433d6423SLionel Sambuc   } else
287433d6423SLionel Sambuc 	/* Synchronize with starter process. */
288433d6423SLionel Sambuc 	read(npipe_fd, buf, strlen(SYNCING));
289433d6423SLionel Sambuc 
290433d6423SLionel Sambuc   while ((n = read(npipe_fd, buf, BUFSIZE)) > 0)
291433d6423SLionel Sambuc 	write(1, buf, n);
292433d6423SLionel Sambuc 
293433d6423SLionel Sambuc   close(npipe_fd);
294433d6423SLionel Sambuc 
295433d6423SLionel Sambuc   return 0;
296433d6423SLionel Sambuc }
297433d6423SLionel Sambuc 
298433d6423SLionel Sambuc 
alloc_mem()299433d6423SLionel Sambuc int alloc_mem()
300433d6423SLionel Sambuc {
301433d6423SLionel Sambuc   if ((mem_ptr = malloc(mem_size)) == 0) {
302433d6423SLionel Sambuc 	fprintf(stderr, "Unable to allocate memory.\n");
303433d6423SLionel Sambuc 	fprintf(stderr, "Used chmem to increase available proces memory?\n");
304433d6423SLionel Sambuc 	return 1;
305433d6423SLionel Sambuc   } else memset(mem_ptr, '\0', mem_size);
306433d6423SLionel Sambuc 
307433d6423SLionel Sambuc   return 0;
308433d6423SLionel Sambuc }
309433d6423SLionel Sambuc 
310433d6423SLionel Sambuc 
init_outfile()311433d6423SLionel Sambuc int init_outfile()
312433d6423SLionel Sambuc {
313433d6423SLionel Sambuc   if ((outfile_fd = open(outfile, O_CREAT | O_TRUNC | O_WRONLY)) <= 0) {
314433d6423SLionel Sambuc 	fprintf(stderr, "Unable to create outfile %s.\n", outfile);
315433d6423SLionel Sambuc 	return 1;
316433d6423SLionel Sambuc   } else chmod(outfile, S_IRUSR | S_IWUSR);
317433d6423SLionel Sambuc 
318433d6423SLionel Sambuc   return 0;
319433d6423SLionel Sambuc }
320433d6423SLionel Sambuc 
321433d6423SLionel Sambuc 
create_named_pipe()322433d6423SLionel Sambuc int create_named_pipe()
323433d6423SLionel Sambuc {
324433d6423SLionel Sambuc   if ((mkfifo(NPIPE, S_IRUSR | S_IWUSR) == -1) && (errno != EEXIST)) {
325433d6423SLionel Sambuc 	fprintf(stderr, "Unable to create named pipe %s.\n", NPIPE);
326433d6423SLionel Sambuc 	return 1;
327433d6423SLionel Sambuc   } else
328433d6423SLionel Sambuc 	return 0;
329433d6423SLionel Sambuc }
330433d6423SLionel Sambuc 
331433d6423SLionel Sambuc 
detach()332433d6423SLionel Sambuc void detach()
333433d6423SLionel Sambuc {
334433d6423SLionel Sambuc   setsid();
335433d6423SLionel Sambuc   (void) chdir("/");
336433d6423SLionel Sambuc   close(0);
337433d6423SLionel Sambuc   close(1);
338433d6423SLionel Sambuc   close(2);
339433d6423SLionel Sambuc }
340433d6423SLionel Sambuc 
add_proc(struct sprof_proc * p)341433d6423SLionel Sambuc static void add_proc(struct sprof_proc * p)
342433d6423SLionel Sambuc {
343433d6423SLionel Sambuc 	struct sproc * n;
344433d6423SLionel Sambuc 	int slot = ((unsigned)(p->proc)) % HASH_MOD;
345433d6423SLionel Sambuc 
346433d6423SLionel Sambuc 	n = malloc(sizeof(struct sproc));
347433d6423SLionel Sambuc 	if (!n)
348433d6423SLionel Sambuc 		abort();
349433d6423SLionel Sambuc 	n->ep = p->proc;
350433d6423SLionel Sambuc 	memcpy(n->name, p->name, 8);
351433d6423SLionel Sambuc 	n->next = proc_hash[slot];
352433d6423SLionel Sambuc 	proc_hash[slot] = n;
353433d6423SLionel Sambuc }
354433d6423SLionel Sambuc 
get_proc_name(endpoint_t ep)355433d6423SLionel Sambuc static char * get_proc_name(endpoint_t ep)
356433d6423SLionel Sambuc {
357433d6423SLionel Sambuc 	struct sproc * p;
358433d6423SLionel Sambuc 
359433d6423SLionel Sambuc 	for (p = proc_hash[((unsigned)ep) % HASH_MOD]; p; p = p->next) {
360433d6423SLionel Sambuc 		if (p->ep == ep)
361433d6423SLionel Sambuc 			return p->name;
362433d6423SLionel Sambuc 	}
363433d6423SLionel Sambuc 
364433d6423SLionel Sambuc 	return NULL;
365433d6423SLionel Sambuc }
366433d6423SLionel Sambuc 
write_outfile()367433d6423SLionel Sambuc int write_outfile()
368433d6423SLionel Sambuc {
369433d6423SLionel Sambuc   ssize_t n;
370433d6423SLionel Sambuc   int written;
371433d6423SLionel Sambuc   char header[80];
372433d6423SLionel Sambuc 
373433d6423SLionel Sambuc   printf("Writing to %s ...", outfile);
374433d6423SLionel Sambuc 
375433d6423SLionel Sambuc   /* Write header. */
376433d6423SLionel Sambuc   sprintf(header, "stat\n%u %u %u\n",	sizeof(struct sprof_info_s),
377433d6423SLionel Sambuc 					sizeof(struct sprof_sample),
378433d6423SLionel Sambuc 					sizeof(struct sprof_proc));
379433d6423SLionel Sambuc 
380433d6423SLionel Sambuc   n = write(outfile_fd, header, strlen(header));
381433d6423SLionel Sambuc 
382433d6423SLionel Sambuc   if (n < 0) {
383433d6423SLionel Sambuc 	fprintf(stderr, "Error writing to outfile %s.\n", outfile);
384433d6423SLionel Sambuc 	return 1;
385433d6423SLionel Sambuc   }
386433d6423SLionel Sambuc 
387433d6423SLionel Sambuc   written = write_outfile_sprof();
388433d6423SLionel Sambuc   if (written < 0) return -1;
389433d6423SLionel Sambuc 
390433d6423SLionel Sambuc   printf(" header %d bytes, data %d bytes.\n", strlen(header), written);
391433d6423SLionel Sambuc   return 0;
392433d6423SLionel Sambuc }
393433d6423SLionel Sambuc 
write_outfile_sprof()394433d6423SLionel Sambuc int write_outfile_sprof()
395433d6423SLionel Sambuc {
396433d6423SLionel Sambuc   int towrite;
397433d6423SLionel Sambuc   ssize_t written, written_total = 0;
398433d6423SLionel Sambuc 
399433d6423SLionel Sambuc   /* write profiling totals */
400433d6423SLionel Sambuc   written = write(outfile_fd, &sprof_info, sizeof(sprof_info));
401433d6423SLionel Sambuc   if (written != sizeof(sprof_info)) goto error;
402433d6423SLionel Sambuc   written_total += written;
403433d6423SLionel Sambuc 
404433d6423SLionel Sambuc   /* write raw samples */
405433d6423SLionel Sambuc   towrite = mem_used == -1 ? mem_size : mem_used;
406433d6423SLionel Sambuc   written = write(outfile_fd, mem_ptr, towrite);
407433d6423SLionel Sambuc   if (written != towrite) goto error;
408433d6423SLionel Sambuc   written_total += written;
409433d6423SLionel Sambuc 
410433d6423SLionel Sambuc   return written_total;
411433d6423SLionel Sambuc 
412433d6423SLionel Sambuc error:
413433d6423SLionel Sambuc   fprintf(stderr, "Error writing to outfile %s.\n", outfile);
414433d6423SLionel Sambuc   return -1;
415433d6423SLionel Sambuc }
416