[PATCH] blkparse: split format parsing into seperate file
[blktrace.git] / blkparse_fmt.c
1 /*
2  * This file contains format parsing code for blkparse, allowing you to
3  * customize the individual action format and generel output format.
4  */
5 #include <stdio.h>
6 #include <string.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <ctype.h>
10
11 #include "blktrace.h"
12
13 #define VALID_SPECS     "BCDFGMPQRSTU"
14
15 #define HEADER          "%D %2c %8s %5T.%9t %5p %2a %3d "
16
17 static char *override_format[256];
18
19 static inline int valid_spec(int spec)
20 {
21         return strchr(VALID_SPECS, spec) != NULL;
22 }
23
24 void set_all_format_specs(char *optarg)
25 {
26         char *p;
27
28         for (p = VALID_SPECS; *p; p++)
29                 if (override_format[(int)(*p)] == NULL)
30                         override_format[(int)(*p)] = strdup(optarg);
31 }
32
33 int add_format_spec(char *optarg)
34 {
35         int spec = optarg[0];
36
37         if (!valid_spec(spec)) {
38                 fprintf(stderr,"Bad format specifier %c\n", spec);
39                 return 1;
40         }
41         if (optarg[1] != ',') {
42                 fprintf(stderr,"Bad format specifier - need ',' %s\n", optarg);
43                 return 1;
44         }
45         optarg += 2;
46         if (*optarg == '\0') {
47                 fprintf(stderr,"Bad format specifier - need fmt %s\n", optarg);
48                 return 1;
49         }
50
51         /*
52          * Set both merges (front and back)
53          */
54         if (spec == 'M') {
55                 override_format['B'] = strdup(optarg);
56                 override_format['M'] = strdup(optarg);
57         } else
58                 override_format[spec] = strdup(optarg);
59
60         return 0;
61 }
62
63 static void print_field(char *act, struct per_cpu_info *pci,
64                         struct blk_io_trace *t, unsigned long long elapsed,
65                         int pdu_len, unsigned char *pdu_buf, char field,
66                         int minus, int has_w, int width)
67 {
68         char format[64];
69
70         if (has_w) {
71                 if (minus)
72                         sprintf(format, "%%-%d", width);
73                 else
74                         sprintf(format, "%%%d", width);
75         } else
76                 sprintf(format, "%%");
77
78         switch (field) {
79         case 'a':
80                 fprintf(ofp, strcat(format, "s"), act);
81                 break;
82         case 'c':
83                 fprintf(ofp, strcat(format, "d"), pci->cpu);
84                 break;
85         case 'C':
86                 fprintf(ofp, strcat(format, "s"), t->comm);
87                 break;
88         case 'd': {
89                 char rwbs[4];
90                 int i = 0;
91                 int w = t->action & BLK_TC_ACT(BLK_TC_WRITE);
92                 int b = t->action & BLK_TC_ACT(BLK_TC_BARRIER);
93                 int s = t->action & BLK_TC_ACT(BLK_TC_SYNC);
94                 if (w)
95                         rwbs[i++] = 'W';
96                 else
97                         rwbs[i++] = 'R';
98                 if (b)
99                         rwbs[i++] = 'B';
100                 if (s)
101                         rwbs[i++] = 'S';
102                 rwbs[i] = '\0';
103                 fprintf(ofp, strcat(format, "s"), rwbs);
104                 break;
105         }
106         case 'D':       /* format width ignored */
107                 fprintf(ofp,"%3d,%-3d", MAJOR(t->device), MINOR(t->device));
108                 break;
109         case 'e':
110                 fprintf(ofp, strcat(format, "d"), t->error);
111                 break;
112         case 'M':
113                 fprintf(ofp, strcat(format, "d"), MAJOR(t->device));
114                 break;
115         case 'm':
116                 fprintf(ofp, strcat(format, "d"), MINOR(t->device));
117                 break;
118         case 'n':
119                 fprintf(ofp, strcat(format, "u"), t->bytes >> 9);
120                 break;
121         case 'p':
122                 fprintf(ofp, strcat(format, "u"), t->pid);
123                 break;
124         case 'P':       /* format width ignored */
125                 if ((pdu_len > 0) && (pdu_buf != NULL)) {
126                         int i;
127                         unsigned char *p = pdu_buf;
128                         for (i = 0; i < pdu_len; i++) {
129                                 if (i)
130                                         fprintf(ofp, " ");
131
132                                 fprintf(ofp, "%02x", *p++);
133                         }
134                 }
135                 break;
136         case 's':
137                 fprintf(ofp, strcat(format, "ld"), t->sequence);
138                 break;
139         case 'S':
140                 fprintf(ofp, strcat(format, "lu"), t->sector);
141                 break;
142         case 't':
143                 sprintf(format, "%%0%dlu", has_w ? width : 9);
144                 fprintf(ofp, format, NANO_SECONDS(t->time));
145                 break;
146         case 'T':
147                 fprintf(ofp, strcat(format, "d"), SECONDS(t->time));
148                 break;
149         case 'u':
150                 if (elapsed == -1ULL) {
151                         fprintf(stderr, "Expecting elapsed value\n");
152                         exit(1);
153                 }
154                 fprintf(ofp, strcat(format, "llu"), elapsed / 1000);
155                 break;
156         case 'U': {
157                 __u64 *depth = (__u64 *) ((char *) t + sizeof(*t));
158                 fprintf(ofp, strcat(format, "u"),
159                                         (unsigned int) be64_to_cpu(*depth));
160                 break;
161         }
162         default:
163                 fprintf(ofp,strcat(format, "c"), field);
164                 break;
165         }
166 }
167
168 static char *parse_field(char *act, struct per_cpu_info *pci, 
169                          struct blk_io_trace *t, unsigned long long elapsed, 
170                          int pdu_len, unsigned char *pdu_buf, 
171                          char *master_format)
172 {
173         int minus = 0;
174         int has_w = 0;
175         int width = 0;
176         char *p = master_format;
177
178         if (*p == '-') {
179                 minus = 1;
180                 p++;
181         }
182         if (isdigit(*p)) {
183                 has_w = 1;
184                 do {
185                         width = (width * 10) + (*p++ - '0');
186                 } while ((*p) && (isdigit(*p)));
187         }
188         if (*p) {
189                 print_field(act, pci, t, elapsed, pdu_len, pdu_buf, *p++,
190                             minus, has_w, width);
191         }
192         return p;
193 }
194
195 static char *fmt_select(int fmt_spec, struct blk_io_trace *t,
196                         unsigned long long elapsed)
197 {
198         char *fmt;
199         static char scratch_format[1024];
200
201         if (override_format[fmt_spec] != NULL)
202                 return override_format[fmt_spec];
203
204         switch (fmt_spec) {
205         case 'C':       /* Complete */
206                 if (t->action & BLK_TC_ACT(BLK_TC_PC))
207                         strcpy(scratch_format, HEADER "(%P) [%e]\n");
208                 else {
209                         if (elapsed != -1ULL) {
210                                 strcpy(scratch_format,
211                                         HEADER "%S +%n (%8u) [%e]\n");
212                         } else
213                                 strcpy(scratch_format, HEADER "%S + %n [%e]\n");
214                 }
215                 fmt = scratch_format;
216                 break;
217
218         case 'D':       /* Issue */
219                 if (t->action & BLK_TC_ACT(BLK_TC_PC))
220                         strcpy(scratch_format, HEADER "%n (%P) [%C]\n");
221                 else {
222                         if (elapsed != -1ULL) {
223                                 strcpy(scratch_format,
224                                         HEADER "%S + %n (%8u) [%C]\n");
225                         } else
226                                 strcpy(scratch_format, HEADER "%S + %n [%C]\n");
227                 }
228                 fmt = scratch_format;
229                 break;
230
231         case 'I':       /* Insert */
232                 if (t->action & BLK_TC_ACT(BLK_TC_PC))
233                         strcpy(scratch_format, HEADER "%n (%P) [%C]\n");
234                 else {
235                         if (elapsed != -1ULL) {
236                                 strcpy(scratch_format,
237                                         HEADER "%S + %n (%8u) [%C]\n");
238                         } else
239                                 strcpy(scratch_format, HEADER "%S + %n [%C]\n");
240                 }
241                 fmt = scratch_format;
242                 break;
243
244         case 'Q':       /* Queue */
245         case 'W':       /* Bounce */
246                 if (elapsed != -1ULL) {
247                         strcpy(scratch_format, HEADER "%S + %n (%8u) [%C]\n");
248                 } else
249                         strcpy(scratch_format, HEADER "%S + %n [%C]\n");
250                 fmt = scratch_format;
251                 break;
252
253         case 'B':       /* Back merge */
254         case 'F':       /* Front merge */
255         case 'M':       /* Front or back merge */
256                 fmt = HEADER "%S + %n [%C]\n";
257                 break;
258
259         case 'P':       /* Plug */
260                 fmt = HEADER "[%C]\n";
261                 break;
262
263         case 'G':       /* Get request */
264         case 'S':       /* Sleep request */
265                 fmt = HEADER "%S + %n [%C]\n";
266                 break;
267
268         case 'U':       /* Unplug IO */
269         case 'T':       /* Unplug timer */
270                 fmt = HEADER "[%C] %U\n";
271                 break;
272
273         case 'X':       /* Split */
274                 strcpy(scratch_format, HEADER "%S / %U [%C]\n");
275                 fmt = scratch_format;
276                 break;
277
278         default:
279                 fprintf(stderr,"FATAL: Invalid format spec %c\n", fmt_spec);
280                 exit(1);
281                 /*NOTREACHED*/
282         }
283
284         return fmt;
285 }
286
287 void process_fmt(char *act, struct per_cpu_info *pci, struct blk_io_trace *t,
288                  unsigned long long elapsed, int pdu_len,
289                  unsigned char *pdu_buf)
290 {
291         char *p = fmt_select(act[0], t, elapsed);
292
293         while (*p) {
294                 switch (*p) {
295                 case '%':       /* Field specifier */
296                         p++;
297                         if (*p == '%')
298                                 fprintf(ofp, "%c", *p++);
299                         else if (!*p)
300                                 fprintf(ofp, "%c", '%');
301                         else
302                                 p = parse_field(act, pci, t, elapsed,
303                                                 pdu_len, pdu_buf, p);
304                         break;
305                 case '\\': {    /* escape */
306                         switch (p[1]) {
307                         case 'b': fprintf(ofp, "\b"); break;
308                         case 'n': fprintf(ofp, "\n"); break;
309                         case 'r': fprintf(ofp, "\r"); break;
310                         case 't': fprintf(ofp, "\t"); break;
311                         default:
312                                 fprintf(stderr, 
313                                         "Invalid escape char in format %c\n",
314                                         p[1]);
315                                 exit(1);
316                                 /*NOTREACHED*/
317                         }
318                         p += 2;
319                         break;
320                 }
321                 default:
322                         fprintf(ofp, "%c", *p++);
323                         break;
324                 }
325         }
326 }
327
328