1 /* profile - profile operating system
3 * The profile command is used to control statistical profiling.
4 * It writes the profiling data collected by the kernel to a file.
7 * 14 Aug, 2006 Created (Rogier Meurs)
19 #include <minix/profile.h>
31 #define DEF_OUTFILE "profile.stat.out"
32 #define NPIPE "/tmp/profile.npipe"
34 #define DEF_MEMSIZE 64
39 #define MB (1024*1024)
40 #define SYNCING "SYNC"
41 #define DEV_LOG "/dev/log"
47 int intr_type
= PROF_RTC
;
50 int outfile_fd
, npipe_fd
;
51 struct sprof_info_s sprof_info
;
60 static struct sproc
* proc_hash
[HASH_MOD
];
62 int handle_args(int argc
, char *argv
[]);
65 int create_named_pipe(void);
67 int init_outfile(void);
68 int write_outfile(void);
69 int write_outfile_sprof(void);
72 int main(int argc
, char *argv
[])
76 if ((res
= handle_args(argc
, argv
))) {
79 printf("Error in parameters.\n");
83 printf("Specify one of start|stop|get|reset.\n");
87 printf("Incorrect memory size.\n");
91 printf("Incorrect frequency.\n");
95 printf("Output filename missing.\n");
103 * Check the frequency when we know the intr type. Only selected values
104 * are correct for RTC
106 if (action
== START
&& intr_type
== PROF_RTC
&&
107 (freq
< MIN_FREQ
|| freq
> MAX_FREQ
)) {
108 printf("Incorrect frequency.\n");
113 printf(" profile start [--rtc | --nmi] "
114 "[-m memsize] [-o outfile] [-f frequency]\n");
115 printf(" profile stop\n\n");
116 printf(" - --rtc is default, --nmi allows kernel profiling\n");
117 printf(" - memsize in MB, default: %u\n", DEF_MEMSIZE
);
118 printf(" - default output file: profile.stat.out\n");
119 printf(" - sample frequencies for --rtc (default: %u):\n", DEF_FREQ
);
120 printf(" 3 8192 Hz 10 64 Hz\n");
121 printf(" 4 4096 Hz 11 32 Hz\n");
122 printf(" 5 2048 Hz 12 16 Hz\n");
123 printf(" 6 1024 Hz 13 8 Hz\n");
124 printf(" 7 512 Hz 14 4 Hz\n");
125 printf(" 8 256 Hz 15 2 Hz\n");
126 printf(" 9 128 Hz\n\n");
127 printf("Use sprofalyze to analyze output file.\n");
133 if (start()) return 1;
136 if (stop()) return 1;
145 int handle_args(int argc
, char *argv
[])
150 if (strcmp(*argv
, "-h") == 0 || strcmp(*argv
, "help") == 0 ||
151 strcmp(*argv
, "--help") == 0) {
154 if (strcmp(*argv
, "-m") == 0) {
155 if (--argc
== 0) return ESYNTAX
;
156 if (sscanf(*++argv
, "%u", &mem_size
) != 1 ||
157 mem_size
< MIN_MEMSIZE
) return EMEM
;
159 if (strcmp(*argv
, "-f") == 0) {
160 if (--argc
== 0) return ESYNTAX
;
161 if (sscanf(*++argv
, "%u", &freq
) != 1)
164 if (strcmp(*argv
, "-o") == 0) {
165 if (--argc
== 0) return ESYNTAX
;
168 if (strcmp(*argv
, "--rtc") == 0) {
169 intr_type
= PROF_RTC
;
171 if (strcmp(*argv
, "--nmi") == 0) {
172 intr_type
= PROF_NMI
;
174 if (strcmp(*argv
, "start") == 0) {
175 if (action
) return EACTION
;
178 if (strcmp(*argv
, "stop") == 0) {
179 if (action
) return EACTION
;
184 /* No action specified. */
185 if (!action
) return EHELP
;
187 /* Init unspecified parameters. */
188 if (action
== START
) {
189 if (strcmp(outfile
, "") == 0) outfile
= DEF_OUTFILE
;
190 if (mem_size
== 0) mem_size
= DEF_MEMSIZE
;
191 mem_size
*= MB
; /* mem_size in bytes */
192 mem_size
-= mem_size
% sizeof(struct sprof_sample
); /* align to sample size */
193 if (freq
== 0) freq
= DEF_FREQ
; /* default frequency */
201 /* This is the "starter process" for statistical profiling.
203 * Create output file for profiling data. Create named pipe to
204 * synchronize with stopper process. Fork so the parent can exit.
205 * Allocate memory for profiling data. Start profiling in kernel.
206 * Complete detachment from terminal. Write known string to named
207 * pipe, which blocks until read by stopper process. Redirect
208 * stdout/stderr to the named pipe. Write profiling data to file.
213 if (init_outfile() || create_named_pipe()) return 1;
215 printf("Starting statistical profiling.\n");
217 if (fork() != 0) exit(0);
219 if (alloc_mem()) return 1;
221 if (sprofile(PROF_START
, mem_size
, freq
, intr_type
, &sprof_info
, mem_ptr
)) {
223 fprintf(stderr
, "Error starting profiling.\n");
229 /* Temporarily redirect to system log to catch errors. */
230 log_fd
= open(DEV_LOG
, O_WRONLY
);
234 if ((npipe_fd
= open(NPIPE
, O_WRONLY
)) < 0) {
235 fprintf(stderr
, "Unable to open named pipe %s.\n", NPIPE
);
238 /* Synchronize with stopper process. */
239 write(npipe_fd
, SYNCING
, strlen(SYNCING
));
241 /* Now redirect to named pipe. */
245 mem_used
= sprof_info
.mem_used
;
247 if (mem_used
== -1) {
248 fprintf(stderr
, "WARNING: Profiling was stopped prematurely due to ");
249 fprintf(stderr
, "insufficient memory.\n");
250 fprintf(stderr
, "Try increasing available memory using the -m switch.\n");
253 if (write_outfile()) return 1;
267 /* This is the "stopper" process for statistical profiling.
269 * Stop profiling in kernel. Read known string from named pipe
270 * to synchronize with starter proces. Read named pipe until EOF
271 * and write to stdout, this allows feedback from started process
277 if (sprofile(PROF_STOP
, 0, 0, 0, 0, 0)) {
279 fprintf(stderr
, "Error stopping profiling.\n");
281 } else printf("Statistical profiling stopped.\n");
283 if ((npipe_fd
= open(NPIPE
, O_RDONLY
)) < 0) {
284 fprintf(stderr
, "Unable to open named pipe %s.\n", NPIPE
);
287 /* Synchronize with starter process. */
288 read(npipe_fd
, buf
, strlen(SYNCING
));
290 while ((n
= read(npipe_fd
, buf
, BUFSIZE
)) > 0)
301 if ((mem_ptr
= malloc(mem_size
)) == 0) {
302 fprintf(stderr
, "Unable to allocate memory.\n");
303 fprintf(stderr
, "Used chmem to increase available proces memory?\n");
305 } else memset(mem_ptr
, '\0', mem_size
);
313 if ((outfile_fd
= open(outfile
, O_CREAT
| O_TRUNC
| O_WRONLY
)) <= 0) {
314 fprintf(stderr
, "Unable to create outfile %s.\n", outfile
);
316 } else chmod(outfile
, S_IRUSR
| S_IWUSR
);
322 int create_named_pipe()
324 if ((mkfifo(NPIPE
, S_IRUSR
| S_IWUSR
) == -1) && (errno
!= EEXIST
)) {
325 fprintf(stderr
, "Unable to create named pipe %s.\n", NPIPE
);
341 static void add_proc(struct sprof_proc
* p
)
344 int slot
= ((unsigned)(p
->proc
)) % HASH_MOD
;
346 n
= malloc(sizeof(struct sproc
));
350 memcpy(n
->name
, p
->name
, 8);
351 n
->next
= proc_hash
[slot
];
355 static char * get_proc_name(endpoint_t ep
)
359 for (p
= proc_hash
[((unsigned)ep
) % HASH_MOD
]; p
; p
= p
->next
) {
373 printf("Writing to %s ...", outfile
);
376 sprintf(header
, "stat\n%u %u %u\n", sizeof(struct sprof_info_s
),
377 sizeof(struct sprof_sample
),
378 sizeof(struct sprof_proc
));
380 n
= write(outfile_fd
, header
, strlen(header
));
383 fprintf(stderr
, "Error writing to outfile %s.\n", outfile
);
387 written
= write_outfile_sprof();
388 if (written
< 0) return -1;
390 printf(" header %d bytes, data %d bytes.\n", strlen(header
), written
);
394 int write_outfile_sprof()
397 ssize_t written
, written_total
= 0;
399 /* write profiling totals */
400 written
= write(outfile_fd
, &sprof_info
, sizeof(sprof_info
));
401 if (written
!= sizeof(sprof_info
)) goto error
;
402 written_total
+= written
;
404 /* write raw samples */
405 towrite
= mem_used
== -1 ? mem_size
: mem_used
;
406 written
= write(outfile_fd
, mem_ptr
, towrite
);
407 if (written
!= towrite
) goto error
;
408 written_total
+= written
;
410 return written_total
;
413 fprintf(stderr
, "Error writing to outfile %s.\n", outfile
);