1*1a3d31e3SAndroid Build Coastguard Worker /*
2*1a3d31e3SAndroid Build Coastguard Worker * Blktrace record utility - Convert binary trace data into bunches of IOs
3*1a3d31e3SAndroid Build Coastguard Worker *
4*1a3d31e3SAndroid Build Coastguard Worker * Copyright (C) 2007 Alan D. Brunelle <[email protected]>
5*1a3d31e3SAndroid Build Coastguard Worker *
6*1a3d31e3SAndroid Build Coastguard Worker * This program is free software; you can redistribute it and/or modify
7*1a3d31e3SAndroid Build Coastguard Worker * it under the terms of the GNU General Public License as published by
8*1a3d31e3SAndroid Build Coastguard Worker * the Free Software Foundation; either version 2 of the License, or
9*1a3d31e3SAndroid Build Coastguard Worker * (at your option) any later version.
10*1a3d31e3SAndroid Build Coastguard Worker *
11*1a3d31e3SAndroid Build Coastguard Worker * This program is distributed in the hope that it will be useful,
12*1a3d31e3SAndroid Build Coastguard Worker * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*1a3d31e3SAndroid Build Coastguard Worker * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14*1a3d31e3SAndroid Build Coastguard Worker * GNU General Public License for more details.
15*1a3d31e3SAndroid Build Coastguard Worker *
16*1a3d31e3SAndroid Build Coastguard Worker * You should have received a copy of the GNU General Public License
17*1a3d31e3SAndroid Build Coastguard Worker * along with this program; if not, write to the Free Software
18*1a3d31e3SAndroid Build Coastguard Worker * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*1a3d31e3SAndroid Build Coastguard Worker */
20*1a3d31e3SAndroid Build Coastguard Worker
21*1a3d31e3SAndroid Build Coastguard Worker #include <assert.h>
22*1a3d31e3SAndroid Build Coastguard Worker #include <fcntl.h>
23*1a3d31e3SAndroid Build Coastguard Worker #include <stdio.h>
24*1a3d31e3SAndroid Build Coastguard Worker #include <stdlib.h>
25*1a3d31e3SAndroid Build Coastguard Worker #include <string.h>
26*1a3d31e3SAndroid Build Coastguard Worker #include <unistd.h>
27*1a3d31e3SAndroid Build Coastguard Worker #include <sys/param.h>
28*1a3d31e3SAndroid Build Coastguard Worker #include <sys/stat.h>
29*1a3d31e3SAndroid Build Coastguard Worker #include <sys/types.h>
30*1a3d31e3SAndroid Build Coastguard Worker #include <dirent.h>
31*1a3d31e3SAndroid Build Coastguard Worker #include <stdarg.h>
32*1a3d31e3SAndroid Build Coastguard Worker
33*1a3d31e3SAndroid Build Coastguard Worker #if !defined(_GNU_SOURCE)
34*1a3d31e3SAndroid Build Coastguard Worker # define _GNU_SOURCE
35*1a3d31e3SAndroid Build Coastguard Worker #endif
36*1a3d31e3SAndroid Build Coastguard Worker #include <getopt.h>
37*1a3d31e3SAndroid Build Coastguard Worker
38*1a3d31e3SAndroid Build Coastguard Worker #include "list.h"
39*1a3d31e3SAndroid Build Coastguard Worker #include "btrecord.h"
40*1a3d31e3SAndroid Build Coastguard Worker #include "blktrace.h"
41*1a3d31e3SAndroid Build Coastguard Worker
42*1a3d31e3SAndroid Build Coastguard Worker /*
43*1a3d31e3SAndroid Build Coastguard Worker * Per input file information
44*1a3d31e3SAndroid Build Coastguard Worker *
45*1a3d31e3SAndroid Build Coastguard Worker * @head: Used to link up on input_files
46*1a3d31e3SAndroid Build Coastguard Worker * @devnm: Device name portion of this input file
47*1a3d31e3SAndroid Build Coastguard Worker * @file_name: Fully qualified name for this input file
48*1a3d31e3SAndroid Build Coastguard Worker * @cpu: CPU that this file was collected on
49*1a3d31e3SAndroid Build Coastguard Worker * @ifd: Input file descriptor (when opened)
50*1a3d31e3SAndroid Build Coastguard Worker * @tpkts: Total number of packets processed.
51*1a3d31e3SAndroid Build Coastguard Worker */
52*1a3d31e3SAndroid Build Coastguard Worker struct ifile_info {
53*1a3d31e3SAndroid Build Coastguard Worker struct list_head head;
54*1a3d31e3SAndroid Build Coastguard Worker char *devnm, *file_name;
55*1a3d31e3SAndroid Build Coastguard Worker int cpu, ifd;
56*1a3d31e3SAndroid Build Coastguard Worker __u64 tpkts, genesis;
57*1a3d31e3SAndroid Build Coastguard Worker };
58*1a3d31e3SAndroid Build Coastguard Worker
59*1a3d31e3SAndroid Build Coastguard Worker /*
60*1a3d31e3SAndroid Build Coastguard Worker * Per IO trace information
61*1a3d31e3SAndroid Build Coastguard Worker *
62*1a3d31e3SAndroid Build Coastguard Worker * @time: Time stamp when trace was emitted
63*1a3d31e3SAndroid Build Coastguard Worker * @sector: IO sector identifier
64*1a3d31e3SAndroid Build Coastguard Worker * @bytes: Number of bytes transferred
65*1a3d31e3SAndroid Build Coastguard Worker * @rw: Read (1) or write (0)
66*1a3d31e3SAndroid Build Coastguard Worker */
67*1a3d31e3SAndroid Build Coastguard Worker struct io_spec {
68*1a3d31e3SAndroid Build Coastguard Worker __u64 time;
69*1a3d31e3SAndroid Build Coastguard Worker __u64 sector;
70*1a3d31e3SAndroid Build Coastguard Worker __u32 bytes;
71*1a3d31e3SAndroid Build Coastguard Worker int rw;
72*1a3d31e3SAndroid Build Coastguard Worker };
73*1a3d31e3SAndroid Build Coastguard Worker
74*1a3d31e3SAndroid Build Coastguard Worker /*
75*1a3d31e3SAndroid Build Coastguard Worker * Per output file information
76*1a3d31e3SAndroid Build Coastguard Worker *
77*1a3d31e3SAndroid Build Coastguard Worker * @ofp: Output file
78*1a3d31e3SAndroid Build Coastguard Worker * @vfp: Verbose output file
79*1a3d31e3SAndroid Build Coastguard Worker * @file_name: Fully qualified name for this file
80*1a3d31e3SAndroid Build Coastguard Worker * @vfn: Fully qualified name for this file
81*1a3d31e3SAndroid Build Coastguard Worker * @cur: Current IO bunch being collected
82*1a3d31e3SAndroid Build Coastguard Worker * @iip: Input file this is associated with
83*1a3d31e3SAndroid Build Coastguard Worker * @start_time: Start time of th ecurrent bunch
84*1a3d31e3SAndroid Build Coastguard Worker * @last_time: Time of last packet put in
85*1a3d31e3SAndroid Build Coastguard Worker * @bunches: Number of bunches processed
86*1a3d31e3SAndroid Build Coastguard Worker * @pkts: Number of packets stored in bunches
87*1a3d31e3SAndroid Build Coastguard Worker */
88*1a3d31e3SAndroid Build Coastguard Worker struct io_stream {
89*1a3d31e3SAndroid Build Coastguard Worker FILE *ofp, *vfp;
90*1a3d31e3SAndroid Build Coastguard Worker char *file_name, *vfn;
91*1a3d31e3SAndroid Build Coastguard Worker struct io_bunch *cur;
92*1a3d31e3SAndroid Build Coastguard Worker struct ifile_info *iip;
93*1a3d31e3SAndroid Build Coastguard Worker __u64 start_time, last_time, bunches, pkts;
94*1a3d31e3SAndroid Build Coastguard Worker };
95*1a3d31e3SAndroid Build Coastguard Worker
96*1a3d31e3SAndroid Build Coastguard Worker int data_is_native; // Indicates whether to swap
97*1a3d31e3SAndroid Build Coastguard Worker static LIST_HEAD(input_files); // List of all input files
98*1a3d31e3SAndroid Build Coastguard Worker static char *idir = "."; // Input directory base
99*1a3d31e3SAndroid Build Coastguard Worker static char *odir = "."; // Output directory base
100*1a3d31e3SAndroid Build Coastguard Worker static char *obase = "replay"; // Output file base
101*1a3d31e3SAndroid Build Coastguard Worker static __u64 max_bunch_tm = (10 * 1000 * 1000); // 10 milliseconds
102*1a3d31e3SAndroid Build Coastguard Worker static __u64 max_pkts_per_bunch = 8; // Default # of pkts per bunch
103*1a3d31e3SAndroid Build Coastguard Worker static int verbose = 0; // Boolean: output stats
104*1a3d31e3SAndroid Build Coastguard Worker static int find_traces = 0; // Boolean: Find traces in dir
105*1a3d31e3SAndroid Build Coastguard Worker
106*1a3d31e3SAndroid Build Coastguard Worker static char usage_str[] = \
107*1a3d31e3SAndroid Build Coastguard Worker "\n" \
108*1a3d31e3SAndroid Build Coastguard Worker "\t[ -d <dir> : --input-directory=<dir> ] Default: .\n" \
109*1a3d31e3SAndroid Build Coastguard Worker "\t[ -D <dir> : --output-directory=<dir>] Default: .\n" \
110*1a3d31e3SAndroid Build Coastguard Worker "\t[ -F : --find-traces ] Default: Off\n" \
111*1a3d31e3SAndroid Build Coastguard Worker "\t[ -h : --help ] Default: Off\n" \
112*1a3d31e3SAndroid Build Coastguard Worker "\t[ -m <nsec> : --max-bunch-time=<nsec> ] Default: 10 msec\n" \
113*1a3d31e3SAndroid Build Coastguard Worker "\t[ -M <pkts> : --max-pkts=<pkts> ] Default: 8\n" \
114*1a3d31e3SAndroid Build Coastguard Worker "\t[ -o <base> : --output-base=<base> ] Default: replay\n" \
115*1a3d31e3SAndroid Build Coastguard Worker "\t[ -v : --verbose ] Default: Off\n" \
116*1a3d31e3SAndroid Build Coastguard Worker "\t[ -V : --version ] Default: Off\n" \
117*1a3d31e3SAndroid Build Coastguard Worker "\t<dev>... Default: None\n" \
118*1a3d31e3SAndroid Build Coastguard Worker "\n";
119*1a3d31e3SAndroid Build Coastguard Worker
120*1a3d31e3SAndroid Build Coastguard Worker #define S_OPTS "d:D:Fhm:M:o:vV"
121*1a3d31e3SAndroid Build Coastguard Worker static struct option l_opts[] = {
122*1a3d31e3SAndroid Build Coastguard Worker {
123*1a3d31e3SAndroid Build Coastguard Worker .name = "input-directory",
124*1a3d31e3SAndroid Build Coastguard Worker .has_arg = required_argument,
125*1a3d31e3SAndroid Build Coastguard Worker .flag = NULL,
126*1a3d31e3SAndroid Build Coastguard Worker .val = 'd'
127*1a3d31e3SAndroid Build Coastguard Worker },
128*1a3d31e3SAndroid Build Coastguard Worker {
129*1a3d31e3SAndroid Build Coastguard Worker .name = "output-directory",
130*1a3d31e3SAndroid Build Coastguard Worker .has_arg = required_argument,
131*1a3d31e3SAndroid Build Coastguard Worker .flag = NULL,
132*1a3d31e3SAndroid Build Coastguard Worker .val = 'D'
133*1a3d31e3SAndroid Build Coastguard Worker },
134*1a3d31e3SAndroid Build Coastguard Worker {
135*1a3d31e3SAndroid Build Coastguard Worker .name = "find-traces",
136*1a3d31e3SAndroid Build Coastguard Worker .has_arg = no_argument,
137*1a3d31e3SAndroid Build Coastguard Worker .flag = NULL,
138*1a3d31e3SAndroid Build Coastguard Worker .val = 'F'
139*1a3d31e3SAndroid Build Coastguard Worker },
140*1a3d31e3SAndroid Build Coastguard Worker {
141*1a3d31e3SAndroid Build Coastguard Worker .name = "help",
142*1a3d31e3SAndroid Build Coastguard Worker .has_arg = no_argument,
143*1a3d31e3SAndroid Build Coastguard Worker .flag = NULL,
144*1a3d31e3SAndroid Build Coastguard Worker .val = 'h'
145*1a3d31e3SAndroid Build Coastguard Worker },
146*1a3d31e3SAndroid Build Coastguard Worker {
147*1a3d31e3SAndroid Build Coastguard Worker .name = "max-bunch-time",
148*1a3d31e3SAndroid Build Coastguard Worker .has_arg = required_argument,
149*1a3d31e3SAndroid Build Coastguard Worker .flag = NULL,
150*1a3d31e3SAndroid Build Coastguard Worker .val = 'm'
151*1a3d31e3SAndroid Build Coastguard Worker },
152*1a3d31e3SAndroid Build Coastguard Worker {
153*1a3d31e3SAndroid Build Coastguard Worker .name = "max-pkts",
154*1a3d31e3SAndroid Build Coastguard Worker .has_arg = required_argument,
155*1a3d31e3SAndroid Build Coastguard Worker .flag = NULL,
156*1a3d31e3SAndroid Build Coastguard Worker .val = 'M'
157*1a3d31e3SAndroid Build Coastguard Worker },
158*1a3d31e3SAndroid Build Coastguard Worker {
159*1a3d31e3SAndroid Build Coastguard Worker .name = "output-base",
160*1a3d31e3SAndroid Build Coastguard Worker .has_arg = required_argument,
161*1a3d31e3SAndroid Build Coastguard Worker .flag = NULL,
162*1a3d31e3SAndroid Build Coastguard Worker .val = 'o'
163*1a3d31e3SAndroid Build Coastguard Worker },
164*1a3d31e3SAndroid Build Coastguard Worker {
165*1a3d31e3SAndroid Build Coastguard Worker .name = "verbose",
166*1a3d31e3SAndroid Build Coastguard Worker .has_arg = no_argument,
167*1a3d31e3SAndroid Build Coastguard Worker .flag = NULL,
168*1a3d31e3SAndroid Build Coastguard Worker .val = 'v'
169*1a3d31e3SAndroid Build Coastguard Worker },
170*1a3d31e3SAndroid Build Coastguard Worker {
171*1a3d31e3SAndroid Build Coastguard Worker .name = "version",
172*1a3d31e3SAndroid Build Coastguard Worker .has_arg = no_argument,
173*1a3d31e3SAndroid Build Coastguard Worker .flag = NULL,
174*1a3d31e3SAndroid Build Coastguard Worker .val = 'V'
175*1a3d31e3SAndroid Build Coastguard Worker },
176*1a3d31e3SAndroid Build Coastguard Worker {
177*1a3d31e3SAndroid Build Coastguard Worker .name = NULL
178*1a3d31e3SAndroid Build Coastguard Worker }
179*1a3d31e3SAndroid Build Coastguard Worker };
180*1a3d31e3SAndroid Build Coastguard Worker
181*1a3d31e3SAndroid Build Coastguard Worker #define ERR_ARGS 1
182*1a3d31e3SAndroid Build Coastguard Worker #define ERR_SYSCALL 2
fatal(const char * errstring,const int exitval,const char * fmt,...)183*1a3d31e3SAndroid Build Coastguard Worker static inline void fatal(const char *errstring, const int exitval,
184*1a3d31e3SAndroid Build Coastguard Worker const char *fmt, ...)
185*1a3d31e3SAndroid Build Coastguard Worker {
186*1a3d31e3SAndroid Build Coastguard Worker va_list ap;
187*1a3d31e3SAndroid Build Coastguard Worker
188*1a3d31e3SAndroid Build Coastguard Worker if (errstring)
189*1a3d31e3SAndroid Build Coastguard Worker perror(errstring);
190*1a3d31e3SAndroid Build Coastguard Worker
191*1a3d31e3SAndroid Build Coastguard Worker va_start(ap, fmt);
192*1a3d31e3SAndroid Build Coastguard Worker vfprintf(stderr, fmt, ap);
193*1a3d31e3SAndroid Build Coastguard Worker va_end(ap);
194*1a3d31e3SAndroid Build Coastguard Worker
195*1a3d31e3SAndroid Build Coastguard Worker exit(exitval);
196*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
197*1a3d31e3SAndroid Build Coastguard Worker }
198*1a3d31e3SAndroid Build Coastguard Worker
199*1a3d31e3SAndroid Build Coastguard Worker /**
200*1a3d31e3SAndroid Build Coastguard Worker * match - Return true if this trace is a proper QUEUE transaction
201*1a3d31e3SAndroid Build Coastguard Worker * @action: Action field from trace
202*1a3d31e3SAndroid Build Coastguard Worker */
match(__u32 action)203*1a3d31e3SAndroid Build Coastguard Worker static inline int match(__u32 action)
204*1a3d31e3SAndroid Build Coastguard Worker {
205*1a3d31e3SAndroid Build Coastguard Worker return ((action & 0xffff) == __BLK_TA_QUEUE) &&
206*1a3d31e3SAndroid Build Coastguard Worker (action & BLK_TC_ACT(BLK_TC_QUEUE));
207*1a3d31e3SAndroid Build Coastguard Worker }
208*1a3d31e3SAndroid Build Coastguard Worker
209*1a3d31e3SAndroid Build Coastguard Worker /**
210*1a3d31e3SAndroid Build Coastguard Worker * usage - Display usage string and version
211*1a3d31e3SAndroid Build Coastguard Worker */
usage(void)212*1a3d31e3SAndroid Build Coastguard Worker static void usage(void)
213*1a3d31e3SAndroid Build Coastguard Worker {
214*1a3d31e3SAndroid Build Coastguard Worker fprintf(stderr, "Usage: btrecord -- version %s\n%s",
215*1a3d31e3SAndroid Build Coastguard Worker my_btversion, usage_str);
216*1a3d31e3SAndroid Build Coastguard Worker }
217*1a3d31e3SAndroid Build Coastguard Worker
218*1a3d31e3SAndroid Build Coastguard Worker /**
219*1a3d31e3SAndroid Build Coastguard Worker * write_file_hdr - Seek to and write btrecord file header
220*1a3d31e3SAndroid Build Coastguard Worker * @stream: Output file information
221*1a3d31e3SAndroid Build Coastguard Worker * @hdr: Header to write
222*1a3d31e3SAndroid Build Coastguard Worker */
write_file_hdr(struct io_stream * stream,struct io_file_hdr * hdr)223*1a3d31e3SAndroid Build Coastguard Worker static void write_file_hdr(struct io_stream *stream, struct io_file_hdr *hdr)
224*1a3d31e3SAndroid Build Coastguard Worker {
225*1a3d31e3SAndroid Build Coastguard Worker hdr->version = mk_btversion(btver_mjr, btver_mnr, btver_sub);
226*1a3d31e3SAndroid Build Coastguard Worker
227*1a3d31e3SAndroid Build Coastguard Worker if (verbose) {
228*1a3d31e3SAndroid Build Coastguard Worker fprintf(stderr, "\t%s: %llx %llx %llx %llx\n",
229*1a3d31e3SAndroid Build Coastguard Worker stream->file_name,
230*1a3d31e3SAndroid Build Coastguard Worker (long long unsigned)hdr->version,
231*1a3d31e3SAndroid Build Coastguard Worker (long long unsigned)hdr->genesis,
232*1a3d31e3SAndroid Build Coastguard Worker (long long unsigned)hdr->nbunches,
233*1a3d31e3SAndroid Build Coastguard Worker (long long unsigned)hdr->total_pkts);
234*1a3d31e3SAndroid Build Coastguard Worker }
235*1a3d31e3SAndroid Build Coastguard Worker
236*1a3d31e3SAndroid Build Coastguard Worker fseek(stream->ofp, 0, SEEK_SET);
237*1a3d31e3SAndroid Build Coastguard Worker if (fwrite(hdr, sizeof(*hdr), 1, stream->ofp) != 1) {
238*1a3d31e3SAndroid Build Coastguard Worker fatal(stream->file_name, ERR_SYSCALL, "Hdr write failed\n");
239*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
240*1a3d31e3SAndroid Build Coastguard Worker }
241*1a3d31e3SAndroid Build Coastguard Worker }
242*1a3d31e3SAndroid Build Coastguard Worker
243*1a3d31e3SAndroid Build Coastguard Worker /**
244*1a3d31e3SAndroid Build Coastguard Worker * io_bunch_create - Allocate & initialize an io_bunch
245*1a3d31e3SAndroid Build Coastguard Worker * @io_stream: IO stream being added to
246*1a3d31e3SAndroid Build Coastguard Worker * @pre_stall: Amount of time that this bunch should be delayed by
247*1a3d31e3SAndroid Build Coastguard Worker * @start_time: Records current start
248*1a3d31e3SAndroid Build Coastguard Worker */
io_bunch_create(struct io_stream * stream,__u64 start_time)249*1a3d31e3SAndroid Build Coastguard Worker static inline void io_bunch_create(struct io_stream *stream, __u64 start_time)
250*1a3d31e3SAndroid Build Coastguard Worker {
251*1a3d31e3SAndroid Build Coastguard Worker struct io_bunch *cur = malloc(sizeof(*cur));
252*1a3d31e3SAndroid Build Coastguard Worker
253*1a3d31e3SAndroid Build Coastguard Worker memset(cur, 0, sizeof(*cur));
254*1a3d31e3SAndroid Build Coastguard Worker
255*1a3d31e3SAndroid Build Coastguard Worker cur->hdr.npkts = 0;
256*1a3d31e3SAndroid Build Coastguard Worker cur->hdr.time_stamp = stream->start_time = start_time;
257*1a3d31e3SAndroid Build Coastguard Worker
258*1a3d31e3SAndroid Build Coastguard Worker stream->cur = cur;
259*1a3d31e3SAndroid Build Coastguard Worker }
260*1a3d31e3SAndroid Build Coastguard Worker
261*1a3d31e3SAndroid Build Coastguard Worker /**
262*1a3d31e3SAndroid Build Coastguard Worker * io_bunch_add - Add an IO to the current bunch of IOs
263*1a3d31e3SAndroid Build Coastguard Worker * @stream: Per-output file stream information
264*1a3d31e3SAndroid Build Coastguard Worker * @spec: IO trace specification
265*1a3d31e3SAndroid Build Coastguard Worker *
266*1a3d31e3SAndroid Build Coastguard Worker * Returns update bunch information
267*1a3d31e3SAndroid Build Coastguard Worker */
io_bunch_add(struct io_stream * stream,struct io_spec * spec)268*1a3d31e3SAndroid Build Coastguard Worker static void io_bunch_add(struct io_stream *stream, struct io_spec *spec)
269*1a3d31e3SAndroid Build Coastguard Worker {
270*1a3d31e3SAndroid Build Coastguard Worker struct io_bunch *cur = stream->cur;
271*1a3d31e3SAndroid Build Coastguard Worker struct io_pkt iop = {
272*1a3d31e3SAndroid Build Coastguard Worker .sector = spec->sector,
273*1a3d31e3SAndroid Build Coastguard Worker .nbytes = spec->bytes,
274*1a3d31e3SAndroid Build Coastguard Worker .rw = spec->rw
275*1a3d31e3SAndroid Build Coastguard Worker };
276*1a3d31e3SAndroid Build Coastguard Worker
277*1a3d31e3SAndroid Build Coastguard Worker assert(cur != NULL);
278*1a3d31e3SAndroid Build Coastguard Worker assert(cur->hdr.npkts < BT_MAX_PKTS);
279*1a3d31e3SAndroid Build Coastguard Worker assert(stream->last_time == 0 || stream->last_time <= spec->time);
280*1a3d31e3SAndroid Build Coastguard Worker
281*1a3d31e3SAndroid Build Coastguard Worker cur->pkts[cur->hdr.npkts++] = iop; // Struct copy
282*1a3d31e3SAndroid Build Coastguard Worker stream->last_time = spec->time;
283*1a3d31e3SAndroid Build Coastguard Worker }
284*1a3d31e3SAndroid Build Coastguard Worker
285*1a3d31e3SAndroid Build Coastguard Worker /**
286*1a3d31e3SAndroid Build Coastguard Worker * rem_input_file - Release resources associated with an input file
287*1a3d31e3SAndroid Build Coastguard Worker * @iip: Per-input file information
288*1a3d31e3SAndroid Build Coastguard Worker */
rem_input_file(struct ifile_info * iip)289*1a3d31e3SAndroid Build Coastguard Worker static void rem_input_file(struct ifile_info *iip)
290*1a3d31e3SAndroid Build Coastguard Worker {
291*1a3d31e3SAndroid Build Coastguard Worker list_del(&iip->head);
292*1a3d31e3SAndroid Build Coastguard Worker
293*1a3d31e3SAndroid Build Coastguard Worker close(iip->ifd);
294*1a3d31e3SAndroid Build Coastguard Worker free(iip->file_name);
295*1a3d31e3SAndroid Build Coastguard Worker free(iip->devnm);
296*1a3d31e3SAndroid Build Coastguard Worker free(iip);
297*1a3d31e3SAndroid Build Coastguard Worker }
298*1a3d31e3SAndroid Build Coastguard Worker
299*1a3d31e3SAndroid Build Coastguard Worker /**
300*1a3d31e3SAndroid Build Coastguard Worker * __add_input_file - Allocate and initialize per-input file structure
301*1a3d31e3SAndroid Build Coastguard Worker * @cpu: CPU for this file
302*1a3d31e3SAndroid Build Coastguard Worker * @devnm: Device name for this file
303*1a3d31e3SAndroid Build Coastguard Worker * @file_name: Fully qualifed input file name
304*1a3d31e3SAndroid Build Coastguard Worker */
__add_input_file(int cpu,char * devnm,char * file_name)305*1a3d31e3SAndroid Build Coastguard Worker static void __add_input_file(int cpu, char *devnm, char *file_name)
306*1a3d31e3SAndroid Build Coastguard Worker {
307*1a3d31e3SAndroid Build Coastguard Worker struct ifile_info *iip = malloc(sizeof(*iip));
308*1a3d31e3SAndroid Build Coastguard Worker
309*1a3d31e3SAndroid Build Coastguard Worker iip->cpu = cpu;
310*1a3d31e3SAndroid Build Coastguard Worker iip->tpkts = 0;
311*1a3d31e3SAndroid Build Coastguard Worker iip->genesis = 0;
312*1a3d31e3SAndroid Build Coastguard Worker iip->devnm = strdup(devnm);
313*1a3d31e3SAndroid Build Coastguard Worker iip->file_name = strdup(file_name);
314*1a3d31e3SAndroid Build Coastguard Worker iip->ifd = open(file_name, O_RDONLY);
315*1a3d31e3SAndroid Build Coastguard Worker if (iip->ifd < 0) {
316*1a3d31e3SAndroid Build Coastguard Worker fatal(file_name, ERR_ARGS, "Unable to open\n");
317*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
318*1a3d31e3SAndroid Build Coastguard Worker }
319*1a3d31e3SAndroid Build Coastguard Worker
320*1a3d31e3SAndroid Build Coastguard Worker list_add_tail(&iip->head, &input_files);
321*1a3d31e3SAndroid Build Coastguard Worker }
322*1a3d31e3SAndroid Build Coastguard Worker
323*1a3d31e3SAndroid Build Coastguard Worker /**
324*1a3d31e3SAndroid Build Coastguard Worker * add_input_file - Set up the input file name
325*1a3d31e3SAndroid Build Coastguard Worker * @devnm: Device name to use
326*1a3d31e3SAndroid Build Coastguard Worker */
add_input_file(char * devnm)327*1a3d31e3SAndroid Build Coastguard Worker static void add_input_file(char *devnm)
328*1a3d31e3SAndroid Build Coastguard Worker {
329*1a3d31e3SAndroid Build Coastguard Worker struct list_head *p;
330*1a3d31e3SAndroid Build Coastguard Worker int cpu, found = 0;
331*1a3d31e3SAndroid Build Coastguard Worker
332*1a3d31e3SAndroid Build Coastguard Worker __list_for_each(p, &input_files) {
333*1a3d31e3SAndroid Build Coastguard Worker struct ifile_info *iip = list_entry(p, struct ifile_info, head);
334*1a3d31e3SAndroid Build Coastguard Worker if (strcmp(iip->devnm, devnm) == 0)
335*1a3d31e3SAndroid Build Coastguard Worker return;
336*1a3d31e3SAndroid Build Coastguard Worker }
337*1a3d31e3SAndroid Build Coastguard Worker
338*1a3d31e3SAndroid Build Coastguard Worker for (cpu = 0; ; cpu++) {
339*1a3d31e3SAndroid Build Coastguard Worker char full_name[MAXPATHLEN];
340*1a3d31e3SAndroid Build Coastguard Worker
341*1a3d31e3SAndroid Build Coastguard Worker sprintf(full_name, "%s/%s.blktrace.%d", idir, devnm, cpu);
342*1a3d31e3SAndroid Build Coastguard Worker if (access(full_name, R_OK) != 0)
343*1a3d31e3SAndroid Build Coastguard Worker break;
344*1a3d31e3SAndroid Build Coastguard Worker
345*1a3d31e3SAndroid Build Coastguard Worker __add_input_file(cpu, devnm, full_name);
346*1a3d31e3SAndroid Build Coastguard Worker found++;
347*1a3d31e3SAndroid Build Coastguard Worker }
348*1a3d31e3SAndroid Build Coastguard Worker
349*1a3d31e3SAndroid Build Coastguard Worker if (!found) {
350*1a3d31e3SAndroid Build Coastguard Worker fatal(NULL, ERR_ARGS, "No traces found for %s\n", devnm);
351*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
352*1a3d31e3SAndroid Build Coastguard Worker }
353*1a3d31e3SAndroid Build Coastguard Worker }
354*1a3d31e3SAndroid Build Coastguard Worker
find_input_files(char * idir)355*1a3d31e3SAndroid Build Coastguard Worker static void find_input_files(char *idir)
356*1a3d31e3SAndroid Build Coastguard Worker {
357*1a3d31e3SAndroid Build Coastguard Worker struct dirent *ent;
358*1a3d31e3SAndroid Build Coastguard Worker DIR *dir = opendir(idir);
359*1a3d31e3SAndroid Build Coastguard Worker
360*1a3d31e3SAndroid Build Coastguard Worker if (dir == NULL) {
361*1a3d31e3SAndroid Build Coastguard Worker fatal(idir, ERR_ARGS, "Unable to open %s\n", idir);
362*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
363*1a3d31e3SAndroid Build Coastguard Worker }
364*1a3d31e3SAndroid Build Coastguard Worker
365*1a3d31e3SAndroid Build Coastguard Worker while ((ent = readdir(dir)) != NULL) {
366*1a3d31e3SAndroid Build Coastguard Worker char *p, *dsf;
367*1a3d31e3SAndroid Build Coastguard Worker
368*1a3d31e3SAndroid Build Coastguard Worker if (strstr(ent->d_name, ".blktrace.") == NULL)
369*1a3d31e3SAndroid Build Coastguard Worker continue;
370*1a3d31e3SAndroid Build Coastguard Worker
371*1a3d31e3SAndroid Build Coastguard Worker dsf = strdup(ent->d_name);
372*1a3d31e3SAndroid Build Coastguard Worker p = index(dsf, '.');
373*1a3d31e3SAndroid Build Coastguard Worker assert(p != NULL);
374*1a3d31e3SAndroid Build Coastguard Worker *p = '\0';
375*1a3d31e3SAndroid Build Coastguard Worker add_input_file(dsf);
376*1a3d31e3SAndroid Build Coastguard Worker free(dsf);
377*1a3d31e3SAndroid Build Coastguard Worker }
378*1a3d31e3SAndroid Build Coastguard Worker
379*1a3d31e3SAndroid Build Coastguard Worker closedir(dir);
380*1a3d31e3SAndroid Build Coastguard Worker }
381*1a3d31e3SAndroid Build Coastguard Worker
382*1a3d31e3SAndroid Build Coastguard Worker /**
383*1a3d31e3SAndroid Build Coastguard Worker * handle_args - Parse passed in argument list
384*1a3d31e3SAndroid Build Coastguard Worker * @argc: Number of arguments in argv
385*1a3d31e3SAndroid Build Coastguard Worker * @argv: Arguments passed in
386*1a3d31e3SAndroid Build Coastguard Worker *
387*1a3d31e3SAndroid Build Coastguard Worker * Does rudimentary parameter verification as well.
388*1a3d31e3SAndroid Build Coastguard Worker */
handle_args(int argc,char * argv[])389*1a3d31e3SAndroid Build Coastguard Worker void handle_args(int argc, char *argv[])
390*1a3d31e3SAndroid Build Coastguard Worker {
391*1a3d31e3SAndroid Build Coastguard Worker int c;
392*1a3d31e3SAndroid Build Coastguard Worker
393*1a3d31e3SAndroid Build Coastguard Worker while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) != -1) {
394*1a3d31e3SAndroid Build Coastguard Worker switch (c) {
395*1a3d31e3SAndroid Build Coastguard Worker case 'd':
396*1a3d31e3SAndroid Build Coastguard Worker idir = optarg;
397*1a3d31e3SAndroid Build Coastguard Worker if (access(idir, R_OK | X_OK) != 0) {
398*1a3d31e3SAndroid Build Coastguard Worker fatal(idir, ERR_ARGS,
399*1a3d31e3SAndroid Build Coastguard Worker "Invalid input directory specified\n");
400*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
401*1a3d31e3SAndroid Build Coastguard Worker }
402*1a3d31e3SAndroid Build Coastguard Worker break;
403*1a3d31e3SAndroid Build Coastguard Worker
404*1a3d31e3SAndroid Build Coastguard Worker case 'D':
405*1a3d31e3SAndroid Build Coastguard Worker odir = optarg;
406*1a3d31e3SAndroid Build Coastguard Worker if (access(odir, R_OK | X_OK) != 0) {
407*1a3d31e3SAndroid Build Coastguard Worker fatal(odir, ERR_ARGS,
408*1a3d31e3SAndroid Build Coastguard Worker "Invalid output directory specified\n");
409*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
410*1a3d31e3SAndroid Build Coastguard Worker }
411*1a3d31e3SAndroid Build Coastguard Worker break;
412*1a3d31e3SAndroid Build Coastguard Worker
413*1a3d31e3SAndroid Build Coastguard Worker case 'F':
414*1a3d31e3SAndroid Build Coastguard Worker find_traces = 1;
415*1a3d31e3SAndroid Build Coastguard Worker break;
416*1a3d31e3SAndroid Build Coastguard Worker
417*1a3d31e3SAndroid Build Coastguard Worker case 'h':
418*1a3d31e3SAndroid Build Coastguard Worker usage();
419*1a3d31e3SAndroid Build Coastguard Worker exit(0);
420*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
421*1a3d31e3SAndroid Build Coastguard Worker
422*1a3d31e3SAndroid Build Coastguard Worker case 'm':
423*1a3d31e3SAndroid Build Coastguard Worker max_bunch_tm = (__u64)atoll(optarg);
424*1a3d31e3SAndroid Build Coastguard Worker if (max_bunch_tm < 1) {
425*1a3d31e3SAndroid Build Coastguard Worker fprintf(stderr, "Invalid bunch time %llu\n",
426*1a3d31e3SAndroid Build Coastguard Worker (unsigned long long)max_bunch_tm);
427*1a3d31e3SAndroid Build Coastguard Worker exit(ERR_ARGS);
428*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
429*1a3d31e3SAndroid Build Coastguard Worker }
430*1a3d31e3SAndroid Build Coastguard Worker break;
431*1a3d31e3SAndroid Build Coastguard Worker
432*1a3d31e3SAndroid Build Coastguard Worker case 'M':
433*1a3d31e3SAndroid Build Coastguard Worker max_pkts_per_bunch = (__u64)atoll(optarg);
434*1a3d31e3SAndroid Build Coastguard Worker if (!((1 <= max_pkts_per_bunch) &&
435*1a3d31e3SAndroid Build Coastguard Worker (max_pkts_per_bunch < 513))) {
436*1a3d31e3SAndroid Build Coastguard Worker fprintf(stderr, "Invalid max pkts %llu\n",
437*1a3d31e3SAndroid Build Coastguard Worker (unsigned long long)max_pkts_per_bunch);
438*1a3d31e3SAndroid Build Coastguard Worker exit(ERR_ARGS);
439*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
440*1a3d31e3SAndroid Build Coastguard Worker }
441*1a3d31e3SAndroid Build Coastguard Worker break;
442*1a3d31e3SAndroid Build Coastguard Worker
443*1a3d31e3SAndroid Build Coastguard Worker case 'o':
444*1a3d31e3SAndroid Build Coastguard Worker obase = optarg;
445*1a3d31e3SAndroid Build Coastguard Worker break;
446*1a3d31e3SAndroid Build Coastguard Worker
447*1a3d31e3SAndroid Build Coastguard Worker case 'V':
448*1a3d31e3SAndroid Build Coastguard Worker fprintf(stderr, "btrecord -- version %s\n",
449*1a3d31e3SAndroid Build Coastguard Worker my_btversion);
450*1a3d31e3SAndroid Build Coastguard Worker exit(0);
451*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
452*1a3d31e3SAndroid Build Coastguard Worker
453*1a3d31e3SAndroid Build Coastguard Worker case 'v':
454*1a3d31e3SAndroid Build Coastguard Worker verbose++;
455*1a3d31e3SAndroid Build Coastguard Worker break;
456*1a3d31e3SAndroid Build Coastguard Worker
457*1a3d31e3SAndroid Build Coastguard Worker default:
458*1a3d31e3SAndroid Build Coastguard Worker usage();
459*1a3d31e3SAndroid Build Coastguard Worker fatal(NULL, ERR_ARGS, "Invalid command line\n");
460*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
461*1a3d31e3SAndroid Build Coastguard Worker }
462*1a3d31e3SAndroid Build Coastguard Worker }
463*1a3d31e3SAndroid Build Coastguard Worker
464*1a3d31e3SAndroid Build Coastguard Worker while (optind < argc)
465*1a3d31e3SAndroid Build Coastguard Worker add_input_file(argv[optind++]);
466*1a3d31e3SAndroid Build Coastguard Worker
467*1a3d31e3SAndroid Build Coastguard Worker if (find_traces)
468*1a3d31e3SAndroid Build Coastguard Worker find_input_files(idir);
469*1a3d31e3SAndroid Build Coastguard Worker
470*1a3d31e3SAndroid Build Coastguard Worker if (list_len(&input_files) == 0) {
471*1a3d31e3SAndroid Build Coastguard Worker fatal(NULL, ERR_ARGS, "Missing required input file name(s)\n");
472*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
473*1a3d31e3SAndroid Build Coastguard Worker }
474*1a3d31e3SAndroid Build Coastguard Worker }
475*1a3d31e3SAndroid Build Coastguard Worker
476*1a3d31e3SAndroid Build Coastguard Worker /**
477*1a3d31e3SAndroid Build Coastguard Worker * next_io - Retrieve next Q trace from input stream
478*1a3d31e3SAndroid Build Coastguard Worker * @iip: Per-input file information
479*1a3d31e3SAndroid Build Coastguard Worker * @spec: IO specifier for trace
480*1a3d31e3SAndroid Build Coastguard Worker *
481*1a3d31e3SAndroid Build Coastguard Worker * Returns 0 on end of file, 1 if valid data returned.
482*1a3d31e3SAndroid Build Coastguard Worker */
next_io(struct ifile_info * iip,struct io_spec * spec)483*1a3d31e3SAndroid Build Coastguard Worker static int next_io(struct ifile_info *iip, struct io_spec *spec)
484*1a3d31e3SAndroid Build Coastguard Worker {
485*1a3d31e3SAndroid Build Coastguard Worker ssize_t ret;
486*1a3d31e3SAndroid Build Coastguard Worker __u32 action;
487*1a3d31e3SAndroid Build Coastguard Worker __u16 pdu_len;
488*1a3d31e3SAndroid Build Coastguard Worker struct blk_io_trace t;
489*1a3d31e3SAndroid Build Coastguard Worker
490*1a3d31e3SAndroid Build Coastguard Worker again:
491*1a3d31e3SAndroid Build Coastguard Worker ret = read(iip->ifd, &t, sizeof(t));
492*1a3d31e3SAndroid Build Coastguard Worker if (ret < 0) {
493*1a3d31e3SAndroid Build Coastguard Worker fatal(iip->file_name, ERR_SYSCALL, "Read failed\n");
494*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
495*1a3d31e3SAndroid Build Coastguard Worker }
496*1a3d31e3SAndroid Build Coastguard Worker else if (ret == 0)
497*1a3d31e3SAndroid Build Coastguard Worker return 0;
498*1a3d31e3SAndroid Build Coastguard Worker else if (ret < (ssize_t)sizeof(t)) {
499*1a3d31e3SAndroid Build Coastguard Worker fprintf(stderr, "WARNING: Short read on %s (%d)\n",
500*1a3d31e3SAndroid Build Coastguard Worker iip->file_name, (int)ret);
501*1a3d31e3SAndroid Build Coastguard Worker return 0;
502*1a3d31e3SAndroid Build Coastguard Worker }
503*1a3d31e3SAndroid Build Coastguard Worker
504*1a3d31e3SAndroid Build Coastguard Worker if (data_is_native == -1)
505*1a3d31e3SAndroid Build Coastguard Worker check_data_endianness(t.magic);
506*1a3d31e3SAndroid Build Coastguard Worker
507*1a3d31e3SAndroid Build Coastguard Worker assert(data_is_native >= 0);
508*1a3d31e3SAndroid Build Coastguard Worker if (data_is_native) {
509*1a3d31e3SAndroid Build Coastguard Worker spec->time = t.time;
510*1a3d31e3SAndroid Build Coastguard Worker spec->sector = t.sector;
511*1a3d31e3SAndroid Build Coastguard Worker spec->bytes = t.bytes;
512*1a3d31e3SAndroid Build Coastguard Worker action = t.action;
513*1a3d31e3SAndroid Build Coastguard Worker pdu_len = t.pdu_len;
514*1a3d31e3SAndroid Build Coastguard Worker }
515*1a3d31e3SAndroid Build Coastguard Worker else {
516*1a3d31e3SAndroid Build Coastguard Worker spec->time = be64_to_cpu(t.time);
517*1a3d31e3SAndroid Build Coastguard Worker spec->sector = be64_to_cpu(t.sector);
518*1a3d31e3SAndroid Build Coastguard Worker spec->bytes = be32_to_cpu(t.bytes);
519*1a3d31e3SAndroid Build Coastguard Worker action = be32_to_cpu(t.action);
520*1a3d31e3SAndroid Build Coastguard Worker pdu_len = be16_to_cpu(t.pdu_len);
521*1a3d31e3SAndroid Build Coastguard Worker }
522*1a3d31e3SAndroid Build Coastguard Worker
523*1a3d31e3SAndroid Build Coastguard Worker
524*1a3d31e3SAndroid Build Coastguard Worker if (pdu_len) {
525*1a3d31e3SAndroid Build Coastguard Worker char buf[pdu_len];
526*1a3d31e3SAndroid Build Coastguard Worker
527*1a3d31e3SAndroid Build Coastguard Worker ret = read(iip->ifd, buf, pdu_len);
528*1a3d31e3SAndroid Build Coastguard Worker if (ret < 0) {
529*1a3d31e3SAndroid Build Coastguard Worker fatal(iip->file_name, ERR_SYSCALL, "Read PDU failed\n");
530*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
531*1a3d31e3SAndroid Build Coastguard Worker }
532*1a3d31e3SAndroid Build Coastguard Worker else if (ret < (ssize_t)pdu_len) {
533*1a3d31e3SAndroid Build Coastguard Worker fprintf(stderr, "WARNING: Short PDU read on %s (%d)\n",
534*1a3d31e3SAndroid Build Coastguard Worker iip->file_name, (int)ret);
535*1a3d31e3SAndroid Build Coastguard Worker return 0;
536*1a3d31e3SAndroid Build Coastguard Worker }
537*1a3d31e3SAndroid Build Coastguard Worker }
538*1a3d31e3SAndroid Build Coastguard Worker
539*1a3d31e3SAndroid Build Coastguard Worker iip->tpkts++;
540*1a3d31e3SAndroid Build Coastguard Worker if (!match(action))
541*1a3d31e3SAndroid Build Coastguard Worker goto again;
542*1a3d31e3SAndroid Build Coastguard Worker
543*1a3d31e3SAndroid Build Coastguard Worker spec->rw = (action & BLK_TC_ACT(BLK_TC_READ)) ? 1 : 0;
544*1a3d31e3SAndroid Build Coastguard Worker if (verbose > 1)
545*1a3d31e3SAndroid Build Coastguard Worker fprintf(stderr, "%2d: %10llu+%10llu (%d) @ %10llx\n",
546*1a3d31e3SAndroid Build Coastguard Worker iip->cpu, (long long unsigned)spec->sector,
547*1a3d31e3SAndroid Build Coastguard Worker (long long unsigned)spec->bytes / 512LLU,
548*1a3d31e3SAndroid Build Coastguard Worker spec->rw, (long long unsigned)spec->time);
549*1a3d31e3SAndroid Build Coastguard Worker
550*1a3d31e3SAndroid Build Coastguard Worker if (iip->genesis == 0) {
551*1a3d31e3SAndroid Build Coastguard Worker iip->genesis = spec->time;
552*1a3d31e3SAndroid Build Coastguard Worker if (verbose > 1)
553*1a3d31e3SAndroid Build Coastguard Worker fprintf(stderr, "\tSetting new genesis: %llx(%d)\n",
554*1a3d31e3SAndroid Build Coastguard Worker (long long unsigned)iip->genesis, iip->cpu);
555*1a3d31e3SAndroid Build Coastguard Worker }
556*1a3d31e3SAndroid Build Coastguard Worker else if (iip->genesis > spec->time)
557*1a3d31e3SAndroid Build Coastguard Worker fatal(NULL, ERR_SYSCALL,
558*1a3d31e3SAndroid Build Coastguard Worker "Time inversion? %llu ... %llu\n",
559*1a3d31e3SAndroid Build Coastguard Worker (long long unsigned )iip->genesis,
560*1a3d31e3SAndroid Build Coastguard Worker (long long unsigned )spec->time);
561*1a3d31e3SAndroid Build Coastguard Worker
562*1a3d31e3SAndroid Build Coastguard Worker return 1;
563*1a3d31e3SAndroid Build Coastguard Worker }
564*1a3d31e3SAndroid Build Coastguard Worker
565*1a3d31e3SAndroid Build Coastguard Worker /**
566*1a3d31e3SAndroid Build Coastguard Worker * bunch_output_hdr - Output bunch header
567*1a3d31e3SAndroid Build Coastguard Worker */
bunch_output_hdr(struct io_stream * stream)568*1a3d31e3SAndroid Build Coastguard Worker static inline void bunch_output_hdr(struct io_stream *stream)
569*1a3d31e3SAndroid Build Coastguard Worker {
570*1a3d31e3SAndroid Build Coastguard Worker struct io_bunch_hdr *hdrp = &stream->cur->hdr;
571*1a3d31e3SAndroid Build Coastguard Worker
572*1a3d31e3SAndroid Build Coastguard Worker assert(0 < hdrp->npkts && hdrp->npkts <= BT_MAX_PKTS);
573*1a3d31e3SAndroid Build Coastguard Worker if (fwrite(hdrp, sizeof(struct io_bunch_hdr), 1, stream->ofp) != 1) {
574*1a3d31e3SAndroid Build Coastguard Worker fatal(stream->file_name, ERR_SYSCALL, "fwrite(hdr) failed\n");
575*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
576*1a3d31e3SAndroid Build Coastguard Worker }
577*1a3d31e3SAndroid Build Coastguard Worker
578*1a3d31e3SAndroid Build Coastguard Worker if (verbose) {
579*1a3d31e3SAndroid Build Coastguard Worker __u64 off = hdrp->time_stamp - stream->iip->genesis;
580*1a3d31e3SAndroid Build Coastguard Worker
581*1a3d31e3SAndroid Build Coastguard Worker assert(stream->vfp);
582*1a3d31e3SAndroid Build Coastguard Worker fprintf(stream->vfp, "------------------\n");
583*1a3d31e3SAndroid Build Coastguard Worker fprintf(stream->vfp, "%4llu.%09llu %3llu\n",
584*1a3d31e3SAndroid Build Coastguard Worker (unsigned long long)off / (1000 * 1000 * 1000),
585*1a3d31e3SAndroid Build Coastguard Worker (unsigned long long)off % (1000 * 1000 * 1000),
586*1a3d31e3SAndroid Build Coastguard Worker (unsigned long long)hdrp->npkts);
587*1a3d31e3SAndroid Build Coastguard Worker fprintf(stream->vfp, "------------------\n");
588*1a3d31e3SAndroid Build Coastguard Worker }
589*1a3d31e3SAndroid Build Coastguard Worker }
590*1a3d31e3SAndroid Build Coastguard Worker
591*1a3d31e3SAndroid Build Coastguard Worker /**
592*1a3d31e3SAndroid Build Coastguard Worker * bunch_output_pkt - Output IO packets
593*1a3d31e3SAndroid Build Coastguard Worker */
bunch_output_pkts(struct io_stream * stream)594*1a3d31e3SAndroid Build Coastguard Worker static inline void bunch_output_pkts(struct io_stream *stream)
595*1a3d31e3SAndroid Build Coastguard Worker {
596*1a3d31e3SAndroid Build Coastguard Worker struct io_pkt *p = stream->cur->pkts;
597*1a3d31e3SAndroid Build Coastguard Worker size_t npkts = stream->cur->hdr.npkts;
598*1a3d31e3SAndroid Build Coastguard Worker
599*1a3d31e3SAndroid Build Coastguard Worker assert(0 < npkts && npkts <= BT_MAX_PKTS);
600*1a3d31e3SAndroid Build Coastguard Worker if (fwrite(p, sizeof(struct io_pkt), npkts, stream->ofp) != npkts) {
601*1a3d31e3SAndroid Build Coastguard Worker fatal(stream->file_name, ERR_SYSCALL, "fwrite(pkts) failed\n");
602*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
603*1a3d31e3SAndroid Build Coastguard Worker }
604*1a3d31e3SAndroid Build Coastguard Worker
605*1a3d31e3SAndroid Build Coastguard Worker if (verbose) {
606*1a3d31e3SAndroid Build Coastguard Worker size_t i;
607*1a3d31e3SAndroid Build Coastguard Worker
608*1a3d31e3SAndroid Build Coastguard Worker assert(stream->vfp);
609*1a3d31e3SAndroid Build Coastguard Worker for (i = 0; i < npkts; i++, p++)
610*1a3d31e3SAndroid Build Coastguard Worker fprintf(stream->vfp, "\t%1d %10llu\t%10llu\n",
611*1a3d31e3SAndroid Build Coastguard Worker p->rw,
612*1a3d31e3SAndroid Build Coastguard Worker (unsigned long long)p->sector,
613*1a3d31e3SAndroid Build Coastguard Worker (unsigned long long)p->nbytes / 512);
614*1a3d31e3SAndroid Build Coastguard Worker }
615*1a3d31e3SAndroid Build Coastguard Worker }
616*1a3d31e3SAndroid Build Coastguard Worker
617*1a3d31e3SAndroid Build Coastguard Worker /**
618*1a3d31e3SAndroid Build Coastguard Worker * stream_flush - Flush current bunch of IOs out to the output stream
619*1a3d31e3SAndroid Build Coastguard Worker * @stream: Per-output file stream information
620*1a3d31e3SAndroid Build Coastguard Worker */
stream_flush(struct io_stream * stream)621*1a3d31e3SAndroid Build Coastguard Worker static void stream_flush(struct io_stream *stream)
622*1a3d31e3SAndroid Build Coastguard Worker {
623*1a3d31e3SAndroid Build Coastguard Worker struct io_bunch *cur = stream->cur;
624*1a3d31e3SAndroid Build Coastguard Worker
625*1a3d31e3SAndroid Build Coastguard Worker if (cur) {
626*1a3d31e3SAndroid Build Coastguard Worker if (cur->hdr.npkts) {
627*1a3d31e3SAndroid Build Coastguard Worker assert(cur->hdr.npkts <= BT_MAX_PKTS);
628*1a3d31e3SAndroid Build Coastguard Worker bunch_output_hdr(stream);
629*1a3d31e3SAndroid Build Coastguard Worker bunch_output_pkts(stream);
630*1a3d31e3SAndroid Build Coastguard Worker
631*1a3d31e3SAndroid Build Coastguard Worker stream->bunches++;
632*1a3d31e3SAndroid Build Coastguard Worker stream->pkts += cur->hdr.npkts;
633*1a3d31e3SAndroid Build Coastguard Worker }
634*1a3d31e3SAndroid Build Coastguard Worker free(cur);
635*1a3d31e3SAndroid Build Coastguard Worker }
636*1a3d31e3SAndroid Build Coastguard Worker }
637*1a3d31e3SAndroid Build Coastguard Worker
638*1a3d31e3SAndroid Build Coastguard Worker /**
639*1a3d31e3SAndroid Build Coastguard Worker * bunch_done - Returns true if current bunch is either full, or next IO is late
640*1a3d31e3SAndroid Build Coastguard Worker * @stream: Output stream information
641*1a3d31e3SAndroid Build Coastguard Worker * @spec: IO trace specification
642*1a3d31e3SAndroid Build Coastguard Worker */
bunch_done(struct io_stream * stream,struct io_spec * spec)643*1a3d31e3SAndroid Build Coastguard Worker static inline int bunch_done(struct io_stream *stream, struct io_spec *spec)
644*1a3d31e3SAndroid Build Coastguard Worker {
645*1a3d31e3SAndroid Build Coastguard Worker if (stream->cur->hdr.npkts >= max_pkts_per_bunch)
646*1a3d31e3SAndroid Build Coastguard Worker return 1;
647*1a3d31e3SAndroid Build Coastguard Worker
648*1a3d31e3SAndroid Build Coastguard Worker if ((spec->time - stream->start_time) > max_bunch_tm)
649*1a3d31e3SAndroid Build Coastguard Worker return 1;
650*1a3d31e3SAndroid Build Coastguard Worker
651*1a3d31e3SAndroid Build Coastguard Worker return 0;
652*1a3d31e3SAndroid Build Coastguard Worker }
653*1a3d31e3SAndroid Build Coastguard Worker
654*1a3d31e3SAndroid Build Coastguard Worker /**
655*1a3d31e3SAndroid Build Coastguard Worker * stream_add_io - Add an IO trace to the current stream
656*1a3d31e3SAndroid Build Coastguard Worker * @stream: Output stream information
657*1a3d31e3SAndroid Build Coastguard Worker * @spec: IO trace specification
658*1a3d31e3SAndroid Build Coastguard Worker */
stream_add_io(struct io_stream * stream,struct io_spec * spec)659*1a3d31e3SAndroid Build Coastguard Worker static void stream_add_io(struct io_stream *stream, struct io_spec *spec)
660*1a3d31e3SAndroid Build Coastguard Worker {
661*1a3d31e3SAndroid Build Coastguard Worker
662*1a3d31e3SAndroid Build Coastguard Worker if (stream->cur == NULL)
663*1a3d31e3SAndroid Build Coastguard Worker io_bunch_create(stream, spec->time);
664*1a3d31e3SAndroid Build Coastguard Worker else if (bunch_done(stream, spec)) {
665*1a3d31e3SAndroid Build Coastguard Worker stream_flush(stream);
666*1a3d31e3SAndroid Build Coastguard Worker io_bunch_create(stream, spec->time);
667*1a3d31e3SAndroid Build Coastguard Worker }
668*1a3d31e3SAndroid Build Coastguard Worker
669*1a3d31e3SAndroid Build Coastguard Worker io_bunch_add(stream, spec);
670*1a3d31e3SAndroid Build Coastguard Worker }
671*1a3d31e3SAndroid Build Coastguard Worker
672*1a3d31e3SAndroid Build Coastguard Worker /**
673*1a3d31e3SAndroid Build Coastguard Worker * stream_open - Open output stream for specified input stream
674*1a3d31e3SAndroid Build Coastguard Worker * @iip: Per-input file information
675*1a3d31e3SAndroid Build Coastguard Worker */
stream_open(struct ifile_info * iip)676*1a3d31e3SAndroid Build Coastguard Worker static struct io_stream *stream_open(struct ifile_info *iip)
677*1a3d31e3SAndroid Build Coastguard Worker {
678*1a3d31e3SAndroid Build Coastguard Worker char ofile_name[MAXPATHLEN];
679*1a3d31e3SAndroid Build Coastguard Worker struct io_stream *stream = malloc(sizeof(*stream));
680*1a3d31e3SAndroid Build Coastguard Worker struct io_file_hdr io_file_hdr = {
681*1a3d31e3SAndroid Build Coastguard Worker .genesis = 0,
682*1a3d31e3SAndroid Build Coastguard Worker .nbunches = 0,
683*1a3d31e3SAndroid Build Coastguard Worker .total_pkts = 0
684*1a3d31e3SAndroid Build Coastguard Worker };
685*1a3d31e3SAndroid Build Coastguard Worker
686*1a3d31e3SAndroid Build Coastguard Worker memset(stream, 0, sizeof(*stream));
687*1a3d31e3SAndroid Build Coastguard Worker
688*1a3d31e3SAndroid Build Coastguard Worker sprintf(ofile_name, "%s/%s.%s.%d", odir, iip->devnm, obase, iip->cpu);
689*1a3d31e3SAndroid Build Coastguard Worker stream->ofp = fopen(ofile_name, "w");
690*1a3d31e3SAndroid Build Coastguard Worker if (!stream->ofp) {
691*1a3d31e3SAndroid Build Coastguard Worker fatal(ofile_name, ERR_SYSCALL, "Open failed\n");
692*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
693*1a3d31e3SAndroid Build Coastguard Worker }
694*1a3d31e3SAndroid Build Coastguard Worker
695*1a3d31e3SAndroid Build Coastguard Worker stream->iip = iip;
696*1a3d31e3SAndroid Build Coastguard Worker stream->cur = NULL;
697*1a3d31e3SAndroid Build Coastguard Worker stream->bunches = stream->pkts = 0;
698*1a3d31e3SAndroid Build Coastguard Worker stream->last_time = 0;
699*1a3d31e3SAndroid Build Coastguard Worker stream->file_name = strdup(ofile_name);
700*1a3d31e3SAndroid Build Coastguard Worker
701*1a3d31e3SAndroid Build Coastguard Worker write_file_hdr(stream, &io_file_hdr);
702*1a3d31e3SAndroid Build Coastguard Worker
703*1a3d31e3SAndroid Build Coastguard Worker if (verbose) {
704*1a3d31e3SAndroid Build Coastguard Worker char vfile_name[MAXPATHLEN];
705*1a3d31e3SAndroid Build Coastguard Worker
706*1a3d31e3SAndroid Build Coastguard Worker sprintf(vfile_name, "%s/%s.%s.%d.rec", odir, iip->devnm,
707*1a3d31e3SAndroid Build Coastguard Worker obase, iip->cpu);
708*1a3d31e3SAndroid Build Coastguard Worker stream->vfp = fopen(vfile_name, "w");
709*1a3d31e3SAndroid Build Coastguard Worker if (!stream->vfp) {
710*1a3d31e3SAndroid Build Coastguard Worker fatal(vfile_name, ERR_SYSCALL, "Open failed\n");
711*1a3d31e3SAndroid Build Coastguard Worker /*NOTREACHED*/
712*1a3d31e3SAndroid Build Coastguard Worker }
713*1a3d31e3SAndroid Build Coastguard Worker
714*1a3d31e3SAndroid Build Coastguard Worker stream->vfn = strdup(vfile_name);
715*1a3d31e3SAndroid Build Coastguard Worker }
716*1a3d31e3SAndroid Build Coastguard Worker
717*1a3d31e3SAndroid Build Coastguard Worker data_is_native = -1;
718*1a3d31e3SAndroid Build Coastguard Worker return stream;
719*1a3d31e3SAndroid Build Coastguard Worker }
720*1a3d31e3SAndroid Build Coastguard Worker
721*1a3d31e3SAndroid Build Coastguard Worker /**
722*1a3d31e3SAndroid Build Coastguard Worker * stream_close - Release resources associated with an output stream
723*1a3d31e3SAndroid Build Coastguard Worker * @stream: Stream to release
724*1a3d31e3SAndroid Build Coastguard Worker */
stream_close(struct io_stream * stream)725*1a3d31e3SAndroid Build Coastguard Worker static void stream_close(struct io_stream *stream)
726*1a3d31e3SAndroid Build Coastguard Worker {
727*1a3d31e3SAndroid Build Coastguard Worker struct io_file_hdr io_file_hdr = {
728*1a3d31e3SAndroid Build Coastguard Worker .genesis = stream->iip->genesis,
729*1a3d31e3SAndroid Build Coastguard Worker .nbunches = stream->bunches,
730*1a3d31e3SAndroid Build Coastguard Worker .total_pkts = stream->pkts
731*1a3d31e3SAndroid Build Coastguard Worker };
732*1a3d31e3SAndroid Build Coastguard Worker
733*1a3d31e3SAndroid Build Coastguard Worker stream_flush(stream);
734*1a3d31e3SAndroid Build Coastguard Worker write_file_hdr(stream, &io_file_hdr);
735*1a3d31e3SAndroid Build Coastguard Worker fclose(stream->ofp);
736*1a3d31e3SAndroid Build Coastguard Worker
737*1a3d31e3SAndroid Build Coastguard Worker if (verbose && stream->bunches) {
738*1a3d31e3SAndroid Build Coastguard Worker fprintf(stderr,
739*1a3d31e3SAndroid Build Coastguard Worker "%s:%d: %llu pkts (tot), %llu pkts (replay), "
740*1a3d31e3SAndroid Build Coastguard Worker "%llu bunches, %.1lf pkts/bunch\n",
741*1a3d31e3SAndroid Build Coastguard Worker stream->iip->devnm, stream->iip->cpu,
742*1a3d31e3SAndroid Build Coastguard Worker (unsigned long long)stream->iip->tpkts,
743*1a3d31e3SAndroid Build Coastguard Worker (unsigned long long)stream->pkts,
744*1a3d31e3SAndroid Build Coastguard Worker (unsigned long long)stream->bunches,
745*1a3d31e3SAndroid Build Coastguard Worker (double)(stream->pkts) / (double)(stream->bunches));
746*1a3d31e3SAndroid Build Coastguard Worker
747*1a3d31e3SAndroid Build Coastguard Worker fclose(stream->vfp);
748*1a3d31e3SAndroid Build Coastguard Worker free(stream->vfn);
749*1a3d31e3SAndroid Build Coastguard Worker }
750*1a3d31e3SAndroid Build Coastguard Worker
751*1a3d31e3SAndroid Build Coastguard Worker free(stream->file_name);
752*1a3d31e3SAndroid Build Coastguard Worker free(stream);
753*1a3d31e3SAndroid Build Coastguard Worker }
754*1a3d31e3SAndroid Build Coastguard Worker
755*1a3d31e3SAndroid Build Coastguard Worker /**
756*1a3d31e3SAndroid Build Coastguard Worker * process - Process one input file to an output file
757*1a3d31e3SAndroid Build Coastguard Worker * @iip: Per-input file information
758*1a3d31e3SAndroid Build Coastguard Worker */
process(struct ifile_info * iip)759*1a3d31e3SAndroid Build Coastguard Worker static void process(struct ifile_info *iip)
760*1a3d31e3SAndroid Build Coastguard Worker {
761*1a3d31e3SAndroid Build Coastguard Worker struct io_spec spec;
762*1a3d31e3SAndroid Build Coastguard Worker struct io_stream *stream;
763*1a3d31e3SAndroid Build Coastguard Worker
764*1a3d31e3SAndroid Build Coastguard Worker stream = stream_open(iip);
765*1a3d31e3SAndroid Build Coastguard Worker while (next_io(iip, &spec))
766*1a3d31e3SAndroid Build Coastguard Worker stream_add_io(stream, &spec);
767*1a3d31e3SAndroid Build Coastguard Worker stream_close(stream);
768*1a3d31e3SAndroid Build Coastguard Worker
769*1a3d31e3SAndroid Build Coastguard Worker rem_input_file(iip);
770*1a3d31e3SAndroid Build Coastguard Worker }
771*1a3d31e3SAndroid Build Coastguard Worker
772*1a3d31e3SAndroid Build Coastguard Worker /**
773*1a3d31e3SAndroid Build Coastguard Worker * main -
774*1a3d31e3SAndroid Build Coastguard Worker * @argc: Number of arguments
775*1a3d31e3SAndroid Build Coastguard Worker * @argv: Array of arguments
776*1a3d31e3SAndroid Build Coastguard Worker */
main(int argc,char * argv[])777*1a3d31e3SAndroid Build Coastguard Worker int main(int argc, char *argv[])
778*1a3d31e3SAndroid Build Coastguard Worker {
779*1a3d31e3SAndroid Build Coastguard Worker struct list_head *p, *q;
780*1a3d31e3SAndroid Build Coastguard Worker
781*1a3d31e3SAndroid Build Coastguard Worker handle_args(argc, argv);
782*1a3d31e3SAndroid Build Coastguard Worker list_for_each_safe(p, q, &input_files)
783*1a3d31e3SAndroid Build Coastguard Worker process(list_entry(p, struct ifile_info, head));
784*1a3d31e3SAndroid Build Coastguard Worker
785*1a3d31e3SAndroid Build Coastguard Worker return 0;
786*1a3d31e3SAndroid Build Coastguard Worker }
787