3 * Linux Trace Toolkit Daemon
5 * This is a simple daemon that reads a few relay+debugfs channels and save
10 * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
23 #include <sys/types.h>
35 #include <asm/ioctl.h>
36 #include <asm/types.h>
38 /* Get the next sub buffer that can be read. */
39 #define RELAY_GET_SUBBUF _IOR(0xF4, 0x00,__u32)
40 /* Release the oldest reserved (by "get") sub buffer. */
41 #define RELAY_PUT_SUBBUF _IOW(0xF4, 0x01,__u32)
42 /* returns the number of sub buffers in the per cpu channel. */
43 #define RELAY_GET_N_SUBBUFS _IOR(0xF4, 0x02,__u32)
44 /* returns the size of the sub buffers. */
45 #define RELAY_GET_SUBBUF_SIZE _IOR(0xF4, 0x03,__u32)
59 unsigned int n_subbufs
;
60 unsigned int subbuf_size
;
62 pthread_mutex_t mutex
;
65 struct channel_trace_fd
{
70 static char *trace_name
= NULL
;
71 static char *channel_name
= NULL
;
72 static int daemon_mode
= 0;
73 static int append_mode
= 0;
74 static unsigned long num_threads
= 1;
75 volatile static int quit_program
= 0; /* For signal handler */
76 static int dump_flight_only
= 0;
77 static int dump_normal_only
= 0;
81 * -t directory Directory name of the trace to write to. Will be created.
82 * -c directory Root directory of the debugfs trace channels.
83 * -d Run in background (daemon).
84 * -a Trace append mode.
85 * -s Send SIGUSR1 to parent when ready for IO.
87 void show_arguments(void)
89 printf("Please use the following arguments :\n");
91 printf("-t directory Directory name of the trace to write to.\n"
92 " It will be created.\n");
93 printf("-c directory Root directory of the debugfs trace channels.\n");
94 printf("-d Run in background (daemon).\n");
95 printf("-a Append to an possibly existing trace.\n");
96 printf("-N Number of threads to start.\n");
97 printf("-f Dump only flight recorder channels.\n");
98 printf("-n Dump only normal channels.\n");
105 * Parses the command line arguments.
107 * Returns 1 if the arguments were correct, but doesn't ask for program
108 * continuation. Returns -1 if the arguments are incorrect, or 0 if OK.
110 int parse_arguments(int argc
, char **argv
)
116 if(strcmp(argv
[1], "-h") == 0) {
123 switch(argv
[argn
][0]) {
125 switch(argv
[argn
][1]) {
128 trace_name
= argv
[argn
+1];
134 channel_name
= argv
[argn
+1];
146 num_threads
= strtoul(argv
[argn
+1], NULL
, 0);
151 dump_flight_only
= 1;
154 dump_normal_only
= 1;
157 printf("Invalid argument '%s'.\n", argv
[argn
]);
163 printf("Invalid argument '%s'.\n", argv
[argn
]);
170 if(trace_name
== NULL
) {
171 printf("Please specify a trace name.\n");
176 if(channel_name
== NULL
) {
177 printf("Please specify a channel name.\n");
187 printf("Linux Trace Toolkit Trace Daemon\n");
189 printf("Reading from debugfs directory : %s\n", channel_name
);
190 printf("Writing to trace directory : %s\n", trace_name
);
195 /* signal handling */
197 static void handler(int signo
)
199 printf("Signal %d received : exiting cleanly\n", signo
);
205 int open_channel_trace_pairs(char *subchannel_name
, char *subtrace_name
,
206 struct channel_trace_fd
*fd_pairs
)
208 DIR *channel_dir
= opendir(subchannel_name
);
209 struct dirent
*entry
;
210 struct stat stat_buf
;
212 char path_channel
[PATH_MAX
];
213 int path_channel_len
;
214 char *path_channel_ptr
;
215 char path_trace
[PATH_MAX
];
217 char *path_trace_ptr
;
220 if(channel_dir
== NULL
) {
221 perror(subchannel_name
);
226 printf("Creating trace subdirectory %s\n", subtrace_name
);
227 ret
= mkdir(subtrace_name
, S_IRWXU
|S_IRWXG
|S_IRWXO
);
229 if(errno
!= EEXIST
) {
230 perror(subtrace_name
);
236 strncpy(path_channel
, subchannel_name
, PATH_MAX
-1);
237 path_channel_len
= strlen(path_channel
);
238 path_channel
[path_channel_len
] = '/';
240 path_channel_ptr
= path_channel
+ path_channel_len
;
242 strncpy(path_trace
, subtrace_name
, PATH_MAX
-1);
243 path_trace_len
= strlen(path_trace
);
244 path_trace
[path_trace_len
] = '/';
246 path_trace_ptr
= path_trace
+ path_trace_len
;
248 while((entry
= readdir(channel_dir
)) != NULL
) {
250 if(entry
->d_name
[0] == '.') continue;
252 strncpy(path_channel_ptr
, entry
->d_name
, PATH_MAX
- path_channel_len
);
253 strncpy(path_trace_ptr
, entry
->d_name
, PATH_MAX
- path_trace_len
);
255 ret
= stat(path_channel
, &stat_buf
);
257 perror(path_channel
);
261 printf("Channel file : %s\n", path_channel
);
263 if(S_ISDIR(stat_buf
.st_mode
)) {
265 printf("Entering channel subdirectory...\n");
266 ret
= open_channel_trace_pairs(path_channel
, path_trace
, fd_pairs
);
267 if(ret
< 0) continue;
268 } else if(S_ISREG(stat_buf
.st_mode
)) {
269 if(strncmp(entry
->d_name
, "flight-", sizeof("flight-")-1) != 0) {
270 if(dump_flight_only
) {
271 printf("Skipping normal channel %s\n", path_channel
);
275 if(dump_normal_only
) {
276 printf("Skipping flight channel %s\n", path_channel
);
280 printf("Opening file.\n");
282 fd_pairs
->pair
= realloc(fd_pairs
->pair
,
283 ++fd_pairs
->num_pairs
* sizeof(struct fd_pair
));
285 /* Open the channel in read mode */
286 fd_pairs
->pair
[fd_pairs
->num_pairs
-1].channel
=
287 open(path_channel
, O_RDONLY
| O_NONBLOCK
);
288 if(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].channel
== -1) {
289 perror(path_channel
);
290 fd_pairs
->num_pairs
--;
293 /* Open the trace in write mode, only append if append_mode */
294 ret
= stat(path_trace
, &stat_buf
);
297 printf("Appending to file %s as requested\n", path_trace
);
299 fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
=
300 open(path_trace
, O_WRONLY
|O_APPEND
,
301 S_IRWXU
|S_IRWXG
|S_IRWXO
);
303 if(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
== -1) {
307 printf("File %s exists, cannot open. Try append mode.\n", path_trace
);
312 if(errno
== ENOENT
) {
313 fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
=
314 open(path_trace
, O_WRONLY
|O_CREAT
|O_EXCL
,
315 S_IRWXU
|S_IRWXG
|S_IRWXO
);
316 if(fd_pairs
->pair
[fd_pairs
->num_pairs
-1].trace
== -1) {
325 closedir(channel_dir
);
331 int read_subbuffer(struct fd_pair
*pair
)
333 unsigned int consumed_old
;
337 err
= ioctl(pair
->channel
, RELAY_GET_SUBBUF
,
339 printf("cookie : %u\n", consumed_old
);
342 perror("Reserving sub buffer failed (everything is normal, it is due to concurrency)");
346 err
= TEMP_FAILURE_RETRY(write(pair
->trace
,
348 + (consumed_old
& ((pair
->n_subbufs
* pair
->subbuf_size
)-1)),
353 perror("Error in writing to file");
357 err
= fsync(pair
->trace
);
360 perror("Error in writing to file");
365 err
= ioctl(pair
->channel
, RELAY_PUT_SUBBUF
, &consumed_old
);
368 if(errno
== EFAULT
) {
369 perror("Error in unreserving sub buffer\n");
370 } else if(errno
== EIO
) {
371 perror("Reader has been pushed by the writer, last subbuffer corrupted.");
372 /* FIXME : we may delete the last written buffer if we wish. */
383 int map_channels(struct channel_trace_fd
*fd_pairs
)
388 if(fd_pairs
->num_pairs
<= 0) {
389 printf("No channel to read\n");
393 /* Get the subbuf sizes and number */
395 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
396 struct fd_pair
*pair
= &fd_pairs
->pair
[i
];
398 ret
= ioctl(pair
->channel
, RELAY_GET_N_SUBBUFS
,
401 perror("Error in getting the number of subbuffers");
404 ret
= ioctl(pair
->channel
, RELAY_GET_SUBBUF_SIZE
,
407 perror("Error in getting the size of the subbuffers");
410 ret
= pthread_mutex_init(&pair
->mutex
, NULL
); /* Fast mutex */
412 perror("Error in mutex init");
418 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
419 struct fd_pair
*pair
= &fd_pairs
->pair
[i
];
421 pair
->mmap
= mmap(0, pair
->subbuf_size
* pair
->n_subbufs
, PROT_READ
,
422 MAP_SHARED
, pair
->channel
, 0);
423 if(pair
->mmap
== MAP_FAILED
) {
424 perror("Mmap error");
429 goto end
; /* success */
432 /* munmap only the successfully mmapped indexes */
436 struct fd_pair
*pair
= &fd_pairs
->pair
[j
];
439 err_ret
= munmap(pair
->mmap
, pair
->subbuf_size
* pair
->n_subbufs
);
441 perror("Error in munmap");
453 int unmap_channels(struct channel_trace_fd
*fd_pairs
)
459 for(j
=0;j
<fd_pairs
->num_pairs
;j
++) {
460 struct fd_pair
*pair
= &fd_pairs
->pair
[j
];
463 err_ret
= munmap(pair
->mmap
, pair
->subbuf_size
* pair
->n_subbufs
);
465 perror("Error in munmap");
468 err_ret
= pthread_mutex_destroy(&pair
->mutex
);
470 perror("Error in mutex destroy");
483 * Read the debugfs channels and write them in the paired tracefiles.
485 * @fd_pairs : paired channels and trace files.
487 * returns (void*)0 on success, (void*)-1 on error.
489 * Note that the high priority polled channels are consumed first. We then poll
490 * again to see if these channels are still in priority. Only when no
491 * high priority channel is left, we start reading low priority channels.
493 * Note that a channel is considered high priority when the buffer is almost
497 void * read_channels(void *arg
)
499 struct pollfd
*pollfd
;
501 int num_rdy
, num_hup
;
504 struct channel_trace_fd
*fd_pairs
= (struct channel_trace_fd
*)arg
;
506 /* Start polling the FD */
508 pollfd
= malloc(fd_pairs
->num_pairs
* sizeof(struct pollfd
));
510 /* Note : index in pollfd is the same index as fd_pair->pair */
511 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
512 pollfd
[i
].fd
= fd_pairs
->pair
[i
].channel
;
513 pollfd
[i
].events
= POLLIN
|POLLPRI
;
520 printf("Press a key for next poll...\n");
522 read(STDIN_FILENO
, &buf
, 1);
523 printf("Next poll (polling %d fd) :\n", fd_pairs
->num_pairs
);
526 /* Have we received a signal ? */
527 if(quit_program
) break;
529 num_rdy
= poll(pollfd
, fd_pairs
->num_pairs
, -1);
531 perror("Poll error");
535 printf("Data received\n");
537 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
538 switch(pollfd
[i
].revents
) {
540 printf("Error returned in polling fd %d.\n", pollfd
[i
].fd
);
544 printf("Polling fd %d tells it has hung up.\n", pollfd
[i
].fd
);
548 printf("Polling fd %d tells fd is not open.\n", pollfd
[i
].fd
);
552 if(pthread_mutex_trylock(&fd_pairs
->pair
[i
].mutex
) == 0) {
553 printf("Urgent read on fd %d\n", pollfd
[i
].fd
);
554 /* Take care of high priority channels first. */
556 /* it's ok to have an unavailable subbuffer */
557 ret
= read_subbuffer(&fd_pairs
->pair
[i
]);
558 if(ret
== EAGAIN
) ret
= 0;
560 ret
= pthread_mutex_unlock(&fd_pairs
->pair
[i
].mutex
);
562 printf("Error in mutex unlock : %s\n", strerror(ret
));
567 /* If every FD has hung up, we end the read loop here */
568 if(num_hup
== fd_pairs
->num_pairs
) break;
571 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
572 switch(pollfd
[i
].revents
) {
574 if(pthread_mutex_trylock(&fd_pairs
->pair
[i
].mutex
) == 0) {
575 /* Take care of low priority channels. */
576 printf("Normal read on fd %d\n", pollfd
[i
].fd
);
577 /* it's ok to have an unavailable subbuffer */
578 ret
= read_subbuffer(&fd_pairs
->pair
[i
]);
579 if(ret
== EAGAIN
) ret
= 0;
581 ret
= pthread_mutex_unlock(&fd_pairs
->pair
[i
].mutex
);
583 printf("Error in mutex unlock : %s\n", strerror(ret
));
600 void close_channel_trace_pairs(struct channel_trace_fd
*fd_pairs
)
605 for(i
=0;i
<fd_pairs
->num_pairs
;i
++) {
606 ret
= close(fd_pairs
->pair
[i
].channel
);
607 if(ret
== -1) perror("Close error on channel");
608 ret
= close(fd_pairs
->pair
[i
].trace
);
609 if(ret
== -1) perror("Close error on trace");
611 free(fd_pairs
->pair
);
614 int main(int argc
, char ** argv
)
617 struct channel_trace_fd fd_pairs
= { NULL
, 0 };
618 struct sigaction act
;
623 ret
= parse_arguments(argc
, argv
);
625 if(ret
!= 0) show_arguments();
626 if(ret
< 0) return EINVAL
;
627 if(ret
> 0) return 0;
635 perror("An error occured while daemonizing.");
640 /* Connect the signal handlers */
641 act
.sa_handler
= handler
;
643 sigemptyset(&(act
.sa_mask
));
644 sigaddset(&(act
.sa_mask
), SIGTERM
);
645 sigaddset(&(act
.sa_mask
), SIGQUIT
);
646 sigaddset(&(act
.sa_mask
), SIGINT
);
647 sigaction(SIGTERM
, &act
, NULL
);
648 sigaction(SIGQUIT
, &act
, NULL
);
649 sigaction(SIGINT
, &act
, NULL
);
652 if(ret
= open_channel_trace_pairs(channel_name
, trace_name
, &fd_pairs
))
655 if(ret
= map_channels(&fd_pairs
))
658 tids
= malloc(sizeof(pthread_t
) * num_threads
);
659 for(i
=0; i
<num_threads
; i
++) {
660 ret
= pthread_create(&tids
[i
], NULL
, read_channels
, &fd_pairs
);
662 perror("Error creating thread");
667 for(i
=0; i
<num_threads
; i
++) {
668 ret
= pthread_join(tids
[i
], &tret
);
670 perror("Error joining thread");
674 printf("Error %s occured in thread %u\n", strerror((int)tret
), i
);
680 ret
|= unmap_channels(&fd_pairs
);
683 close_channel_trace_pairs(&fd_pairs
);