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