xref: /aosp_15_r20/external/blktrace/iowatcher/blkparse.c (revision 1a3d31e37cc95e9919fd86900a2b6a555f55952c)
1*1a3d31e3SAndroid Build Coastguard Worker /*
2*1a3d31e3SAndroid Build Coastguard Worker  * Copyright (C) 2012 Fusion-io
3*1a3d31e3SAndroid Build Coastguard Worker  *
4*1a3d31e3SAndroid Build Coastguard Worker  *  This program is free software; you can redistribute it and/or
5*1a3d31e3SAndroid Build Coastguard Worker  *  modify it under the terms of the GNU General Public
6*1a3d31e3SAndroid Build Coastguard Worker  *  License v2 as published by the Free Software Foundation.
7*1a3d31e3SAndroid Build Coastguard Worker  *
8*1a3d31e3SAndroid Build Coastguard Worker  *  This program is distributed in the hope that it will be useful,
9*1a3d31e3SAndroid Build Coastguard Worker  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10*1a3d31e3SAndroid Build Coastguard Worker  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11*1a3d31e3SAndroid Build Coastguard Worker  *  GNU General Public License for more details.
12*1a3d31e3SAndroid Build Coastguard Worker  *
13*1a3d31e3SAndroid Build Coastguard Worker  *  You should have received a copy of the GNU General Public License
14*1a3d31e3SAndroid Build Coastguard Worker  *  along with this program; if not, write to the Free Software
15*1a3d31e3SAndroid Build Coastguard Worker  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16*1a3d31e3SAndroid Build Coastguard Worker  *
17*1a3d31e3SAndroid Build Coastguard Worker  *  Parts of this file were imported from Jens Axboe's blktrace sources (also GPL)
18*1a3d31e3SAndroid Build Coastguard Worker  */
19*1a3d31e3SAndroid Build Coastguard Worker #include <sys/types.h>
20*1a3d31e3SAndroid Build Coastguard Worker #include <sys/stat.h>
21*1a3d31e3SAndroid Build Coastguard Worker #include <fcntl.h>
22*1a3d31e3SAndroid Build Coastguard Worker #include <unistd.h>
23*1a3d31e3SAndroid Build Coastguard Worker #include <stdlib.h>
24*1a3d31e3SAndroid Build Coastguard Worker #include <stdio.h>
25*1a3d31e3SAndroid Build Coastguard Worker #include <math.h>
26*1a3d31e3SAndroid Build Coastguard Worker #include <inttypes.h>
27*1a3d31e3SAndroid Build Coastguard Worker #include <string.h>
28*1a3d31e3SAndroid Build Coastguard Worker #include <asm/types.h>
29*1a3d31e3SAndroid Build Coastguard Worker #include <errno.h>
30*1a3d31e3SAndroid Build Coastguard Worker #include <sys/mman.h>
31*1a3d31e3SAndroid Build Coastguard Worker #include <time.h>
32*1a3d31e3SAndroid Build Coastguard Worker #include <math.h>
33*1a3d31e3SAndroid Build Coastguard Worker #include <dirent.h>
34*1a3d31e3SAndroid Build Coastguard Worker 
35*1a3d31e3SAndroid Build Coastguard Worker #include "plot.h"
36*1a3d31e3SAndroid Build Coastguard Worker #include "blkparse.h"
37*1a3d31e3SAndroid Build Coastguard Worker #include "list.h"
38*1a3d31e3SAndroid Build Coastguard Worker #include "tracers.h"
39*1a3d31e3SAndroid Build Coastguard Worker 
40*1a3d31e3SAndroid Build Coastguard Worker #define IO_HASH_TABLE_BITS  11
41*1a3d31e3SAndroid Build Coastguard Worker #define IO_HASH_TABLE_SIZE (1 << IO_HASH_TABLE_BITS)
42*1a3d31e3SAndroid Build Coastguard Worker static struct list_head io_hash_table[IO_HASH_TABLE_SIZE];
43*1a3d31e3SAndroid Build Coastguard Worker static u64 ios_in_flight = 0;
44*1a3d31e3SAndroid Build Coastguard Worker 
45*1a3d31e3SAndroid Build Coastguard Worker #define PROCESS_HASH_TABLE_BITS 7
46*1a3d31e3SAndroid Build Coastguard Worker #define PROCESS_HASH_TABLE_SIZE (1 << PROCESS_HASH_TABLE_BITS)
47*1a3d31e3SAndroid Build Coastguard Worker static struct list_head process_hash_table[PROCESS_HASH_TABLE_SIZE];
48*1a3d31e3SAndroid Build Coastguard Worker 
49*1a3d31e3SAndroid Build Coastguard Worker extern int plot_io_action;
50*1a3d31e3SAndroid Build Coastguard Worker extern int io_per_process;
51*1a3d31e3SAndroid Build Coastguard Worker 
52*1a3d31e3SAndroid Build Coastguard Worker /*
53*1a3d31e3SAndroid Build Coastguard Worker  * Trace categories
54*1a3d31e3SAndroid Build Coastguard Worker  */
55*1a3d31e3SAndroid Build Coastguard Worker enum {
56*1a3d31e3SAndroid Build Coastguard Worker 	BLK_TC_READ	= 1 << 0,	/* reads */
57*1a3d31e3SAndroid Build Coastguard Worker 	BLK_TC_WRITE	= 1 << 1,	/* writes */
58*1a3d31e3SAndroid Build Coastguard Worker 	BLK_TC_FLUSH	= 1 << 2,	/* flush */
59*1a3d31e3SAndroid Build Coastguard Worker 	BLK_TC_SYNC	= 1 << 3,	/* sync */
60*1a3d31e3SAndroid Build Coastguard Worker 	BLK_TC_QUEUE	= 1 << 4,	/* queueing/merging */
61*1a3d31e3SAndroid Build Coastguard Worker 	BLK_TC_REQUEUE	= 1 << 5,	/* requeueing */
62*1a3d31e3SAndroid Build Coastguard Worker 	BLK_TC_ISSUE	= 1 << 6,	/* issue */
63*1a3d31e3SAndroid Build Coastguard Worker 	BLK_TC_COMPLETE	= 1 << 7,	/* completions */
64*1a3d31e3SAndroid Build Coastguard Worker 	BLK_TC_FS	= 1 << 8,	/* fs requests */
65*1a3d31e3SAndroid Build Coastguard Worker 	BLK_TC_PC	= 1 << 9,	/* pc requests */
66*1a3d31e3SAndroid Build Coastguard Worker 	BLK_TC_NOTIFY	= 1 << 10,	/* special message */
67*1a3d31e3SAndroid Build Coastguard Worker 	BLK_TC_AHEAD	= 1 << 11,	/* readahead */
68*1a3d31e3SAndroid Build Coastguard Worker 	BLK_TC_META	= 1 << 12,	/* metadata */
69*1a3d31e3SAndroid Build Coastguard Worker 	BLK_TC_DISCARD	= 1 << 13,	/* discard requests */
70*1a3d31e3SAndroid Build Coastguard Worker 	BLK_TC_DRV_DATA	= 1 << 14,	/* binary driver data */
71*1a3d31e3SAndroid Build Coastguard Worker 	BLK_TC_FUA	= 1 << 15,	/* fua requests */
72*1a3d31e3SAndroid Build Coastguard Worker 
73*1a3d31e3SAndroid Build Coastguard Worker 	BLK_TC_END	= 1 << 15,	/* we've run out of bits! */
74*1a3d31e3SAndroid Build Coastguard Worker };
75*1a3d31e3SAndroid Build Coastguard Worker 
76*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TC_SHIFT		(16)
77*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TC_ACT(act)		((act) << BLK_TC_SHIFT)
78*1a3d31e3SAndroid Build Coastguard Worker #define BLK_DATADIR(a) (((a) >> BLK_TC_SHIFT) & (BLK_TC_READ | BLK_TC_WRITE))
79*1a3d31e3SAndroid Build Coastguard Worker 
80*1a3d31e3SAndroid Build Coastguard Worker /*
81*1a3d31e3SAndroid Build Coastguard Worker  * Basic trace actions
82*1a3d31e3SAndroid Build Coastguard Worker  */
83*1a3d31e3SAndroid Build Coastguard Worker enum {
84*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TA_QUEUE = 1,		/* queued */
85*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TA_BACKMERGE,		/* back merged to existing rq */
86*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TA_FRONTMERGE,		/* front merge to existing rq */
87*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TA_GETRQ,			/* allocated new request */
88*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TA_SLEEPRQ,		/* sleeping on rq allocation */
89*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TA_REQUEUE,		/* request requeued */
90*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TA_ISSUE,			/* sent to driver */
91*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TA_COMPLETE,		/* completed by driver */
92*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TA_PLUG,			/* queue was plugged */
93*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TA_UNPLUG_IO,		/* queue was unplugged by io */
94*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TA_UNPLUG_TIMER,		/* queue was unplugged by timer */
95*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TA_INSERT,		/* insert request */
96*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TA_SPLIT,			/* bio was split */
97*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TA_BOUNCE,		/* bio was bounced */
98*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TA_REMAP,			/* bio was remapped */
99*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TA_ABORT,			/* request aborted */
100*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TA_DRV_DATA,		/* binary driver data */
101*1a3d31e3SAndroid Build Coastguard Worker };
102*1a3d31e3SAndroid Build Coastguard Worker 
103*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TA_MASK ((1 << BLK_TC_SHIFT) - 1)
104*1a3d31e3SAndroid Build Coastguard Worker 
105*1a3d31e3SAndroid Build Coastguard Worker /*
106*1a3d31e3SAndroid Build Coastguard Worker  * Notify events.
107*1a3d31e3SAndroid Build Coastguard Worker  */
108*1a3d31e3SAndroid Build Coastguard Worker enum blktrace_notify {
109*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TN_PROCESS = 0,		/* establish pid/name mapping */
110*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TN_TIMESTAMP,		/* include system clock */
111*1a3d31e3SAndroid Build Coastguard Worker 	__BLK_TN_MESSAGE,               /* Character string message */
112*1a3d31e3SAndroid Build Coastguard Worker };
113*1a3d31e3SAndroid Build Coastguard Worker 
114*1a3d31e3SAndroid Build Coastguard Worker /*
115*1a3d31e3SAndroid Build Coastguard Worker  * Trace actions in full. Additionally, read or write is masked
116*1a3d31e3SAndroid Build Coastguard Worker  */
117*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TA_QUEUE		(__BLK_TA_QUEUE | BLK_TC_ACT(BLK_TC_QUEUE))
118*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TA_BACKMERGE	(__BLK_TA_BACKMERGE | BLK_TC_ACT(BLK_TC_QUEUE))
119*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TA_FRONTMERGE	(__BLK_TA_FRONTMERGE | BLK_TC_ACT(BLK_TC_QUEUE))
120*1a3d31e3SAndroid Build Coastguard Worker #define	BLK_TA_GETRQ		(__BLK_TA_GETRQ | BLK_TC_ACT(BLK_TC_QUEUE))
121*1a3d31e3SAndroid Build Coastguard Worker #define	BLK_TA_SLEEPRQ		(__BLK_TA_SLEEPRQ | BLK_TC_ACT(BLK_TC_QUEUE))
122*1a3d31e3SAndroid Build Coastguard Worker #define	BLK_TA_REQUEUE		(__BLK_TA_REQUEUE | BLK_TC_ACT(BLK_TC_REQUEUE))
123*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TA_ISSUE		(__BLK_TA_ISSUE | BLK_TC_ACT(BLK_TC_ISSUE))
124*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TA_COMPLETE		(__BLK_TA_COMPLETE| BLK_TC_ACT(BLK_TC_COMPLETE))
125*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TA_PLUG		(__BLK_TA_PLUG | BLK_TC_ACT(BLK_TC_QUEUE))
126*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TA_UNPLUG_IO	(__BLK_TA_UNPLUG_IO | BLK_TC_ACT(BLK_TC_QUEUE))
127*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TA_UNPLUG_TIMER	(__BLK_TA_UNPLUG_TIMER | BLK_TC_ACT(BLK_TC_QUEUE))
128*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TA_INSERT		(__BLK_TA_INSERT | BLK_TC_ACT(BLK_TC_QUEUE))
129*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TA_SPLIT		(__BLK_TA_SPLIT)
130*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TA_BOUNCE		(__BLK_TA_BOUNCE)
131*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TA_REMAP		(__BLK_TA_REMAP | BLK_TC_ACT(BLK_TC_QUEUE))
132*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TA_ABORT		(__BLK_TA_ABORT | BLK_TC_ACT(BLK_TC_QUEUE))
133*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TA_DRV_DATA		(__BLK_TA_DRV_DATA | BLK_TC_ACT(BLK_TC_DRV_DATA))
134*1a3d31e3SAndroid Build Coastguard Worker 
135*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TN_PROCESS		(__BLK_TN_PROCESS | BLK_TC_ACT(BLK_TC_NOTIFY))
136*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TN_TIMESTAMP	(__BLK_TN_TIMESTAMP | BLK_TC_ACT(BLK_TC_NOTIFY))
137*1a3d31e3SAndroid Build Coastguard Worker #define BLK_TN_MESSAGE		(__BLK_TN_MESSAGE | BLK_TC_ACT(BLK_TC_NOTIFY))
138*1a3d31e3SAndroid Build Coastguard Worker 
139*1a3d31e3SAndroid Build Coastguard Worker #define BLK_IO_TRACE_MAGIC	0x65617400
140*1a3d31e3SAndroid Build Coastguard Worker #define BLK_IO_TRACE_VERSION	0x07
141*1a3d31e3SAndroid Build Coastguard Worker /*
142*1a3d31e3SAndroid Build Coastguard Worker  * The trace itself
143*1a3d31e3SAndroid Build Coastguard Worker  */
144*1a3d31e3SAndroid Build Coastguard Worker struct blk_io_trace {
145*1a3d31e3SAndroid Build Coastguard Worker 	__u32 magic;		/* MAGIC << 8 | version */
146*1a3d31e3SAndroid Build Coastguard Worker 	__u32 sequence;		/* event number */
147*1a3d31e3SAndroid Build Coastguard Worker 	__u64 time;		/* in nanoseconds */
148*1a3d31e3SAndroid Build Coastguard Worker 	__u64 sector;		/* disk offset */
149*1a3d31e3SAndroid Build Coastguard Worker 	__u32 bytes;		/* transfer length */
150*1a3d31e3SAndroid Build Coastguard Worker 	__u32 action;		/* what happened */
151*1a3d31e3SAndroid Build Coastguard Worker 	__u32 pid;		/* who did it */
152*1a3d31e3SAndroid Build Coastguard Worker 	__u32 device;		/* device identifier (dev_t) */
153*1a3d31e3SAndroid Build Coastguard Worker 	__u32 cpu;		/* on what cpu did it happen */
154*1a3d31e3SAndroid Build Coastguard Worker 	__u16 error;		/* completion error */
155*1a3d31e3SAndroid Build Coastguard Worker 	__u16 pdu_len;		/* length of data after this trace */
156*1a3d31e3SAndroid Build Coastguard Worker };
157*1a3d31e3SAndroid Build Coastguard Worker 
158*1a3d31e3SAndroid Build Coastguard Worker struct pending_io {
159*1a3d31e3SAndroid Build Coastguard Worker 	/* sector offset of this IO */
160*1a3d31e3SAndroid Build Coastguard Worker 	u64 sector;
161*1a3d31e3SAndroid Build Coastguard Worker 
162*1a3d31e3SAndroid Build Coastguard Worker 	/* dev_t for this IO */
163*1a3d31e3SAndroid Build Coastguard Worker 	u32 device;
164*1a3d31e3SAndroid Build Coastguard Worker 
165*1a3d31e3SAndroid Build Coastguard Worker 	/* time this IO was dispatched */
166*1a3d31e3SAndroid Build Coastguard Worker 	u64 dispatch_time;
167*1a3d31e3SAndroid Build Coastguard Worker 	/* time this IO was finished */
168*1a3d31e3SAndroid Build Coastguard Worker 	u64 completion_time;
169*1a3d31e3SAndroid Build Coastguard Worker 	struct list_head hash_list;
170*1a3d31e3SAndroid Build Coastguard Worker 	/* process which queued this IO */
171*1a3d31e3SAndroid Build Coastguard Worker 	u32 pid;
172*1a3d31e3SAndroid Build Coastguard Worker };
173*1a3d31e3SAndroid Build Coastguard Worker 
174*1a3d31e3SAndroid Build Coastguard Worker struct pid_map {
175*1a3d31e3SAndroid Build Coastguard Worker 	struct list_head hash_list;
176*1a3d31e3SAndroid Build Coastguard Worker 	u32 pid;
177*1a3d31e3SAndroid Build Coastguard Worker 	int index;
178*1a3d31e3SAndroid Build Coastguard Worker 	char name[0];
179*1a3d31e3SAndroid Build Coastguard Worker };
180*1a3d31e3SAndroid Build Coastguard Worker 
get_record_time(struct trace * trace)181*1a3d31e3SAndroid Build Coastguard Worker u64 get_record_time(struct trace *trace)
182*1a3d31e3SAndroid Build Coastguard Worker {
183*1a3d31e3SAndroid Build Coastguard Worker 	return trace->io->time;
184*1a3d31e3SAndroid Build Coastguard Worker }
185*1a3d31e3SAndroid Build Coastguard Worker 
init_io_hash_table(void)186*1a3d31e3SAndroid Build Coastguard Worker void init_io_hash_table(void)
187*1a3d31e3SAndroid Build Coastguard Worker {
188*1a3d31e3SAndroid Build Coastguard Worker 	int i;
189*1a3d31e3SAndroid Build Coastguard Worker 	struct list_head *head;
190*1a3d31e3SAndroid Build Coastguard Worker 
191*1a3d31e3SAndroid Build Coastguard Worker 	for (i = 0; i < IO_HASH_TABLE_SIZE; i++) {
192*1a3d31e3SAndroid Build Coastguard Worker 		head = io_hash_table + i;
193*1a3d31e3SAndroid Build Coastguard Worker 		INIT_LIST_HEAD(head);
194*1a3d31e3SAndroid Build Coastguard Worker 	}
195*1a3d31e3SAndroid Build Coastguard Worker }
196*1a3d31e3SAndroid Build Coastguard Worker 
197*1a3d31e3SAndroid Build Coastguard Worker /* taken from the kernel hash.h */
hash_sector(u64 val)198*1a3d31e3SAndroid Build Coastguard Worker static inline u64 hash_sector(u64 val)
199*1a3d31e3SAndroid Build Coastguard Worker {
200*1a3d31e3SAndroid Build Coastguard Worker 	u64 hash = val;
201*1a3d31e3SAndroid Build Coastguard Worker 
202*1a3d31e3SAndroid Build Coastguard Worker 	/*  Sigh, gcc can't optimise this alone like it does for 32 bits. */
203*1a3d31e3SAndroid Build Coastguard Worker 	u64 n = hash;
204*1a3d31e3SAndroid Build Coastguard Worker 	n <<= 18;
205*1a3d31e3SAndroid Build Coastguard Worker 	hash -= n;
206*1a3d31e3SAndroid Build Coastguard Worker 	n <<= 33;
207*1a3d31e3SAndroid Build Coastguard Worker 	hash -= n;
208*1a3d31e3SAndroid Build Coastguard Worker 	n <<= 3;
209*1a3d31e3SAndroid Build Coastguard Worker 	hash += n;
210*1a3d31e3SAndroid Build Coastguard Worker 	n <<= 3;
211*1a3d31e3SAndroid Build Coastguard Worker 	hash -= n;
212*1a3d31e3SAndroid Build Coastguard Worker 	n <<= 4;
213*1a3d31e3SAndroid Build Coastguard Worker 	hash += n;
214*1a3d31e3SAndroid Build Coastguard Worker 	n <<= 2;
215*1a3d31e3SAndroid Build Coastguard Worker 	hash += n;
216*1a3d31e3SAndroid Build Coastguard Worker 
217*1a3d31e3SAndroid Build Coastguard Worker 	/* High bits are more random, so use them. */
218*1a3d31e3SAndroid Build Coastguard Worker 	return hash >> (64 - IO_HASH_TABLE_BITS);
219*1a3d31e3SAndroid Build Coastguard Worker }
220*1a3d31e3SAndroid Build Coastguard Worker 
io_hash_table_insert(struct pending_io * ins_pio)221*1a3d31e3SAndroid Build Coastguard Worker static int io_hash_table_insert(struct pending_io *ins_pio)
222*1a3d31e3SAndroid Build Coastguard Worker {
223*1a3d31e3SAndroid Build Coastguard Worker 	u64 sector = ins_pio->sector;
224*1a3d31e3SAndroid Build Coastguard Worker 	u32 dev = ins_pio->device;
225*1a3d31e3SAndroid Build Coastguard Worker 	int slot = hash_sector(sector);
226*1a3d31e3SAndroid Build Coastguard Worker 	struct list_head *head;
227*1a3d31e3SAndroid Build Coastguard Worker 	struct pending_io *pio;
228*1a3d31e3SAndroid Build Coastguard Worker 
229*1a3d31e3SAndroid Build Coastguard Worker 	head = io_hash_table + slot;
230*1a3d31e3SAndroid Build Coastguard Worker 	list_for_each_entry(pio, head, hash_list) {
231*1a3d31e3SAndroid Build Coastguard Worker 		if (pio->sector == sector && pio->device == dev)
232*1a3d31e3SAndroid Build Coastguard Worker 			return -EEXIST;
233*1a3d31e3SAndroid Build Coastguard Worker 	}
234*1a3d31e3SAndroid Build Coastguard Worker 	list_add_tail(&ins_pio->hash_list, head);
235*1a3d31e3SAndroid Build Coastguard Worker 	return 0;
236*1a3d31e3SAndroid Build Coastguard Worker }
237*1a3d31e3SAndroid Build Coastguard Worker 
io_hash_table_search(u64 sector,u32 dev)238*1a3d31e3SAndroid Build Coastguard Worker static struct pending_io *io_hash_table_search(u64 sector, u32 dev)
239*1a3d31e3SAndroid Build Coastguard Worker {
240*1a3d31e3SAndroid Build Coastguard Worker 	int slot = hash_sector(sector);
241*1a3d31e3SAndroid Build Coastguard Worker 	struct list_head *head;
242*1a3d31e3SAndroid Build Coastguard Worker 	struct pending_io *pio;
243*1a3d31e3SAndroid Build Coastguard Worker 
244*1a3d31e3SAndroid Build Coastguard Worker 	head = io_hash_table + slot;
245*1a3d31e3SAndroid Build Coastguard Worker 	list_for_each_entry(pio, head, hash_list) {
246*1a3d31e3SAndroid Build Coastguard Worker 		if (pio->sector == sector && pio->device == dev)
247*1a3d31e3SAndroid Build Coastguard Worker 			return pio;
248*1a3d31e3SAndroid Build Coastguard Worker 	}
249*1a3d31e3SAndroid Build Coastguard Worker 	return NULL;
250*1a3d31e3SAndroid Build Coastguard Worker }
251*1a3d31e3SAndroid Build Coastguard Worker 
hash_queued_io(struct blk_io_trace * io)252*1a3d31e3SAndroid Build Coastguard Worker static struct pending_io *hash_queued_io(struct blk_io_trace *io)
253*1a3d31e3SAndroid Build Coastguard Worker {
254*1a3d31e3SAndroid Build Coastguard Worker 	struct pending_io *pio;
255*1a3d31e3SAndroid Build Coastguard Worker 	int ret;
256*1a3d31e3SAndroid Build Coastguard Worker 
257*1a3d31e3SAndroid Build Coastguard Worker 	pio = calloc(1, sizeof(*pio));
258*1a3d31e3SAndroid Build Coastguard Worker 	pio->sector = io->sector;
259*1a3d31e3SAndroid Build Coastguard Worker 	pio->device = io->device;
260*1a3d31e3SAndroid Build Coastguard Worker 	pio->pid = io->pid;
261*1a3d31e3SAndroid Build Coastguard Worker 
262*1a3d31e3SAndroid Build Coastguard Worker 	ret = io_hash_table_insert(pio);
263*1a3d31e3SAndroid Build Coastguard Worker 	if (ret < 0) {
264*1a3d31e3SAndroid Build Coastguard Worker 		/* crud, the IO is there already */
265*1a3d31e3SAndroid Build Coastguard Worker 		free(pio);
266*1a3d31e3SAndroid Build Coastguard Worker 		return NULL;
267*1a3d31e3SAndroid Build Coastguard Worker 	}
268*1a3d31e3SAndroid Build Coastguard Worker 	return pio;
269*1a3d31e3SAndroid Build Coastguard Worker }
270*1a3d31e3SAndroid Build Coastguard Worker 
hash_dispatched_io(struct blk_io_trace * io)271*1a3d31e3SAndroid Build Coastguard Worker static struct pending_io *hash_dispatched_io(struct blk_io_trace *io)
272*1a3d31e3SAndroid Build Coastguard Worker {
273*1a3d31e3SAndroid Build Coastguard Worker 	struct pending_io *pio;
274*1a3d31e3SAndroid Build Coastguard Worker 
275*1a3d31e3SAndroid Build Coastguard Worker 	pio = io_hash_table_search(io->sector, io->device);
276*1a3d31e3SAndroid Build Coastguard Worker 	if (!pio) {
277*1a3d31e3SAndroid Build Coastguard Worker 		pio = hash_queued_io(io);
278*1a3d31e3SAndroid Build Coastguard Worker 		if (!pio)
279*1a3d31e3SAndroid Build Coastguard Worker 			return NULL;
280*1a3d31e3SAndroid Build Coastguard Worker 	}
281*1a3d31e3SAndroid Build Coastguard Worker 	pio->dispatch_time = io->time;
282*1a3d31e3SAndroid Build Coastguard Worker 	return pio;
283*1a3d31e3SAndroid Build Coastguard Worker }
284*1a3d31e3SAndroid Build Coastguard Worker 
hash_completed_io(struct blk_io_trace * io)285*1a3d31e3SAndroid Build Coastguard Worker static struct pending_io *hash_completed_io(struct blk_io_trace *io)
286*1a3d31e3SAndroid Build Coastguard Worker {
287*1a3d31e3SAndroid Build Coastguard Worker 	struct pending_io *pio;
288*1a3d31e3SAndroid Build Coastguard Worker 
289*1a3d31e3SAndroid Build Coastguard Worker 	pio = io_hash_table_search(io->sector, io->device);
290*1a3d31e3SAndroid Build Coastguard Worker 
291*1a3d31e3SAndroid Build Coastguard Worker 	if (!pio)
292*1a3d31e3SAndroid Build Coastguard Worker 		return NULL;
293*1a3d31e3SAndroid Build Coastguard Worker 	return pio;
294*1a3d31e3SAndroid Build Coastguard Worker }
295*1a3d31e3SAndroid Build Coastguard Worker 
init_process_hash_table(void)296*1a3d31e3SAndroid Build Coastguard Worker void init_process_hash_table(void)
297*1a3d31e3SAndroid Build Coastguard Worker {
298*1a3d31e3SAndroid Build Coastguard Worker 	int i;
299*1a3d31e3SAndroid Build Coastguard Worker 	struct list_head *head;
300*1a3d31e3SAndroid Build Coastguard Worker 
301*1a3d31e3SAndroid Build Coastguard Worker 	for (i = 0; i < PROCESS_HASH_TABLE_SIZE; i++) {
302*1a3d31e3SAndroid Build Coastguard Worker 		head = process_hash_table + i;
303*1a3d31e3SAndroid Build Coastguard Worker 		INIT_LIST_HEAD(head);
304*1a3d31e3SAndroid Build Coastguard Worker 	}
305*1a3d31e3SAndroid Build Coastguard Worker }
306*1a3d31e3SAndroid Build Coastguard Worker 
hash_pid(u32 pid)307*1a3d31e3SAndroid Build Coastguard Worker static u32 hash_pid(u32 pid)
308*1a3d31e3SAndroid Build Coastguard Worker {
309*1a3d31e3SAndroid Build Coastguard Worker 	u32 hash = pid;
310*1a3d31e3SAndroid Build Coastguard Worker 
311*1a3d31e3SAndroid Build Coastguard Worker 	hash ^= pid >> 3;
312*1a3d31e3SAndroid Build Coastguard Worker 	hash ^= pid >> 3;
313*1a3d31e3SAndroid Build Coastguard Worker 	hash ^= pid >> 4;
314*1a3d31e3SAndroid Build Coastguard Worker 	hash ^= pid >> 6;
315*1a3d31e3SAndroid Build Coastguard Worker 	return (hash & (PROCESS_HASH_TABLE_SIZE - 1));
316*1a3d31e3SAndroid Build Coastguard Worker }
317*1a3d31e3SAndroid Build Coastguard Worker 
process_hash_search(u32 pid)318*1a3d31e3SAndroid Build Coastguard Worker static struct pid_map *process_hash_search(u32 pid)
319*1a3d31e3SAndroid Build Coastguard Worker {
320*1a3d31e3SAndroid Build Coastguard Worker 	int slot = hash_pid(pid);
321*1a3d31e3SAndroid Build Coastguard Worker 	struct list_head *head;
322*1a3d31e3SAndroid Build Coastguard Worker 	struct pid_map *pm;
323*1a3d31e3SAndroid Build Coastguard Worker 
324*1a3d31e3SAndroid Build Coastguard Worker 	head = process_hash_table + slot;
325*1a3d31e3SAndroid Build Coastguard Worker 	list_for_each_entry(pm, head, hash_list) {
326*1a3d31e3SAndroid Build Coastguard Worker 		if (pm->pid == pid)
327*1a3d31e3SAndroid Build Coastguard Worker 			return pm;
328*1a3d31e3SAndroid Build Coastguard Worker 	}
329*1a3d31e3SAndroid Build Coastguard Worker 	return NULL;
330*1a3d31e3SAndroid Build Coastguard Worker }
331*1a3d31e3SAndroid Build Coastguard Worker 
process_hash_insert(u32 pid,char * name)332*1a3d31e3SAndroid Build Coastguard Worker static struct pid_map *process_hash_insert(u32 pid, char *name)
333*1a3d31e3SAndroid Build Coastguard Worker {
334*1a3d31e3SAndroid Build Coastguard Worker 	int slot = hash_pid(pid);
335*1a3d31e3SAndroid Build Coastguard Worker 	struct pid_map *pm;
336*1a3d31e3SAndroid Build Coastguard Worker 	int old_index = 0;
337*1a3d31e3SAndroid Build Coastguard Worker 	char buf[16];
338*1a3d31e3SAndroid Build Coastguard Worker 
339*1a3d31e3SAndroid Build Coastguard Worker 	pm = process_hash_search(pid);
340*1a3d31e3SAndroid Build Coastguard Worker 	if (pm) {
341*1a3d31e3SAndroid Build Coastguard Worker 		/* Entry exists and name shouldn't be changed? */
342*1a3d31e3SAndroid Build Coastguard Worker 		if (!name || !strcmp(name, pm->name))
343*1a3d31e3SAndroid Build Coastguard Worker 			return pm;
344*1a3d31e3SAndroid Build Coastguard Worker 		list_del(&pm->hash_list);
345*1a3d31e3SAndroid Build Coastguard Worker 		old_index = pm->index;
346*1a3d31e3SAndroid Build Coastguard Worker 		free(pm);
347*1a3d31e3SAndroid Build Coastguard Worker 	}
348*1a3d31e3SAndroid Build Coastguard Worker 	if (!name) {
349*1a3d31e3SAndroid Build Coastguard Worker 		sprintf(buf, "[%u]", pid);
350*1a3d31e3SAndroid Build Coastguard Worker 		name = buf;
351*1a3d31e3SAndroid Build Coastguard Worker 	}
352*1a3d31e3SAndroid Build Coastguard Worker 	pm = malloc(sizeof(struct pid_map) + strlen(name) + 1);
353*1a3d31e3SAndroid Build Coastguard Worker 	pm->pid = pid;
354*1a3d31e3SAndroid Build Coastguard Worker 	pm->index = old_index;
355*1a3d31e3SAndroid Build Coastguard Worker 	strcpy(pm->name, name);
356*1a3d31e3SAndroid Build Coastguard Worker 	list_add_tail(&pm->hash_list, process_hash_table + slot);
357*1a3d31e3SAndroid Build Coastguard Worker 
358*1a3d31e3SAndroid Build Coastguard Worker 	return pm;
359*1a3d31e3SAndroid Build Coastguard Worker }
360*1a3d31e3SAndroid Build Coastguard Worker 
handle_notify(struct trace * trace)361*1a3d31e3SAndroid Build Coastguard Worker static void handle_notify(struct trace *trace)
362*1a3d31e3SAndroid Build Coastguard Worker {
363*1a3d31e3SAndroid Build Coastguard Worker 	struct blk_io_trace *io = trace->io;
364*1a3d31e3SAndroid Build Coastguard Worker 	void *payload = (char *)io + sizeof(*io);
365*1a3d31e3SAndroid Build Coastguard Worker 	u32 two32[2];
366*1a3d31e3SAndroid Build Coastguard Worker 
367*1a3d31e3SAndroid Build Coastguard Worker 	if (io->action == BLK_TN_PROCESS) {
368*1a3d31e3SAndroid Build Coastguard Worker 		if (io_per_process)
369*1a3d31e3SAndroid Build Coastguard Worker 			process_hash_insert(io->pid, payload);
370*1a3d31e3SAndroid Build Coastguard Worker 		return;
371*1a3d31e3SAndroid Build Coastguard Worker 	}
372*1a3d31e3SAndroid Build Coastguard Worker 
373*1a3d31e3SAndroid Build Coastguard Worker 	if (io->action != BLK_TN_TIMESTAMP)
374*1a3d31e3SAndroid Build Coastguard Worker 		return;
375*1a3d31e3SAndroid Build Coastguard Worker 
376*1a3d31e3SAndroid Build Coastguard Worker 	if (io->pdu_len != sizeof(two32))
377*1a3d31e3SAndroid Build Coastguard Worker 		return;
378*1a3d31e3SAndroid Build Coastguard Worker 
379*1a3d31e3SAndroid Build Coastguard Worker 	memcpy(two32, payload, sizeof(two32));
380*1a3d31e3SAndroid Build Coastguard Worker 	trace->start_timestamp = io->time;
381*1a3d31e3SAndroid Build Coastguard Worker 	trace->abs_start_time.tv_sec = two32[0];
382*1a3d31e3SAndroid Build Coastguard Worker 	trace->abs_start_time.tv_nsec = two32[1];
383*1a3d31e3SAndroid Build Coastguard Worker 	if (trace->abs_start_time.tv_nsec < 0) {
384*1a3d31e3SAndroid Build Coastguard Worker 		trace->abs_start_time.tv_sec--;
385*1a3d31e3SAndroid Build Coastguard Worker 		trace->abs_start_time.tv_nsec += 1000000000;
386*1a3d31e3SAndroid Build Coastguard Worker 	}
387*1a3d31e3SAndroid Build Coastguard Worker }
388*1a3d31e3SAndroid Build Coastguard Worker 
next_record(struct trace * trace)389*1a3d31e3SAndroid Build Coastguard Worker int next_record(struct trace *trace)
390*1a3d31e3SAndroid Build Coastguard Worker {
391*1a3d31e3SAndroid Build Coastguard Worker 	int skip = trace->io->pdu_len;
392*1a3d31e3SAndroid Build Coastguard Worker 	u64 offset;
393*1a3d31e3SAndroid Build Coastguard Worker 
394*1a3d31e3SAndroid Build Coastguard Worker 	trace->cur += sizeof(*trace->io) + skip;
395*1a3d31e3SAndroid Build Coastguard Worker 	offset = trace->cur - trace->start;
396*1a3d31e3SAndroid Build Coastguard Worker 	if (offset >= trace->len)
397*1a3d31e3SAndroid Build Coastguard Worker 		return 1;
398*1a3d31e3SAndroid Build Coastguard Worker 
399*1a3d31e3SAndroid Build Coastguard Worker 	trace->io = (struct blk_io_trace *)trace->cur;
400*1a3d31e3SAndroid Build Coastguard Worker 	return 0;
401*1a3d31e3SAndroid Build Coastguard Worker }
402*1a3d31e3SAndroid Build Coastguard Worker 
first_record(struct trace * trace)403*1a3d31e3SAndroid Build Coastguard Worker void first_record(struct trace *trace)
404*1a3d31e3SAndroid Build Coastguard Worker {
405*1a3d31e3SAndroid Build Coastguard Worker 	trace->cur = trace->start;
406*1a3d31e3SAndroid Build Coastguard Worker 	trace->io = (struct blk_io_trace *)trace->cur;
407*1a3d31e3SAndroid Build Coastguard Worker }
408*1a3d31e3SAndroid Build Coastguard Worker 
is_io_event(struct blk_io_trace * test)409*1a3d31e3SAndroid Build Coastguard Worker static int is_io_event(struct blk_io_trace *test)
410*1a3d31e3SAndroid Build Coastguard Worker {
411*1a3d31e3SAndroid Build Coastguard Worker 	char *message;
412*1a3d31e3SAndroid Build Coastguard Worker 	if (!(test->action & BLK_TC_ACT(BLK_TC_NOTIFY)))
413*1a3d31e3SAndroid Build Coastguard Worker 		return 1;
414*1a3d31e3SAndroid Build Coastguard Worker 	if (test->action == BLK_TN_MESSAGE) {
415*1a3d31e3SAndroid Build Coastguard Worker 		int len = test->pdu_len;
416*1a3d31e3SAndroid Build Coastguard Worker 		if (len < 3)
417*1a3d31e3SAndroid Build Coastguard Worker 			return 0;
418*1a3d31e3SAndroid Build Coastguard Worker 		message = (char *)(test + 1);
419*1a3d31e3SAndroid Build Coastguard Worker 		if (strncmp(message, "fio ", 4) == 0) {
420*1a3d31e3SAndroid Build Coastguard Worker 			return 1;
421*1a3d31e3SAndroid Build Coastguard Worker 		}
422*1a3d31e3SAndroid Build Coastguard Worker 	}
423*1a3d31e3SAndroid Build Coastguard Worker 	return 0;
424*1a3d31e3SAndroid Build Coastguard Worker }
425*1a3d31e3SAndroid Build Coastguard Worker 
find_last_time(struct trace * trace)426*1a3d31e3SAndroid Build Coastguard Worker u64 find_last_time(struct trace *trace)
427*1a3d31e3SAndroid Build Coastguard Worker {
428*1a3d31e3SAndroid Build Coastguard Worker 	char *p = trace->start + trace->len;
429*1a3d31e3SAndroid Build Coastguard Worker 	struct blk_io_trace *test;
430*1a3d31e3SAndroid Build Coastguard Worker 	int search_len = 0;
431*1a3d31e3SAndroid Build Coastguard Worker 	u64 found = 0;
432*1a3d31e3SAndroid Build Coastguard Worker 
433*1a3d31e3SAndroid Build Coastguard Worker 	if (trace->len < sizeof(*trace->io))
434*1a3d31e3SAndroid Build Coastguard Worker 		return 0;
435*1a3d31e3SAndroid Build Coastguard Worker 	p -= sizeof(*trace->io);
436*1a3d31e3SAndroid Build Coastguard Worker 	while (p >= trace->start) {
437*1a3d31e3SAndroid Build Coastguard Worker 		test = (struct blk_io_trace *)p;
438*1a3d31e3SAndroid Build Coastguard Worker 		if (CHECK_MAGIC(test) && is_io_event(test)) {
439*1a3d31e3SAndroid Build Coastguard Worker 			u64 offset = p - trace->start;
440*1a3d31e3SAndroid Build Coastguard Worker 			if (offset + sizeof(*test) + test->pdu_len == trace->len) {
441*1a3d31e3SAndroid Build Coastguard Worker 				return test->time;
442*1a3d31e3SAndroid Build Coastguard Worker 			}
443*1a3d31e3SAndroid Build Coastguard Worker 		}
444*1a3d31e3SAndroid Build Coastguard Worker 		p--;
445*1a3d31e3SAndroid Build Coastguard Worker 		search_len++;
446*1a3d31e3SAndroid Build Coastguard Worker 		if (search_len > 8192) {
447*1a3d31e3SAndroid Build Coastguard Worker 			break;
448*1a3d31e3SAndroid Build Coastguard Worker 		}
449*1a3d31e3SAndroid Build Coastguard Worker 	}
450*1a3d31e3SAndroid Build Coastguard Worker 
451*1a3d31e3SAndroid Build Coastguard Worker 	/* searching backwards didn't work out, we'll have to scan the file */
452*1a3d31e3SAndroid Build Coastguard Worker 	first_record(trace);
453*1a3d31e3SAndroid Build Coastguard Worker 	while (1) {
454*1a3d31e3SAndroid Build Coastguard Worker 		if (is_io_event(trace->io))
455*1a3d31e3SAndroid Build Coastguard Worker 			found = trace->io->time;
456*1a3d31e3SAndroid Build Coastguard Worker 		if (next_record(trace))
457*1a3d31e3SAndroid Build Coastguard Worker 			break;
458*1a3d31e3SAndroid Build Coastguard Worker 	}
459*1a3d31e3SAndroid Build Coastguard Worker 	first_record(trace);
460*1a3d31e3SAndroid Build Coastguard Worker 	return found;
461*1a3d31e3SAndroid Build Coastguard Worker }
462*1a3d31e3SAndroid Build Coastguard Worker 
parse_fio_bank_message(struct trace * trace,u64 * bank_ret,u64 * offset_ret,u64 * num_banks_ret)463*1a3d31e3SAndroid Build Coastguard Worker static int parse_fio_bank_message(struct trace *trace, u64 *bank_ret, u64 *offset_ret,
464*1a3d31e3SAndroid Build Coastguard Worker 			   u64 *num_banks_ret)
465*1a3d31e3SAndroid Build Coastguard Worker {
466*1a3d31e3SAndroid Build Coastguard Worker 	char *s;
467*1a3d31e3SAndroid Build Coastguard Worker 	char *next;
468*1a3d31e3SAndroid Build Coastguard Worker 	char *message;
469*1a3d31e3SAndroid Build Coastguard Worker 	struct blk_io_trace *test = trace->io;
470*1a3d31e3SAndroid Build Coastguard Worker 	int len = test->pdu_len;
471*1a3d31e3SAndroid Build Coastguard Worker 	u64 bank;
472*1a3d31e3SAndroid Build Coastguard Worker 	u64 offset;
473*1a3d31e3SAndroid Build Coastguard Worker 	u64 num_banks;
474*1a3d31e3SAndroid Build Coastguard Worker 
475*1a3d31e3SAndroid Build Coastguard Worker 	if (!(test->action & BLK_TC_ACT(BLK_TC_NOTIFY)))
476*1a3d31e3SAndroid Build Coastguard Worker 		return -1;
477*1a3d31e3SAndroid Build Coastguard Worker 	if (test->action != BLK_TN_MESSAGE)
478*1a3d31e3SAndroid Build Coastguard Worker 		return -1;
479*1a3d31e3SAndroid Build Coastguard Worker 
480*1a3d31e3SAndroid Build Coastguard Worker 	/* the message is fio rw bank offset num_banks */
481*1a3d31e3SAndroid Build Coastguard Worker 	if (len < 3)
482*1a3d31e3SAndroid Build Coastguard Worker 		return -1;
483*1a3d31e3SAndroid Build Coastguard Worker 	message = (char *)(test + 1);
484*1a3d31e3SAndroid Build Coastguard Worker 	if (strncmp(message, "fio r ", 6) != 0)
485*1a3d31e3SAndroid Build Coastguard Worker 		return -1;
486*1a3d31e3SAndroid Build Coastguard Worker 
487*1a3d31e3SAndroid Build Coastguard Worker 	message = strndup(message, len);
488*1a3d31e3SAndroid Build Coastguard Worker 	s = strchr(message, ' ');
489*1a3d31e3SAndroid Build Coastguard Worker 	if (!s)
490*1a3d31e3SAndroid Build Coastguard Worker 		goto out;
491*1a3d31e3SAndroid Build Coastguard Worker 	s++;
492*1a3d31e3SAndroid Build Coastguard Worker 	s = strchr(s, ' ');
493*1a3d31e3SAndroid Build Coastguard Worker 	if (!s)
494*1a3d31e3SAndroid Build Coastguard Worker 		goto out;
495*1a3d31e3SAndroid Build Coastguard Worker 
496*1a3d31e3SAndroid Build Coastguard Worker 	bank = strtoll(s, &next, 10);
497*1a3d31e3SAndroid Build Coastguard Worker 	if (s == next)
498*1a3d31e3SAndroid Build Coastguard Worker 		goto out;
499*1a3d31e3SAndroid Build Coastguard Worker 	s = next;
500*1a3d31e3SAndroid Build Coastguard Worker 
501*1a3d31e3SAndroid Build Coastguard Worker 	offset = strtoll(s, &next, 10);
502*1a3d31e3SAndroid Build Coastguard Worker 	if (s == next)
503*1a3d31e3SAndroid Build Coastguard Worker 		goto out;
504*1a3d31e3SAndroid Build Coastguard Worker 	s = next;
505*1a3d31e3SAndroid Build Coastguard Worker 
506*1a3d31e3SAndroid Build Coastguard Worker 	num_banks = strtoll(s, &next, 10);
507*1a3d31e3SAndroid Build Coastguard Worker 	if (s == next)
508*1a3d31e3SAndroid Build Coastguard Worker 		goto out;
509*1a3d31e3SAndroid Build Coastguard Worker 
510*1a3d31e3SAndroid Build Coastguard Worker 	*bank_ret = bank;
511*1a3d31e3SAndroid Build Coastguard Worker 	*offset_ret = offset;
512*1a3d31e3SAndroid Build Coastguard Worker 	*num_banks_ret = num_banks;
513*1a3d31e3SAndroid Build Coastguard Worker 
514*1a3d31e3SAndroid Build Coastguard Worker 	return 0;
515*1a3d31e3SAndroid Build Coastguard Worker out:
516*1a3d31e3SAndroid Build Coastguard Worker 	free(message);
517*1a3d31e3SAndroid Build Coastguard Worker 	return -1;
518*1a3d31e3SAndroid Build Coastguard Worker }
519*1a3d31e3SAndroid Build Coastguard Worker 
lookup_dev(struct trace * trace,struct blk_io_trace * io)520*1a3d31e3SAndroid Build Coastguard Worker static struct dev_info *lookup_dev(struct trace *trace, struct blk_io_trace *io)
521*1a3d31e3SAndroid Build Coastguard Worker {
522*1a3d31e3SAndroid Build Coastguard Worker 	u32 dev = io->device;
523*1a3d31e3SAndroid Build Coastguard Worker 	int i;
524*1a3d31e3SAndroid Build Coastguard Worker 	struct dev_info *di = NULL;
525*1a3d31e3SAndroid Build Coastguard Worker 
526*1a3d31e3SAndroid Build Coastguard Worker 	for (i = 0; i < trace->num_devices; i++) {
527*1a3d31e3SAndroid Build Coastguard Worker 		if (trace->devices[i].device == dev) {
528*1a3d31e3SAndroid Build Coastguard Worker 			di = trace->devices + i;
529*1a3d31e3SAndroid Build Coastguard Worker 			goto found;
530*1a3d31e3SAndroid Build Coastguard Worker 		}
531*1a3d31e3SAndroid Build Coastguard Worker 	}
532*1a3d31e3SAndroid Build Coastguard Worker 	i = trace->num_devices++;
533*1a3d31e3SAndroid Build Coastguard Worker 	if (i >= MAX_DEVICES_PER_TRACE) {
534*1a3d31e3SAndroid Build Coastguard Worker 		fprintf(stderr, "Trace contains too many devices (%d)\n", i);
535*1a3d31e3SAndroid Build Coastguard Worker 		exit(1);
536*1a3d31e3SAndroid Build Coastguard Worker 	}
537*1a3d31e3SAndroid Build Coastguard Worker 	di = trace->devices + i;
538*1a3d31e3SAndroid Build Coastguard Worker 	di->device = dev;
539*1a3d31e3SAndroid Build Coastguard Worker found:
540*1a3d31e3SAndroid Build Coastguard Worker 	return di;
541*1a3d31e3SAndroid Build Coastguard Worker }
542*1a3d31e3SAndroid Build Coastguard Worker 
map_devices(struct trace * trace)543*1a3d31e3SAndroid Build Coastguard Worker static void map_devices(struct trace *trace)
544*1a3d31e3SAndroid Build Coastguard Worker {
545*1a3d31e3SAndroid Build Coastguard Worker 	struct dev_info *di;
546*1a3d31e3SAndroid Build Coastguard Worker 	u64 found;
547*1a3d31e3SAndroid Build Coastguard Worker 	u64 map_start = 0;
548*1a3d31e3SAndroid Build Coastguard Worker 	int i;
549*1a3d31e3SAndroid Build Coastguard Worker 
550*1a3d31e3SAndroid Build Coastguard Worker 	first_record(trace);
551*1a3d31e3SAndroid Build Coastguard Worker 	while (1) {
552*1a3d31e3SAndroid Build Coastguard Worker 		if (!(trace->io->action & BLK_TC_ACT(BLK_TC_NOTIFY))) {
553*1a3d31e3SAndroid Build Coastguard Worker 			di = lookup_dev(trace, trace->io);
554*1a3d31e3SAndroid Build Coastguard Worker 			found = trace->io->sector << 9;
555*1a3d31e3SAndroid Build Coastguard Worker 			if (found < di->min)
556*1a3d31e3SAndroid Build Coastguard Worker 				di->min = found;
557*1a3d31e3SAndroid Build Coastguard Worker 
558*1a3d31e3SAndroid Build Coastguard Worker 			found += trace->io->bytes;
559*1a3d31e3SAndroid Build Coastguard Worker 			if (di->max < found)
560*1a3d31e3SAndroid Build Coastguard Worker 				di->max = found;
561*1a3d31e3SAndroid Build Coastguard Worker 		}
562*1a3d31e3SAndroid Build Coastguard Worker 		if (next_record(trace))
563*1a3d31e3SAndroid Build Coastguard Worker 			break;
564*1a3d31e3SAndroid Build Coastguard Worker 	}
565*1a3d31e3SAndroid Build Coastguard Worker 	first_record(trace);
566*1a3d31e3SAndroid Build Coastguard Worker 	for (i = 0; i < trace->num_devices; i++) {
567*1a3d31e3SAndroid Build Coastguard Worker 		di = trace->devices + i;
568*1a3d31e3SAndroid Build Coastguard Worker 		di->map = map_start;
569*1a3d31e3SAndroid Build Coastguard Worker 		map_start += di->max - di->min;
570*1a3d31e3SAndroid Build Coastguard Worker 	}
571*1a3d31e3SAndroid Build Coastguard Worker }
572*1a3d31e3SAndroid Build Coastguard Worker 
map_io(struct trace * trace,struct blk_io_trace * io)573*1a3d31e3SAndroid Build Coastguard Worker static u64 map_io(struct trace *trace, struct blk_io_trace *io)
574*1a3d31e3SAndroid Build Coastguard Worker {
575*1a3d31e3SAndroid Build Coastguard Worker 	struct dev_info *di = lookup_dev(trace, io);
576*1a3d31e3SAndroid Build Coastguard Worker 	u64 val = trace->io->sector << 9;
577*1a3d31e3SAndroid Build Coastguard Worker 	return di->map + val - di->min;
578*1a3d31e3SAndroid Build Coastguard Worker }
579*1a3d31e3SAndroid Build Coastguard Worker 
find_extreme_offsets(struct trace * trace,u64 * min_ret,u64 * max_ret,u64 * max_bank_ret,u64 * max_offset_ret)580*1a3d31e3SAndroid Build Coastguard Worker void find_extreme_offsets(struct trace *trace, u64 *min_ret, u64 *max_ret, u64 *max_bank_ret,
581*1a3d31e3SAndroid Build Coastguard Worker 			  u64 *max_offset_ret)
582*1a3d31e3SAndroid Build Coastguard Worker {
583*1a3d31e3SAndroid Build Coastguard Worker 	u64 found = 0;
584*1a3d31e3SAndroid Build Coastguard Worker 	u64 max = 0, min = ~(u64)0;
585*1a3d31e3SAndroid Build Coastguard Worker 	u64 max_bank = 0;
586*1a3d31e3SAndroid Build Coastguard Worker 	u64 max_bank_offset = 0;
587*1a3d31e3SAndroid Build Coastguard Worker 	u64 num_banks = 0;
588*1a3d31e3SAndroid Build Coastguard Worker 
589*1a3d31e3SAndroid Build Coastguard Worker 	map_devices(trace);
590*1a3d31e3SAndroid Build Coastguard Worker 
591*1a3d31e3SAndroid Build Coastguard Worker 	first_record(trace);
592*1a3d31e3SAndroid Build Coastguard Worker 	while (1) {
593*1a3d31e3SAndroid Build Coastguard Worker 		if (!(trace->io->action & BLK_TC_ACT(BLK_TC_NOTIFY))) {
594*1a3d31e3SAndroid Build Coastguard Worker 			found = map_io(trace, trace->io);
595*1a3d31e3SAndroid Build Coastguard Worker 			if (found < min)
596*1a3d31e3SAndroid Build Coastguard Worker 				min = found;
597*1a3d31e3SAndroid Build Coastguard Worker 
598*1a3d31e3SAndroid Build Coastguard Worker 			found += trace->io->bytes;
599*1a3d31e3SAndroid Build Coastguard Worker 			if (max < found)
600*1a3d31e3SAndroid Build Coastguard Worker 				max = found;
601*1a3d31e3SAndroid Build Coastguard Worker 		} else {
602*1a3d31e3SAndroid Build Coastguard Worker 			u64 bank;
603*1a3d31e3SAndroid Build Coastguard Worker 			u64 offset;
604*1a3d31e3SAndroid Build Coastguard Worker 			if (!parse_fio_bank_message(trace, &bank,
605*1a3d31e3SAndroid Build Coastguard Worker 						    &offset, &num_banks)) {
606*1a3d31e3SAndroid Build Coastguard Worker 				if (bank > max_bank)
607*1a3d31e3SAndroid Build Coastguard Worker 					max_bank = bank;
608*1a3d31e3SAndroid Build Coastguard Worker 				if (offset > max_bank_offset)
609*1a3d31e3SAndroid Build Coastguard Worker 					max_bank_offset = offset;
610*1a3d31e3SAndroid Build Coastguard Worker 			}
611*1a3d31e3SAndroid Build Coastguard Worker 		}
612*1a3d31e3SAndroid Build Coastguard Worker 		if (next_record(trace))
613*1a3d31e3SAndroid Build Coastguard Worker 			break;
614*1a3d31e3SAndroid Build Coastguard Worker 	}
615*1a3d31e3SAndroid Build Coastguard Worker 	first_record(trace);
616*1a3d31e3SAndroid Build Coastguard Worker 	*min_ret = min;
617*1a3d31e3SAndroid Build Coastguard Worker 	*max_ret = max;
618*1a3d31e3SAndroid Build Coastguard Worker 	*max_bank_ret = max_bank;
619*1a3d31e3SAndroid Build Coastguard Worker 	*max_offset_ret = max_bank_offset;
620*1a3d31e3SAndroid Build Coastguard Worker }
621*1a3d31e3SAndroid Build Coastguard Worker 
check_io_types(struct trace * trace)622*1a3d31e3SAndroid Build Coastguard Worker static void check_io_types(struct trace *trace)
623*1a3d31e3SAndroid Build Coastguard Worker {
624*1a3d31e3SAndroid Build Coastguard Worker 	struct blk_io_trace *io = trace->io;
625*1a3d31e3SAndroid Build Coastguard Worker 	int action = io->action & BLK_TA_MASK;
626*1a3d31e3SAndroid Build Coastguard Worker 
627*1a3d31e3SAndroid Build Coastguard Worker 	if (!(io->action & BLK_TC_ACT(BLK_TC_NOTIFY))) {
628*1a3d31e3SAndroid Build Coastguard Worker 		switch (action) {
629*1a3d31e3SAndroid Build Coastguard Worker 		case __BLK_TA_COMPLETE:
630*1a3d31e3SAndroid Build Coastguard Worker 			trace->found_completion = 1;
631*1a3d31e3SAndroid Build Coastguard Worker 			break;
632*1a3d31e3SAndroid Build Coastguard Worker 		case __BLK_TA_ISSUE:
633*1a3d31e3SAndroid Build Coastguard Worker 			trace->found_issue = 1;
634*1a3d31e3SAndroid Build Coastguard Worker 			break;
635*1a3d31e3SAndroid Build Coastguard Worker 		case __BLK_TA_QUEUE:
636*1a3d31e3SAndroid Build Coastguard Worker 			trace->found_queue = 1;
637*1a3d31e3SAndroid Build Coastguard Worker 			break;
638*1a3d31e3SAndroid Build Coastguard Worker 		};
639*1a3d31e3SAndroid Build Coastguard Worker 	}
640*1a3d31e3SAndroid Build Coastguard Worker }
641*1a3d31e3SAndroid Build Coastguard Worker 
642*1a3d31e3SAndroid Build Coastguard Worker 
filter_outliers(struct trace * trace,u64 min_offset,u64 max_offset,u64 * yzoom_min,u64 * yzoom_max)643*1a3d31e3SAndroid Build Coastguard Worker int filter_outliers(struct trace *trace, u64 min_offset, u64 max_offset,
644*1a3d31e3SAndroid Build Coastguard Worker 		    u64 *yzoom_min, u64 *yzoom_max)
645*1a3d31e3SAndroid Build Coastguard Worker {
646*1a3d31e3SAndroid Build Coastguard Worker 	int hits[11];
647*1a3d31e3SAndroid Build Coastguard Worker 	u64 max_per_bucket[11];
648*1a3d31e3SAndroid Build Coastguard Worker 	u64 min_per_bucket[11];
649*1a3d31e3SAndroid Build Coastguard Worker 	u64 bytes_per_bucket = (max_offset - min_offset + 1) / 10;
650*1a3d31e3SAndroid Build Coastguard Worker 	int slot;
651*1a3d31e3SAndroid Build Coastguard Worker 	int fat_count = 0;
652*1a3d31e3SAndroid Build Coastguard Worker 
653*1a3d31e3SAndroid Build Coastguard Worker 	memset(hits, 0, sizeof(int) * 11);
654*1a3d31e3SAndroid Build Coastguard Worker 	memset(max_per_bucket, 0, sizeof(u64) * 11);
655*1a3d31e3SAndroid Build Coastguard Worker 	memset(min_per_bucket, 0xff, sizeof(u64) * 11);
656*1a3d31e3SAndroid Build Coastguard Worker 	first_record(trace);
657*1a3d31e3SAndroid Build Coastguard Worker 	while (1) {
658*1a3d31e3SAndroid Build Coastguard Worker 		check_io_types(trace);
659*1a3d31e3SAndroid Build Coastguard Worker 		if (!(trace->io->action & BLK_TC_ACT(BLK_TC_NOTIFY)) &&
660*1a3d31e3SAndroid Build Coastguard Worker 		    (trace->io->action & BLK_TA_MASK) == __BLK_TA_QUEUE) {
661*1a3d31e3SAndroid Build Coastguard Worker 			u64 off = map_io(trace, trace->io) - min_offset;
662*1a3d31e3SAndroid Build Coastguard Worker 
663*1a3d31e3SAndroid Build Coastguard Worker 			slot = (int)(off / bytes_per_bucket);
664*1a3d31e3SAndroid Build Coastguard Worker 			hits[slot]++;
665*1a3d31e3SAndroid Build Coastguard Worker 			if (off < min_per_bucket[slot])
666*1a3d31e3SAndroid Build Coastguard Worker 				min_per_bucket[slot] = off;
667*1a3d31e3SAndroid Build Coastguard Worker 
668*1a3d31e3SAndroid Build Coastguard Worker 			off += trace->io->bytes;
669*1a3d31e3SAndroid Build Coastguard Worker 			slot = (int)(off / bytes_per_bucket);
670*1a3d31e3SAndroid Build Coastguard Worker 			hits[slot]++;
671*1a3d31e3SAndroid Build Coastguard Worker 			if (off > max_per_bucket[slot])
672*1a3d31e3SAndroid Build Coastguard Worker 				max_per_bucket[slot] = off;
673*1a3d31e3SAndroid Build Coastguard Worker 		}
674*1a3d31e3SAndroid Build Coastguard Worker 		if (next_record(trace))
675*1a3d31e3SAndroid Build Coastguard Worker 			break;
676*1a3d31e3SAndroid Build Coastguard Worker 	}
677*1a3d31e3SAndroid Build Coastguard Worker 	first_record(trace);
678*1a3d31e3SAndroid Build Coastguard Worker 	for (slot = 0; slot < 11; slot++) {
679*1a3d31e3SAndroid Build Coastguard Worker 		if (hits[slot] > fat_count) {
680*1a3d31e3SAndroid Build Coastguard Worker 			fat_count = hits[slot];
681*1a3d31e3SAndroid Build Coastguard Worker 		}
682*1a3d31e3SAndroid Build Coastguard Worker 	}
683*1a3d31e3SAndroid Build Coastguard Worker 
684*1a3d31e3SAndroid Build Coastguard Worker 	*yzoom_max = max_offset;
685*1a3d31e3SAndroid Build Coastguard Worker 	for (slot = 10; slot >= 0; slot--) {
686*1a3d31e3SAndroid Build Coastguard Worker 		double d = hits[slot];
687*1a3d31e3SAndroid Build Coastguard Worker 
688*1a3d31e3SAndroid Build Coastguard Worker 		if (d >= (double)fat_count * .05) {
689*1a3d31e3SAndroid Build Coastguard Worker 			*yzoom_max = max_per_bucket[slot] + min_offset;
690*1a3d31e3SAndroid Build Coastguard Worker 			break;
691*1a3d31e3SAndroid Build Coastguard Worker 		}
692*1a3d31e3SAndroid Build Coastguard Worker 	}
693*1a3d31e3SAndroid Build Coastguard Worker 
694*1a3d31e3SAndroid Build Coastguard Worker 	*yzoom_min = min_offset;
695*1a3d31e3SAndroid Build Coastguard Worker 	for (slot = 0; slot < 10; slot++) {
696*1a3d31e3SAndroid Build Coastguard Worker 		double d = hits[slot];
697*1a3d31e3SAndroid Build Coastguard Worker 
698*1a3d31e3SAndroid Build Coastguard Worker 		if (d >= (double)fat_count * .05) {
699*1a3d31e3SAndroid Build Coastguard Worker 			*yzoom_min = min_per_bucket[slot] + min_offset;
700*1a3d31e3SAndroid Build Coastguard Worker 			break;
701*1a3d31e3SAndroid Build Coastguard Worker 		}
702*1a3d31e3SAndroid Build Coastguard Worker 	}
703*1a3d31e3SAndroid Build Coastguard Worker 	return 0;
704*1a3d31e3SAndroid Build Coastguard Worker }
705*1a3d31e3SAndroid Build Coastguard Worker 
706*1a3d31e3SAndroid Build Coastguard Worker static char footer[] = ".blktrace.0";
707*1a3d31e3SAndroid Build Coastguard Worker static int footer_len = sizeof(footer) - 1;
708*1a3d31e3SAndroid Build Coastguard Worker 
match_trace(char * name,int * len)709*1a3d31e3SAndroid Build Coastguard Worker static int match_trace(char *name, int *len)
710*1a3d31e3SAndroid Build Coastguard Worker {
711*1a3d31e3SAndroid Build Coastguard Worker 	int match_len;
712*1a3d31e3SAndroid Build Coastguard Worker 	int footer_start;
713*1a3d31e3SAndroid Build Coastguard Worker 
714*1a3d31e3SAndroid Build Coastguard Worker 	match_len = strlen(name);
715*1a3d31e3SAndroid Build Coastguard Worker 	if (match_len <= footer_len)
716*1a3d31e3SAndroid Build Coastguard Worker 		return 0;
717*1a3d31e3SAndroid Build Coastguard Worker 
718*1a3d31e3SAndroid Build Coastguard Worker 	footer_start = match_len - footer_len;
719*1a3d31e3SAndroid Build Coastguard Worker 	if (strcmp(name + footer_start, footer) != 0)
720*1a3d31e3SAndroid Build Coastguard Worker 		return 0;
721*1a3d31e3SAndroid Build Coastguard Worker 
722*1a3d31e3SAndroid Build Coastguard Worker 	if (len)
723*1a3d31e3SAndroid Build Coastguard Worker 		*len = match_len;
724*1a3d31e3SAndroid Build Coastguard Worker 	return 1;
725*1a3d31e3SAndroid Build Coastguard Worker }
726*1a3d31e3SAndroid Build Coastguard Worker 
727*1a3d31e3SAndroid Build Coastguard Worker struct tracelist {
728*1a3d31e3SAndroid Build Coastguard Worker 	struct tracelist *next;
729*1a3d31e3SAndroid Build Coastguard Worker 	char *name;
730*1a3d31e3SAndroid Build Coastguard Worker };
731*1a3d31e3SAndroid Build Coastguard Worker 
traces_list(char * dir_name,int * len)732*1a3d31e3SAndroid Build Coastguard Worker static struct tracelist *traces_list(char *dir_name, int *len)
733*1a3d31e3SAndroid Build Coastguard Worker {
734*1a3d31e3SAndroid Build Coastguard Worker 	int count = 0;
735*1a3d31e3SAndroid Build Coastguard Worker 	struct tracelist *traces = NULL;
736*1a3d31e3SAndroid Build Coastguard Worker 	int dlen = strlen(dir_name);
737*1a3d31e3SAndroid Build Coastguard Worker 	DIR *dir = opendir(dir_name);
738*1a3d31e3SAndroid Build Coastguard Worker 	if (!dir)
739*1a3d31e3SAndroid Build Coastguard Worker 		return NULL;
740*1a3d31e3SAndroid Build Coastguard Worker 
741*1a3d31e3SAndroid Build Coastguard Worker 	while (1) {
742*1a3d31e3SAndroid Build Coastguard Worker 		int n = 0;
743*1a3d31e3SAndroid Build Coastguard Worker 		struct tracelist *tl;
744*1a3d31e3SAndroid Build Coastguard Worker 		struct dirent *d = readdir(dir);
745*1a3d31e3SAndroid Build Coastguard Worker 		if (!d)
746*1a3d31e3SAndroid Build Coastguard Worker 			break;
747*1a3d31e3SAndroid Build Coastguard Worker 
748*1a3d31e3SAndroid Build Coastguard Worker 		if (!match_trace(d->d_name, &n))
749*1a3d31e3SAndroid Build Coastguard Worker 			continue;
750*1a3d31e3SAndroid Build Coastguard Worker 
751*1a3d31e3SAndroid Build Coastguard Worker 		n += dlen + 1; /* dir + '/' + file */
752*1a3d31e3SAndroid Build Coastguard Worker 		/* Allocate space for tracelist + filename */
753*1a3d31e3SAndroid Build Coastguard Worker 		tl = calloc(1, sizeof(struct tracelist) + (sizeof(char) * (n + 1)));
754*1a3d31e3SAndroid Build Coastguard Worker 		if (!tl) {
755*1a3d31e3SAndroid Build Coastguard Worker 			closedir(dir);
756*1a3d31e3SAndroid Build Coastguard Worker 			return NULL;
757*1a3d31e3SAndroid Build Coastguard Worker 		}
758*1a3d31e3SAndroid Build Coastguard Worker 		tl->next = traces;
759*1a3d31e3SAndroid Build Coastguard Worker 		tl->name = (char *)(tl + 1);
760*1a3d31e3SAndroid Build Coastguard Worker 		snprintf(tl->name, n, "%s/%s", dir_name, d->d_name);
761*1a3d31e3SAndroid Build Coastguard Worker 		traces = tl;
762*1a3d31e3SAndroid Build Coastguard Worker 		count++;
763*1a3d31e3SAndroid Build Coastguard Worker 	}
764*1a3d31e3SAndroid Build Coastguard Worker 
765*1a3d31e3SAndroid Build Coastguard Worker 	closedir(dir);
766*1a3d31e3SAndroid Build Coastguard Worker 
767*1a3d31e3SAndroid Build Coastguard Worker 	if (len)
768*1a3d31e3SAndroid Build Coastguard Worker 		*len = count;
769*1a3d31e3SAndroid Build Coastguard Worker 
770*1a3d31e3SAndroid Build Coastguard Worker 	return traces;
771*1a3d31e3SAndroid Build Coastguard Worker }
772*1a3d31e3SAndroid Build Coastguard Worker 
traces_free(struct tracelist * traces)773*1a3d31e3SAndroid Build Coastguard Worker static void traces_free(struct tracelist *traces)
774*1a3d31e3SAndroid Build Coastguard Worker {
775*1a3d31e3SAndroid Build Coastguard Worker 	while (traces) {
776*1a3d31e3SAndroid Build Coastguard Worker 		struct tracelist *tl = traces;
777*1a3d31e3SAndroid Build Coastguard Worker 		traces = traces->next;
778*1a3d31e3SAndroid Build Coastguard Worker 		free(tl);
779*1a3d31e3SAndroid Build Coastguard Worker 	}
780*1a3d31e3SAndroid Build Coastguard Worker }
781*1a3d31e3SAndroid Build Coastguard Worker 
dump_traces(struct tracelist * traces,int count,char * dumpfile)782*1a3d31e3SAndroid Build Coastguard Worker static int dump_traces(struct tracelist *traces, int count, char *dumpfile)
783*1a3d31e3SAndroid Build Coastguard Worker {
784*1a3d31e3SAndroid Build Coastguard Worker 	struct tracelist *tl;
785*1a3d31e3SAndroid Build Coastguard Worker 	char **argv = NULL;
786*1a3d31e3SAndroid Build Coastguard Worker 	int argc = 0;
787*1a3d31e3SAndroid Build Coastguard Worker 	int i;
788*1a3d31e3SAndroid Build Coastguard Worker 	int err = 0;
789*1a3d31e3SAndroid Build Coastguard Worker 
790*1a3d31e3SAndroid Build Coastguard Worker 	argc = count * 2; /* {"-i", trace } */
791*1a3d31e3SAndroid Build Coastguard Worker 	argc += 4; /* See below */
792*1a3d31e3SAndroid Build Coastguard Worker 	argv = calloc(argc + 1, sizeof(char *));
793*1a3d31e3SAndroid Build Coastguard Worker 	if (!argv)
794*1a3d31e3SAndroid Build Coastguard Worker 		return -errno;
795*1a3d31e3SAndroid Build Coastguard Worker 
796*1a3d31e3SAndroid Build Coastguard Worker 	i = 0;
797*1a3d31e3SAndroid Build Coastguard Worker 	argv[i++] = "blkparse";
798*1a3d31e3SAndroid Build Coastguard Worker 	argv[i++] = "-O";
799*1a3d31e3SAndroid Build Coastguard Worker 	argv[i++] = "-d";
800*1a3d31e3SAndroid Build Coastguard Worker 	argv[i++] = dumpfile;
801*1a3d31e3SAndroid Build Coastguard Worker 	for (tl = traces; tl != NULL; tl = tl->next) {
802*1a3d31e3SAndroid Build Coastguard Worker 		argv[i++] = "-i";
803*1a3d31e3SAndroid Build Coastguard Worker 		argv[i++] = tl->name;
804*1a3d31e3SAndroid Build Coastguard Worker 	}
805*1a3d31e3SAndroid Build Coastguard Worker 
806*1a3d31e3SAndroid Build Coastguard Worker 	err = run_program(argc, argv, 1, NULL, NULL);
807*1a3d31e3SAndroid Build Coastguard Worker 	if (err)
808*1a3d31e3SAndroid Build Coastguard Worker 		fprintf(stderr, "%s exited with %d, expected 0\n", argv[0], err);
809*1a3d31e3SAndroid Build Coastguard Worker 	free(argv);
810*1a3d31e3SAndroid Build Coastguard Worker 	return err;
811*1a3d31e3SAndroid Build Coastguard Worker }
812*1a3d31e3SAndroid Build Coastguard Worker 
find_trace_file(char * filename)813*1a3d31e3SAndroid Build Coastguard Worker static char *find_trace_file(char *filename)
814*1a3d31e3SAndroid Build Coastguard Worker {
815*1a3d31e3SAndroid Build Coastguard Worker 	int ret;
816*1a3d31e3SAndroid Build Coastguard Worker 	struct stat st;
817*1a3d31e3SAndroid Build Coastguard Worker 	char *dot;
818*1a3d31e3SAndroid Build Coastguard Worker 	int found_dir = 0;
819*1a3d31e3SAndroid Build Coastguard Worker 	char *dumpfile;
820*1a3d31e3SAndroid Build Coastguard Worker 	int len = strlen(filename);
821*1a3d31e3SAndroid Build Coastguard Worker 
822*1a3d31e3SAndroid Build Coastguard Worker 	/* look for an exact match of whatever they pass in.
823*1a3d31e3SAndroid Build Coastguard Worker 	 * If it is a file, assume it is the dump file.
824*1a3d31e3SAndroid Build Coastguard Worker 	 * If a directory, remember that it existed so we
825*1a3d31e3SAndroid Build Coastguard Worker 	 * can combine traces in that directory later
826*1a3d31e3SAndroid Build Coastguard Worker 	 */
827*1a3d31e3SAndroid Build Coastguard Worker 	ret = stat(filename, &st);
828*1a3d31e3SAndroid Build Coastguard Worker 	if (ret == 0) {
829*1a3d31e3SAndroid Build Coastguard Worker 		if (S_ISREG(st.st_mode))
830*1a3d31e3SAndroid Build Coastguard Worker 			return strdup(filename);
831*1a3d31e3SAndroid Build Coastguard Worker 
832*1a3d31e3SAndroid Build Coastguard Worker 		if (S_ISDIR(st.st_mode))
833*1a3d31e3SAndroid Build Coastguard Worker 			found_dir = 1;
834*1a3d31e3SAndroid Build Coastguard Worker 	}
835*1a3d31e3SAndroid Build Coastguard Worker 
836*1a3d31e3SAndroid Build Coastguard Worker 	if (found_dir) {
837*1a3d31e3SAndroid Build Coastguard Worker 		int i;
838*1a3d31e3SAndroid Build Coastguard Worker 		/* Eat up trailing '/'s */
839*1a3d31e3SAndroid Build Coastguard Worker 		for (i = len - 1; filename[i] == '/'; i--)
840*1a3d31e3SAndroid Build Coastguard Worker 			filename[i] = '\0';
841*1a3d31e3SAndroid Build Coastguard Worker 	}
842*1a3d31e3SAndroid Build Coastguard Worker 
843*1a3d31e3SAndroid Build Coastguard Worker 	/*
844*1a3d31e3SAndroid Build Coastguard Worker 	 * try tacking .dump onto the end and see if that already
845*1a3d31e3SAndroid Build Coastguard Worker 	 * has been generated
846*1a3d31e3SAndroid Build Coastguard Worker 	 */
847*1a3d31e3SAndroid Build Coastguard Worker 	ret = asprintf(&dumpfile, "%s.dump", filename);
848*1a3d31e3SAndroid Build Coastguard Worker 	if (ret == -1) {
849*1a3d31e3SAndroid Build Coastguard Worker 		perror("Error building dump file name");
850*1a3d31e3SAndroid Build Coastguard Worker 		return NULL;
851*1a3d31e3SAndroid Build Coastguard Worker 	}
852*1a3d31e3SAndroid Build Coastguard Worker 	ret = stat(dumpfile, &st);
853*1a3d31e3SAndroid Build Coastguard Worker 	if (ret == 0)
854*1a3d31e3SAndroid Build Coastguard Worker 		return dumpfile;
855*1a3d31e3SAndroid Build Coastguard Worker 
856*1a3d31e3SAndroid Build Coastguard Worker 	/*
857*1a3d31e3SAndroid Build Coastguard Worker 	 * try to generate the .dump from all the traces in
858*1a3d31e3SAndroid Build Coastguard Worker 	 * a single dir.
859*1a3d31e3SAndroid Build Coastguard Worker 	 */
860*1a3d31e3SAndroid Build Coastguard Worker 	if (found_dir) {
861*1a3d31e3SAndroid Build Coastguard Worker 		int count;
862*1a3d31e3SAndroid Build Coastguard Worker 		struct tracelist *traces = traces_list(filename, &count);
863*1a3d31e3SAndroid Build Coastguard Worker 		if (traces) {
864*1a3d31e3SAndroid Build Coastguard Worker 			ret = dump_traces(traces, count, dumpfile);
865*1a3d31e3SAndroid Build Coastguard Worker 			traces_free(traces);
866*1a3d31e3SAndroid Build Coastguard Worker 			if (ret == 0)
867*1a3d31e3SAndroid Build Coastguard Worker 				return dumpfile;
868*1a3d31e3SAndroid Build Coastguard Worker 		}
869*1a3d31e3SAndroid Build Coastguard Worker 	}
870*1a3d31e3SAndroid Build Coastguard Worker 	free(dumpfile);
871*1a3d31e3SAndroid Build Coastguard Worker 
872*1a3d31e3SAndroid Build Coastguard Worker 	/*
873*1a3d31e3SAndroid Build Coastguard Worker 	 * try to generate the .dump from all the blktrace
874*1a3d31e3SAndroid Build Coastguard Worker 	 * files for a named trace
875*1a3d31e3SAndroid Build Coastguard Worker 	 */
876*1a3d31e3SAndroid Build Coastguard Worker 	dot = strrchr(filename, '.');
877*1a3d31e3SAndroid Build Coastguard Worker 	if (!dot || strcmp(".dump", dot) != 0) {
878*1a3d31e3SAndroid Build Coastguard Worker 		struct tracelist trace = {0 ,NULL};
879*1a3d31e3SAndroid Build Coastguard Worker 		if (dot && dot != filename)
880*1a3d31e3SAndroid Build Coastguard Worker 			len = dot - filename;
881*1a3d31e3SAndroid Build Coastguard Worker 
882*1a3d31e3SAndroid Build Coastguard Worker 		ret = asprintf(&trace.name, "%*s.blktrace.0", len, filename);
883*1a3d31e3SAndroid Build Coastguard Worker 		if (ret == -1)
884*1a3d31e3SAndroid Build Coastguard Worker 			return NULL;
885*1a3d31e3SAndroid Build Coastguard Worker 		ret = asprintf(&dumpfile, "%*s.dump", len, filename);
886*1a3d31e3SAndroid Build Coastguard Worker 		if (ret == -1) {
887*1a3d31e3SAndroid Build Coastguard Worker 			free(trace.name);
888*1a3d31e3SAndroid Build Coastguard Worker 			return NULL;
889*1a3d31e3SAndroid Build Coastguard Worker 		}
890*1a3d31e3SAndroid Build Coastguard Worker 
891*1a3d31e3SAndroid Build Coastguard Worker 		ret = dump_traces(&trace, 1, dumpfile);
892*1a3d31e3SAndroid Build Coastguard Worker 		if (ret == 0) {
893*1a3d31e3SAndroid Build Coastguard Worker 			free(trace.name);
894*1a3d31e3SAndroid Build Coastguard Worker 			return dumpfile;
895*1a3d31e3SAndroid Build Coastguard Worker 		}
896*1a3d31e3SAndroid Build Coastguard Worker 		free(trace.name);
897*1a3d31e3SAndroid Build Coastguard Worker 		free(dumpfile);
898*1a3d31e3SAndroid Build Coastguard Worker 	}
899*1a3d31e3SAndroid Build Coastguard Worker 	return NULL;
900*1a3d31e3SAndroid Build Coastguard Worker }
open_trace(char * filename)901*1a3d31e3SAndroid Build Coastguard Worker struct trace *open_trace(char *filename)
902*1a3d31e3SAndroid Build Coastguard Worker {
903*1a3d31e3SAndroid Build Coastguard Worker 	int fd;
904*1a3d31e3SAndroid Build Coastguard Worker 	char *p;
905*1a3d31e3SAndroid Build Coastguard Worker 	struct stat st;
906*1a3d31e3SAndroid Build Coastguard Worker 	int ret;
907*1a3d31e3SAndroid Build Coastguard Worker 	struct trace *trace;
908*1a3d31e3SAndroid Build Coastguard Worker 	char *found_filename;
909*1a3d31e3SAndroid Build Coastguard Worker 
910*1a3d31e3SAndroid Build Coastguard Worker 	trace = calloc(1, sizeof(*trace));
911*1a3d31e3SAndroid Build Coastguard Worker 	if (!trace) {
912*1a3d31e3SAndroid Build Coastguard Worker 		fprintf(stderr, "unable to allocate memory for trace\n");
913*1a3d31e3SAndroid Build Coastguard Worker 		return NULL;
914*1a3d31e3SAndroid Build Coastguard Worker 	}
915*1a3d31e3SAndroid Build Coastguard Worker 
916*1a3d31e3SAndroid Build Coastguard Worker 	found_filename = find_trace_file(filename);
917*1a3d31e3SAndroid Build Coastguard Worker 	if (!found_filename) {
918*1a3d31e3SAndroid Build Coastguard Worker 		fprintf(stderr, "Unable to find trace file %s\n", filename);
919*1a3d31e3SAndroid Build Coastguard Worker 		goto fail;
920*1a3d31e3SAndroid Build Coastguard Worker 	}
921*1a3d31e3SAndroid Build Coastguard Worker 	filename = found_filename;
922*1a3d31e3SAndroid Build Coastguard Worker 
923*1a3d31e3SAndroid Build Coastguard Worker 	fd = open(filename, O_RDONLY);
924*1a3d31e3SAndroid Build Coastguard Worker 	if (fd < 0) {
925*1a3d31e3SAndroid Build Coastguard Worker 		fprintf(stderr, "Unable to open trace file %s err %s\n", filename, strerror(errno));
926*1a3d31e3SAndroid Build Coastguard Worker 		goto fail;
927*1a3d31e3SAndroid Build Coastguard Worker 	}
928*1a3d31e3SAndroid Build Coastguard Worker 	ret = fstat(fd, &st);
929*1a3d31e3SAndroid Build Coastguard Worker 	if (ret < 0) {
930*1a3d31e3SAndroid Build Coastguard Worker 		fprintf(stderr, "stat failed on %s err %s\n", filename, strerror(errno));
931*1a3d31e3SAndroid Build Coastguard Worker 		goto fail_fd;
932*1a3d31e3SAndroid Build Coastguard Worker 	}
933*1a3d31e3SAndroid Build Coastguard Worker 	p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
934*1a3d31e3SAndroid Build Coastguard Worker 	if (p == MAP_FAILED) {
935*1a3d31e3SAndroid Build Coastguard Worker 		fprintf(stderr, "Unable to mmap trace file %s, err %s\n", filename, strerror(errno));
936*1a3d31e3SAndroid Build Coastguard Worker 		goto fail_fd;
937*1a3d31e3SAndroid Build Coastguard Worker 	}
938*1a3d31e3SAndroid Build Coastguard Worker 	trace->fd = fd;
939*1a3d31e3SAndroid Build Coastguard Worker 	trace->len = st.st_size;
940*1a3d31e3SAndroid Build Coastguard Worker 	trace->start = p;
941*1a3d31e3SAndroid Build Coastguard Worker 	trace->cur = p;
942*1a3d31e3SAndroid Build Coastguard Worker 	trace->io = (struct blk_io_trace *)p;
943*1a3d31e3SAndroid Build Coastguard Worker 	return trace;
944*1a3d31e3SAndroid Build Coastguard Worker 
945*1a3d31e3SAndroid Build Coastguard Worker fail_fd:
946*1a3d31e3SAndroid Build Coastguard Worker 	close(fd);
947*1a3d31e3SAndroid Build Coastguard Worker fail:
948*1a3d31e3SAndroid Build Coastguard Worker 	free(trace);
949*1a3d31e3SAndroid Build Coastguard Worker 	return NULL;
950*1a3d31e3SAndroid Build Coastguard Worker }
tput_event(struct trace * trace)951*1a3d31e3SAndroid Build Coastguard Worker static inline int tput_event(struct trace *trace)
952*1a3d31e3SAndroid Build Coastguard Worker {
953*1a3d31e3SAndroid Build Coastguard Worker 	if (trace->found_completion)
954*1a3d31e3SAndroid Build Coastguard Worker 		return __BLK_TA_COMPLETE;
955*1a3d31e3SAndroid Build Coastguard Worker 	if (trace->found_issue)
956*1a3d31e3SAndroid Build Coastguard Worker 		return __BLK_TA_ISSUE;
957*1a3d31e3SAndroid Build Coastguard Worker 	if (trace->found_queue)
958*1a3d31e3SAndroid Build Coastguard Worker 		return __BLK_TA_QUEUE;
959*1a3d31e3SAndroid Build Coastguard Worker 
960*1a3d31e3SAndroid Build Coastguard Worker 	return __BLK_TA_COMPLETE;
961*1a3d31e3SAndroid Build Coastguard Worker }
962*1a3d31e3SAndroid Build Coastguard Worker 
action_char_to_num(char action)963*1a3d31e3SAndroid Build Coastguard Worker int action_char_to_num(char action)
964*1a3d31e3SAndroid Build Coastguard Worker {
965*1a3d31e3SAndroid Build Coastguard Worker 	switch (action) {
966*1a3d31e3SAndroid Build Coastguard Worker 	case 'Q':
967*1a3d31e3SAndroid Build Coastguard Worker 		return __BLK_TA_QUEUE;
968*1a3d31e3SAndroid Build Coastguard Worker 	case 'D':
969*1a3d31e3SAndroid Build Coastguard Worker 		return __BLK_TA_ISSUE;
970*1a3d31e3SAndroid Build Coastguard Worker 	case 'C':
971*1a3d31e3SAndroid Build Coastguard Worker 		return __BLK_TA_COMPLETE;
972*1a3d31e3SAndroid Build Coastguard Worker 	}
973*1a3d31e3SAndroid Build Coastguard Worker 	return -1;
974*1a3d31e3SAndroid Build Coastguard Worker }
975*1a3d31e3SAndroid Build Coastguard Worker 
io_event(struct trace * trace)976*1a3d31e3SAndroid Build Coastguard Worker static inline int io_event(struct trace *trace)
977*1a3d31e3SAndroid Build Coastguard Worker {
978*1a3d31e3SAndroid Build Coastguard Worker 	if (plot_io_action)
979*1a3d31e3SAndroid Build Coastguard Worker 		return plot_io_action;
980*1a3d31e3SAndroid Build Coastguard Worker 	if (trace->found_queue)
981*1a3d31e3SAndroid Build Coastguard Worker 		return __BLK_TA_QUEUE;
982*1a3d31e3SAndroid Build Coastguard Worker 	if (trace->found_issue)
983*1a3d31e3SAndroid Build Coastguard Worker 		return __BLK_TA_ISSUE;
984*1a3d31e3SAndroid Build Coastguard Worker 	if (trace->found_completion)
985*1a3d31e3SAndroid Build Coastguard Worker 		return __BLK_TA_COMPLETE;
986*1a3d31e3SAndroid Build Coastguard Worker 
987*1a3d31e3SAndroid Build Coastguard Worker 	return __BLK_TA_COMPLETE;
988*1a3d31e3SAndroid Build Coastguard Worker }
989*1a3d31e3SAndroid Build Coastguard Worker 
add_tput(struct trace * trace,struct graph_line_data * writes_gld,struct graph_line_data * reads_gld)990*1a3d31e3SAndroid Build Coastguard Worker void add_tput(struct trace *trace, struct graph_line_data *writes_gld,
991*1a3d31e3SAndroid Build Coastguard Worker 	      struct graph_line_data *reads_gld)
992*1a3d31e3SAndroid Build Coastguard Worker {
993*1a3d31e3SAndroid Build Coastguard Worker 	struct blk_io_trace *io = trace->io;
994*1a3d31e3SAndroid Build Coastguard Worker 	struct graph_line_data *gld;
995*1a3d31e3SAndroid Build Coastguard Worker 	int action = io->action & BLK_TA_MASK;
996*1a3d31e3SAndroid Build Coastguard Worker 	int seconds;
997*1a3d31e3SAndroid Build Coastguard Worker 
998*1a3d31e3SAndroid Build Coastguard Worker 	if (io->action & BLK_TC_ACT(BLK_TC_NOTIFY))
999*1a3d31e3SAndroid Build Coastguard Worker 		return;
1000*1a3d31e3SAndroid Build Coastguard Worker 
1001*1a3d31e3SAndroid Build Coastguard Worker 	if (action != tput_event(trace))
1002*1a3d31e3SAndroid Build Coastguard Worker 		return;
1003*1a3d31e3SAndroid Build Coastguard Worker 
1004*1a3d31e3SAndroid Build Coastguard Worker 	if (BLK_DATADIR(io->action) & BLK_TC_READ)
1005*1a3d31e3SAndroid Build Coastguard Worker 		gld = reads_gld;
1006*1a3d31e3SAndroid Build Coastguard Worker 	else
1007*1a3d31e3SAndroid Build Coastguard Worker 		gld = writes_gld;
1008*1a3d31e3SAndroid Build Coastguard Worker 
1009*1a3d31e3SAndroid Build Coastguard Worker 	seconds = SECONDS(io->time);
1010*1a3d31e3SAndroid Build Coastguard Worker 	gld->data[seconds].sum += io->bytes;
1011*1a3d31e3SAndroid Build Coastguard Worker 
1012*1a3d31e3SAndroid Build Coastguard Worker 	gld->data[seconds].count = 1;
1013*1a3d31e3SAndroid Build Coastguard Worker 	if (gld->data[seconds].sum > gld->max)
1014*1a3d31e3SAndroid Build Coastguard Worker 		gld->max = gld->data[seconds].sum;
1015*1a3d31e3SAndroid Build Coastguard Worker }
1016*1a3d31e3SAndroid Build Coastguard Worker 
1017*1a3d31e3SAndroid Build Coastguard Worker #define GDD_PTR_ALLOC_STEP 16
1018*1a3d31e3SAndroid Build Coastguard Worker 
get_pid_map(struct trace_file * tf,u32 pid)1019*1a3d31e3SAndroid Build Coastguard Worker static struct pid_map *get_pid_map(struct trace_file *tf, u32 pid)
1020*1a3d31e3SAndroid Build Coastguard Worker {
1021*1a3d31e3SAndroid Build Coastguard Worker 	struct pid_map *pm;
1022*1a3d31e3SAndroid Build Coastguard Worker 
1023*1a3d31e3SAndroid Build Coastguard Worker 	if (!io_per_process) {
1024*1a3d31e3SAndroid Build Coastguard Worker 		if (!tf->io_plots)
1025*1a3d31e3SAndroid Build Coastguard Worker 			tf->io_plots = 1;
1026*1a3d31e3SAndroid Build Coastguard Worker 		return NULL;
1027*1a3d31e3SAndroid Build Coastguard Worker 	}
1028*1a3d31e3SAndroid Build Coastguard Worker 
1029*1a3d31e3SAndroid Build Coastguard Worker 	pm = process_hash_insert(pid, NULL);
1030*1a3d31e3SAndroid Build Coastguard Worker 	/* New entry? */
1031*1a3d31e3SAndroid Build Coastguard Worker 	if (!pm->index) {
1032*1a3d31e3SAndroid Build Coastguard Worker 		if (tf->io_plots == tf->io_plots_allocated) {
1033*1a3d31e3SAndroid Build Coastguard Worker 			tf->io_plots_allocated += GDD_PTR_ALLOC_STEP;
1034*1a3d31e3SAndroid Build Coastguard Worker 			tf->gdd_reads = realloc(tf->gdd_reads, tf->io_plots_allocated * sizeof(struct graph_dot_data *));
1035*1a3d31e3SAndroid Build Coastguard Worker 			if (!tf->gdd_reads)
1036*1a3d31e3SAndroid Build Coastguard Worker 				abort();
1037*1a3d31e3SAndroid Build Coastguard Worker 			tf->gdd_writes = realloc(tf->gdd_writes, tf->io_plots_allocated * sizeof(struct graph_dot_data *));
1038*1a3d31e3SAndroid Build Coastguard Worker 			if (!tf->gdd_writes)
1039*1a3d31e3SAndroid Build Coastguard Worker 				abort();
1040*1a3d31e3SAndroid Build Coastguard Worker 			memset(tf->gdd_reads + tf->io_plots_allocated - GDD_PTR_ALLOC_STEP,
1041*1a3d31e3SAndroid Build Coastguard Worker 			       0, GDD_PTR_ALLOC_STEP * sizeof(struct graph_dot_data *));
1042*1a3d31e3SAndroid Build Coastguard Worker 			memset(tf->gdd_writes + tf->io_plots_allocated - GDD_PTR_ALLOC_STEP,
1043*1a3d31e3SAndroid Build Coastguard Worker 			       0, GDD_PTR_ALLOC_STEP * sizeof(struct graph_dot_data *));
1044*1a3d31e3SAndroid Build Coastguard Worker 		}
1045*1a3d31e3SAndroid Build Coastguard Worker 		pm->index = tf->io_plots++;
1046*1a3d31e3SAndroid Build Coastguard Worker 
1047*1a3d31e3SAndroid Build Coastguard Worker 		return pm;
1048*1a3d31e3SAndroid Build Coastguard Worker 	}
1049*1a3d31e3SAndroid Build Coastguard Worker 	return pm;
1050*1a3d31e3SAndroid Build Coastguard Worker }
1051*1a3d31e3SAndroid Build Coastguard Worker 
add_io(struct trace * trace,struct trace_file * tf)1052*1a3d31e3SAndroid Build Coastguard Worker void add_io(struct trace *trace, struct trace_file *tf)
1053*1a3d31e3SAndroid Build Coastguard Worker {
1054*1a3d31e3SAndroid Build Coastguard Worker 	struct blk_io_trace *io = trace->io;
1055*1a3d31e3SAndroid Build Coastguard Worker 	int action = io->action & BLK_TA_MASK;
1056*1a3d31e3SAndroid Build Coastguard Worker 	u64 offset;
1057*1a3d31e3SAndroid Build Coastguard Worker 	int index;
1058*1a3d31e3SAndroid Build Coastguard Worker 	char *label;
1059*1a3d31e3SAndroid Build Coastguard Worker 	struct pid_map *pm;
1060*1a3d31e3SAndroid Build Coastguard Worker 
1061*1a3d31e3SAndroid Build Coastguard Worker 	if (io->action & BLK_TC_ACT(BLK_TC_NOTIFY))
1062*1a3d31e3SAndroid Build Coastguard Worker 		return;
1063*1a3d31e3SAndroid Build Coastguard Worker 
1064*1a3d31e3SAndroid Build Coastguard Worker 	if (action != io_event(trace))
1065*1a3d31e3SAndroid Build Coastguard Worker 		return;
1066*1a3d31e3SAndroid Build Coastguard Worker 
1067*1a3d31e3SAndroid Build Coastguard Worker 	offset = map_io(trace, io);
1068*1a3d31e3SAndroid Build Coastguard Worker 
1069*1a3d31e3SAndroid Build Coastguard Worker 	pm = get_pid_map(tf, io->pid);
1070*1a3d31e3SAndroid Build Coastguard Worker 	if (!pm) {
1071*1a3d31e3SAndroid Build Coastguard Worker 		index = 0;
1072*1a3d31e3SAndroid Build Coastguard Worker 		label = "";
1073*1a3d31e3SAndroid Build Coastguard Worker 	} else {
1074*1a3d31e3SAndroid Build Coastguard Worker 		index = pm->index;
1075*1a3d31e3SAndroid Build Coastguard Worker 		label = pm->name;
1076*1a3d31e3SAndroid Build Coastguard Worker 	}
1077*1a3d31e3SAndroid Build Coastguard Worker 	if (BLK_DATADIR(io->action) & BLK_TC_READ) {
1078*1a3d31e3SAndroid Build Coastguard Worker 		if (!tf->gdd_reads[index])
1079*1a3d31e3SAndroid Build Coastguard Worker 			tf->gdd_reads[index] = alloc_dot_data(tf->min_seconds, tf->max_seconds, tf->min_offset, tf->max_offset, tf->stop_seconds, pick_color(), strdup(label));
1080*1a3d31e3SAndroid Build Coastguard Worker 		set_gdd_bit(tf->gdd_reads[index], offset, io->bytes, io->time);
1081*1a3d31e3SAndroid Build Coastguard Worker 	} else if (BLK_DATADIR(io->action) & BLK_TC_WRITE) {
1082*1a3d31e3SAndroid Build Coastguard Worker 		if (!tf->gdd_writes[index])
1083*1a3d31e3SAndroid Build Coastguard Worker 			tf->gdd_writes[index] = alloc_dot_data(tf->min_seconds, tf->max_seconds, tf->min_offset, tf->max_offset, tf->stop_seconds, pick_color(), strdup(label));
1084*1a3d31e3SAndroid Build Coastguard Worker 		set_gdd_bit(tf->gdd_writes[index], offset, io->bytes, io->time);
1085*1a3d31e3SAndroid Build Coastguard Worker 	}
1086*1a3d31e3SAndroid Build Coastguard Worker }
1087*1a3d31e3SAndroid Build Coastguard Worker 
add_pending_io(struct trace * trace,struct graph_line_data * gld)1088*1a3d31e3SAndroid Build Coastguard Worker void add_pending_io(struct trace *trace, struct graph_line_data *gld)
1089*1a3d31e3SAndroid Build Coastguard Worker {
1090*1a3d31e3SAndroid Build Coastguard Worker 	unsigned int seconds;
1091*1a3d31e3SAndroid Build Coastguard Worker 	struct blk_io_trace *io = trace->io;
1092*1a3d31e3SAndroid Build Coastguard Worker 	int action = io->action & BLK_TA_MASK;
1093*1a3d31e3SAndroid Build Coastguard Worker 	double avg;
1094*1a3d31e3SAndroid Build Coastguard Worker 	struct pending_io *pio;
1095*1a3d31e3SAndroid Build Coastguard Worker 
1096*1a3d31e3SAndroid Build Coastguard Worker 	if (io->action & BLK_TC_ACT(BLK_TC_NOTIFY))
1097*1a3d31e3SAndroid Build Coastguard Worker 		return;
1098*1a3d31e3SAndroid Build Coastguard Worker 
1099*1a3d31e3SAndroid Build Coastguard Worker 	if (action == __BLK_TA_QUEUE) {
1100*1a3d31e3SAndroid Build Coastguard Worker 		if (io->sector == 0)
1101*1a3d31e3SAndroid Build Coastguard Worker 			return;
1102*1a3d31e3SAndroid Build Coastguard Worker 		if (trace->found_issue || trace->found_completion) {
1103*1a3d31e3SAndroid Build Coastguard Worker 			pio = hash_queued_io(trace->io);
1104*1a3d31e3SAndroid Build Coastguard Worker 			/*
1105*1a3d31e3SAndroid Build Coastguard Worker 			 * When there are no ISSUE events count depth and
1106*1a3d31e3SAndroid Build Coastguard Worker 			 * latency at least from queue events
1107*1a3d31e3SAndroid Build Coastguard Worker 			 */
1108*1a3d31e3SAndroid Build Coastguard Worker 			if (pio && !trace->found_issue) {
1109*1a3d31e3SAndroid Build Coastguard Worker 				pio->dispatch_time = io->time;
1110*1a3d31e3SAndroid Build Coastguard Worker 				goto account_io;
1111*1a3d31e3SAndroid Build Coastguard Worker 			}
1112*1a3d31e3SAndroid Build Coastguard Worker 		}
1113*1a3d31e3SAndroid Build Coastguard Worker 		return;
1114*1a3d31e3SAndroid Build Coastguard Worker 	}
1115*1a3d31e3SAndroid Build Coastguard Worker 	if (action == __BLK_TA_REQUEUE) {
1116*1a3d31e3SAndroid Build Coastguard Worker 		if (ios_in_flight > 0)
1117*1a3d31e3SAndroid Build Coastguard Worker 			ios_in_flight--;
1118*1a3d31e3SAndroid Build Coastguard Worker 		return;
1119*1a3d31e3SAndroid Build Coastguard Worker 	}
1120*1a3d31e3SAndroid Build Coastguard Worker 	if (action != __BLK_TA_ISSUE)
1121*1a3d31e3SAndroid Build Coastguard Worker 		return;
1122*1a3d31e3SAndroid Build Coastguard Worker 
1123*1a3d31e3SAndroid Build Coastguard Worker 	pio = hash_dispatched_io(trace->io);
1124*1a3d31e3SAndroid Build Coastguard Worker 	if (!pio)
1125*1a3d31e3SAndroid Build Coastguard Worker 		return;
1126*1a3d31e3SAndroid Build Coastguard Worker 
1127*1a3d31e3SAndroid Build Coastguard Worker 	if (!trace->found_completion) {
1128*1a3d31e3SAndroid Build Coastguard Worker 		list_del(&pio->hash_list);
1129*1a3d31e3SAndroid Build Coastguard Worker 		free(pio);
1130*1a3d31e3SAndroid Build Coastguard Worker 	}
1131*1a3d31e3SAndroid Build Coastguard Worker 
1132*1a3d31e3SAndroid Build Coastguard Worker account_io:
1133*1a3d31e3SAndroid Build Coastguard Worker 	ios_in_flight++;
1134*1a3d31e3SAndroid Build Coastguard Worker 
1135*1a3d31e3SAndroid Build Coastguard Worker 	seconds = SECONDS(io->time);
1136*1a3d31e3SAndroid Build Coastguard Worker 	gld->data[seconds].sum += ios_in_flight;
1137*1a3d31e3SAndroid Build Coastguard Worker 	gld->data[seconds].count++;
1138*1a3d31e3SAndroid Build Coastguard Worker 
1139*1a3d31e3SAndroid Build Coastguard Worker 	avg = (double)gld->data[seconds].sum / gld->data[seconds].count;
1140*1a3d31e3SAndroid Build Coastguard Worker 	if (gld->max < (u64)avg) {
1141*1a3d31e3SAndroid Build Coastguard Worker 		gld->max = avg;
1142*1a3d31e3SAndroid Build Coastguard Worker 	}
1143*1a3d31e3SAndroid Build Coastguard Worker }
1144*1a3d31e3SAndroid Build Coastguard Worker 
add_completed_io(struct trace * trace,struct graph_line_data * latency_gld)1145*1a3d31e3SAndroid Build Coastguard Worker void add_completed_io(struct trace *trace,
1146*1a3d31e3SAndroid Build Coastguard Worker 		      struct graph_line_data *latency_gld)
1147*1a3d31e3SAndroid Build Coastguard Worker {
1148*1a3d31e3SAndroid Build Coastguard Worker 	struct blk_io_trace *io = trace->io;
1149*1a3d31e3SAndroid Build Coastguard Worker 	int seconds;
1150*1a3d31e3SAndroid Build Coastguard Worker 	int action = io->action & BLK_TA_MASK;
1151*1a3d31e3SAndroid Build Coastguard Worker 	struct pending_io *pio;
1152*1a3d31e3SAndroid Build Coastguard Worker 	double avg;
1153*1a3d31e3SAndroid Build Coastguard Worker 	u64 latency;
1154*1a3d31e3SAndroid Build Coastguard Worker 
1155*1a3d31e3SAndroid Build Coastguard Worker 	if (io->action & BLK_TC_ACT(BLK_TC_NOTIFY))
1156*1a3d31e3SAndroid Build Coastguard Worker 		return;
1157*1a3d31e3SAndroid Build Coastguard Worker 
1158*1a3d31e3SAndroid Build Coastguard Worker 	if (action != __BLK_TA_COMPLETE)
1159*1a3d31e3SAndroid Build Coastguard Worker 		return;
1160*1a3d31e3SAndroid Build Coastguard Worker 
1161*1a3d31e3SAndroid Build Coastguard Worker 	seconds = SECONDS(io->time);
1162*1a3d31e3SAndroid Build Coastguard Worker 
1163*1a3d31e3SAndroid Build Coastguard Worker 	pio = hash_completed_io(trace->io);
1164*1a3d31e3SAndroid Build Coastguard Worker 	if (!pio)
1165*1a3d31e3SAndroid Build Coastguard Worker 		return;
1166*1a3d31e3SAndroid Build Coastguard Worker 
1167*1a3d31e3SAndroid Build Coastguard Worker 	if (ios_in_flight > 0)
1168*1a3d31e3SAndroid Build Coastguard Worker 		ios_in_flight--;
1169*1a3d31e3SAndroid Build Coastguard Worker 	if (io->time >= pio->dispatch_time) {
1170*1a3d31e3SAndroid Build Coastguard Worker 		latency = io->time - pio->dispatch_time;
1171*1a3d31e3SAndroid Build Coastguard Worker 		latency_gld->data[seconds].sum += latency;
1172*1a3d31e3SAndroid Build Coastguard Worker 		latency_gld->data[seconds].count++;
1173*1a3d31e3SAndroid Build Coastguard Worker 	}
1174*1a3d31e3SAndroid Build Coastguard Worker 
1175*1a3d31e3SAndroid Build Coastguard Worker 	list_del(&pio->hash_list);
1176*1a3d31e3SAndroid Build Coastguard Worker 	free(pio);
1177*1a3d31e3SAndroid Build Coastguard Worker 
1178*1a3d31e3SAndroid Build Coastguard Worker 	avg = (double)latency_gld->data[seconds].sum /
1179*1a3d31e3SAndroid Build Coastguard Worker 		latency_gld->data[seconds].count;
1180*1a3d31e3SAndroid Build Coastguard Worker 	if (latency_gld->max < (u64)avg) {
1181*1a3d31e3SAndroid Build Coastguard Worker 		latency_gld->max = avg;
1182*1a3d31e3SAndroid Build Coastguard Worker 	}
1183*1a3d31e3SAndroid Build Coastguard Worker }
1184*1a3d31e3SAndroid Build Coastguard Worker 
add_iop(struct trace * trace,struct graph_line_data * gld)1185*1a3d31e3SAndroid Build Coastguard Worker void add_iop(struct trace *trace, struct graph_line_data *gld)
1186*1a3d31e3SAndroid Build Coastguard Worker {
1187*1a3d31e3SAndroid Build Coastguard Worker 	struct blk_io_trace *io = trace->io;
1188*1a3d31e3SAndroid Build Coastguard Worker 	int action = io->action & BLK_TA_MASK;
1189*1a3d31e3SAndroid Build Coastguard Worker 	int seconds;
1190*1a3d31e3SAndroid Build Coastguard Worker 
1191*1a3d31e3SAndroid Build Coastguard Worker 	if (io->action & BLK_TC_ACT(BLK_TC_NOTIFY))
1192*1a3d31e3SAndroid Build Coastguard Worker 		return;
1193*1a3d31e3SAndroid Build Coastguard Worker 
1194*1a3d31e3SAndroid Build Coastguard Worker 	/* iops and tput use the same events */
1195*1a3d31e3SAndroid Build Coastguard Worker 	if (action != tput_event(trace))
1196*1a3d31e3SAndroid Build Coastguard Worker 		return;
1197*1a3d31e3SAndroid Build Coastguard Worker 
1198*1a3d31e3SAndroid Build Coastguard Worker 	seconds = SECONDS(io->time);
1199*1a3d31e3SAndroid Build Coastguard Worker 	gld->data[seconds].sum += 1;
1200*1a3d31e3SAndroid Build Coastguard Worker 	gld->data[seconds].count = 1;
1201*1a3d31e3SAndroid Build Coastguard Worker 	if (gld->data[seconds].sum > gld->max)
1202*1a3d31e3SAndroid Build Coastguard Worker 		gld->max = gld->data[seconds].sum;
1203*1a3d31e3SAndroid Build Coastguard Worker }
1204*1a3d31e3SAndroid Build Coastguard Worker 
check_record(struct trace * trace)1205*1a3d31e3SAndroid Build Coastguard Worker void check_record(struct trace *trace)
1206*1a3d31e3SAndroid Build Coastguard Worker {
1207*1a3d31e3SAndroid Build Coastguard Worker 	handle_notify(trace);
1208*1a3d31e3SAndroid Build Coastguard Worker }
1209