2 * block queue tracing application
4 * Copyright (C) 2005 Jens Axboe <axboe@suse.de>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <sys/types.h>
29 #include <sys/ioctl.h>
38 #define BUF_SIZE (128 *1024)
41 #define DECLARE_MASK_MAP(mask) { BLK_TC_##mask, #mask, "BLK_TC_"#mask }
42 #define COMPARE_MASK_MAP(mmp, str) \
43 (!strcmp(mmp->short_form, toupper(str)) || \
44 !strcmp(mmp->long_form, toupper(str)))
46 #define VALID_SET(x) ((1 <= (x)) && ((x) < (1 << BLK_TC_SHIFT)))
54 struct mask_map mask_maps[] = {
55 DECLARE_MASK_MAP( READ ),
56 DECLARE_MASK_MAP( WRITE ),
57 DECLARE_MASK_MAP( BARRIER ),
58 DECLARE_MASK_MAP( SYNC ),
59 DECLARE_MASK_MAP( QUEUE ),
60 DECLARE_MASK_MAP( REQUEUE ),
61 DECLARE_MASK_MAP( ISSUE ),
62 DECLARE_MASK_MAP( COMPLETE ),
63 DECLARE_MASK_MAP( FS ),
64 DECLARE_MASK_MAP( PC ),
67 #define S_OPTS "d:a:A:r:"
68 struct option l_opts[] = {
101 struct thread_information {
104 unsigned long events_processed;
107 static char *relay_path;
109 #define is_done() (*(volatile int *)(&done))
110 static volatile int done;
112 static int devfd, ncpus;
113 static struct thread_information *thread_information;
114 static char *buts_name_p;
116 static int act_mask = ~0;
117 static int trace_started;
119 inline int compare_mask_map(struct mask_map *mmp, char *string)
122 char *s, *ustring = strdup(string);
124 for (i = 0, s = ustring; i < strlen(ustring); i++, s++)
127 return !strcmp(mmp->short_form, ustring) ||
128 !strcmp(mmp->long_form, ustring);
131 int find_mask_map(char *string)
135 for (i = 0; i < sizeof(mask_maps)/sizeof(mask_maps[0]); i++)
136 if (compare_mask_map(&mask_maps[i], string))
137 return mask_maps[i].mask;
141 static int start_trace(char *dev)
143 struct blk_user_trace_setup buts;
145 devfd = open(dev, O_RDONLY);
151 memset(&buts, sizeof(buts), 0);
152 buts.buf_size = BUF_SIZE;
153 buts.buf_nr = BUF_NR;
154 buts.act_mask = act_mask;
156 printf("Starting trace on %s\n", dev);
157 if (ioctl(devfd, BLKSTARTTRACE, &buts) < 0) {
158 perror("BLKSTARTTRACE");
163 buts_name_p = strdup(buts.name);
167 static void stop_trace(void)
169 if (ioctl(devfd, BLKSTOPTRACE) < 0)
170 perror("BLKSTOPTRACE");
175 static void extract_data(int cpu, char *ifn, int ifd, char *ofn, int ofd,
179 unsigned char *buf, *p;
184 while (bytes_left > 0) {
185 ret = read(ifd, p, bytes_left);
190 fprintf(stderr, "Thread %d extract_data %s failed\n",
200 ret = write(ofd, buf, nb);
203 fprintf(stderr,"Thread %d extract_data %s failed\n", cpu, ofn);
211 static void *extract(void *arg)
213 struct thread_information *tip = arg;
214 int tracefd, ret, ofd, pdu_len;
215 char ip[64], op[64], dp[64];
216 struct blk_io_trace t;
217 pid_t pid = getpid();
221 CPU_SET(tip->cpu, &cpu_mask);
223 if (sched_setaffinity(pid, sizeof(cpu_mask), &cpu_mask) == -1) {
224 perror("sched_setaffinity");
228 sprintf(op, "%s_out.%d", buts_name_p, tip->cpu);
229 ofd = open(op, O_CREAT|O_TRUNC|O_WRONLY, 0644);
232 fprintf(stderr,"Thread %d failed creat of %s\n", tip->cpu, op);
236 sprintf(ip, "%s%s%d", relay_path, buts_name_p, tip->cpu);
237 tracefd = open(ip, O_RDONLY);
240 fprintf(stderr,"Thread %d failed open of %s\n", tip->cpu, ip);
245 ret = read(tracefd, &t, sizeof(t));
246 if (ret != sizeof(t)) {
249 fprintf(stderr,"Thread %d failed read of %s\n",
252 } else if (ret > 0) {
253 fprintf(stderr,"Thread %d misread %s %d,%d\n",
254 tip->cpu, ip, ret, (int)sizeof(t));
262 if (verify_trace(&t))
269 ret = write(ofd, &t, sizeof(t));
272 fprintf(stderr,"Thread %d failed write of %s\n",
278 extract_data(tip->cpu, ip, tracefd, dp, ofd, pdu_len);
280 tip->events_processed++;
286 static int start_threads(void)
288 struct thread_information *tip;
291 ncpus = sysconf(_SC_NPROCESSORS_ONLN);
293 fprintf(stderr, "sysconf(_SC_NPROCESSORS_ONLN) failed\n");
296 printf("Processors online: %d\n", ncpus);
298 thread_information = malloc(ncpus * sizeof(struct thread_information));
299 for (i = 0, tip = thread_information; i < ncpus; i++, tip++) {
301 tip->events_processed = 0;
303 if (pthread_create(&tip->thread, NULL, extract, tip)) {
304 perror( "pthread_create");
312 static void stop_threads(void)
314 struct thread_information *tip = thread_information;
317 for (i = 0; i < ncpus; i++, tip++) {
320 if (pthread_join(tip->thread, (void *) &ret))
321 perror("thread_join");
325 void show_stats(void)
328 struct thread_information *tip;
329 unsigned long events_processed = 0;
331 for (i = 0, tip = thread_information; i < ncpus; i++, tip++) {
332 printf("CPU%3d: %20ld events\n",
333 tip->cpu, tip->events_processed);
334 events_processed += tip->events_processed;
337 printf("Total: %20ld events\n", events_processed);
340 void handle_sigint(int sig)
342 printf("exiting on signal %d\n", sig);
346 void stop_trace_on_exit(void)
352 int main(int argc, char *argv[])
354 static char default_relay_path[] = "/relay";
357 int act_mask_tmp = 0;
359 while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) >= 0) {
362 i = find_mask_map(optarg);
364 fprintf(stderr,"Invalid action mask %s\n",
372 if ((sscanf(optarg, "%x", &i) != 1) || !VALID_SET(i)) {
374 "Invalid set action mask %s/0x%x\n",
382 dev = strdup(optarg);
390 fprintf(stderr,"Usage: %s -d <dev> "
391 "[-a <trace> [-a <trace>]]\n", argv[0]);
396 if ((dev == NULL) || (optind < argc)) {
397 fprintf(stderr,"Usage: %s -d <dev> "
398 "[-a <trace> [-a <trace>]]\n", argv[0]);
403 relay_path = default_relay_path;
405 if (act_mask_tmp != 0) {
406 act_mask = act_mask_tmp;
407 printf("Tracing 0x%04x: ", act_mask);
408 for (i = 0; i < BLK_TC_SHIFT; i++)
409 if (act_mask & (1 << i))
410 printf("%s ", mask_maps[i].short_form);
414 if (stat(relay_path, &st) < 0) {
415 fprintf(stderr,"%s does not appear to be mounted\n",
420 if (start_trace(dev)) {
422 fprintf(stderr, "Failed to start trace on %s\n", dev);
426 setlocale(LC_NUMERIC, "en_US");
430 fprintf(stderr, "Failed to start worker threads\n");
435 printf("Threads started : %d\n", i);
437 signal(SIGINT, handle_sigint);
438 signal(SIGHUP, handle_sigint);
439 signal(SIGTERM, handle_sigint);
441 atexit(stop_trace_on_exit);