blob: 40817682cba7ce4fcc44b53c7057317ad9081e88 [file] [log] [blame]
Jeff Brown4849cea2013-04-01 16:56:16 -07001// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Jamie Gennis66a37682013-07-15 18:29:18 -07005'use strict';
6
Jeff Brown4849cea2013-04-01 16:56:16 -07007/**
8 * @fileoverview Parses filesystem and block device events in the Linux event
9 * trace format.
10 */
Jamie Gennis66a37682013-07-15 18:29:18 -070011base.require('tracing.importer.linux_perf.parser');
Jeff Brown4849cea2013-04-01 16:56:16 -070012base.exportTo('tracing.importer.linux_perf', function() {
13
14 var Parser = tracing.importer.linux_perf.Parser;
15
16 /**
17 * Parses linux filesystem and block device trace events.
18 * @constructor
19 */
20 function DiskParser(importer) {
21 Parser.call(this, importer);
22
Mohamad Ayyash0d58d5e2014-04-11 17:56:30 -070023 importer.registerEventHandler('f2fs_write_begin',
24 DiskParser.prototype.f2fsWriteBeginEvent.bind(this));
25 importer.registerEventHandler('f2fs_write_end',
26 DiskParser.prototype.f2fsWriteEndEvent.bind(this));
27 importer.registerEventHandler('f2fs_sync_file_enter',
28 DiskParser.prototype.f2fsSyncFileEnterEvent.bind(this));
29 importer.registerEventHandler('f2fs_sync_file_exit',
30 DiskParser.prototype.f2fsSyncFileExitEvent.bind(this));
Jeff Brown4849cea2013-04-01 16:56:16 -070031 importer.registerEventHandler('ext4_sync_file_enter',
32 DiskParser.prototype.ext4SyncFileEnterEvent.bind(this));
33 importer.registerEventHandler('ext4_sync_file_exit',
34 DiskParser.prototype.ext4SyncFileExitEvent.bind(this));
Mohamad Ayyash0d58d5e2014-04-11 17:56:30 -070035 importer.registerEventHandler('ext4_da_write_begin',
36 DiskParser.prototype.ext4WriteBeginEvent.bind(this));
37 importer.registerEventHandler('ext4_da_write_end',
38 DiskParser.prototype.ext4WriteEndEvent.bind(this));
Jeff Brown4849cea2013-04-01 16:56:16 -070039 importer.registerEventHandler('block_rq_issue',
40 DiskParser.prototype.blockRqIssueEvent.bind(this));
41 importer.registerEventHandler('block_rq_complete',
42 DiskParser.prototype.blockRqCompleteEvent.bind(this));
43 }
44
45 DiskParser.prototype = {
46 __proto__: Parser.prototype,
47
48 openAsyncSlice: function(ts, category, threadName, pid, key, name) {
49 var kthread = this.importer.getOrCreateKernelThread(
50 category + ':' + threadName, pid);
Jamie Gennis66a37682013-07-15 18:29:18 -070051 var slice = new tracing.trace_model.AsyncSlice(
Jeff Brown4849cea2013-04-01 16:56:16 -070052 category, name, tracing.getStringColorId(name), ts);
53 slice.startThread = kthread.thread;
54
55 if (!kthread.openAsyncSlices) {
56 kthread.openAsyncSlices = { };
57 }
58 kthread.openAsyncSlices[key] = slice;
59 },
60
61 closeAsyncSlice: function(ts, category, threadName, pid, key, args) {
62 var kthread = this.importer.getOrCreateKernelThread(
63 category + ':' + threadName, pid);
64 if (kthread.openAsyncSlices) {
65 var slice = kthread.openAsyncSlices[key];
66 if (slice) {
67 slice.duration = ts - slice.start;
68 slice.args = args;
69 slice.endThread = kthread.thread;
Jamie Gennis66a37682013-07-15 18:29:18 -070070 slice.subSlices = [
71 new tracing.trace_model.Slice(category, slice.title,
72 slice.colorId, slice.start, slice.args, slice.duration)
73 ];
74 kthread.thread.asyncSliceGroup.push(slice);
Jeff Brown4849cea2013-04-01 16:56:16 -070075 delete kthread.openAsyncSlices[key];
76 }
77 }
78 },
79
80 /**
81 * Parses events and sets up state in the importer.
82 */
Mohamad Ayyash0d58d5e2014-04-11 17:56:30 -070083 f2fsWriteBeginEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
84 var event = /dev = \((\d+,\d+)\), ino = (\d+), pos = (\d+), len = (\d+), flags = (\d+)/.
85 exec(eventBase.details);
86 if (!event)
87 return false;
88 var device = event[1];
89 var inode = parseInt(event[2]);
90 var pos = parseInt(event[3]);
91 var len = parseInt(event[4]);
92 var key = device + '-' + inode + '-' + pos + '-' + len;
93 this.openAsyncSlice(ts, "f2fs", eventBase.threadName, eventBase.pid,
94 key, "f2fs_write");
95 return true;
96 },
97
98 f2fsWriteEndEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
99 var event = /dev = \((\d+,\d+)\), ino = (\d+), pos = (\d+), len = (\d+), copied = (\d+)/.
100 exec(eventBase.details);
101 if (!event)
102 return false;
103
104 var device = event[1];
105 var inode = parseInt(event[2]);
106 var pos = parseInt(event[3]);
107 var len = parseInt(event[4]);
108 var error = parseInt(event[5]) !== len;
109 var key = device + '-' + inode + '-' + pos + '-' + len;
110 this.closeAsyncSlice(ts, 'f2fs', eventBase.threadName, eventBase.pid,
111 key, {
112 device: device,
113 inode: inode,
114 error: error
115 });
116 return true;
117 },
118
119 ext4WriteBeginEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
120 var event = /dev (\d+,\d+) ino (\d+) pos (\d+) len (\d+) flags (\d+)/.
121 exec(eventBase.details);
122 if (!event)
123 return false;
124 var device = event[1];
125 var inode = parseInt(event[2]);
126 var pos = parseInt(event[3]);
127 var len = parseInt(event[4]);
128 var key = device + '-' + inode + '-' + pos + '-' + len;
129 this.openAsyncSlice(ts, "ext4", eventBase.threadName, eventBase.pid,
130 key, "ext4_write");
131 return true;
132 },
133
134 ext4WriteEndEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
135 var event = /dev (\d+,\d+) ino (\d+) pos (\d+) len (\d+) copied (\d+)/.
136 exec(eventBase.details);
137 if (!event)
138 return false;
139
140 var device = event[1];
141 var inode = parseInt(event[2]);
142 var pos = parseInt(event[3]);
143 var len = parseInt(event[4]);
144 var error = parseInt(event[5]) !== len;
145 var key = device + '-' + inode + '-' + pos + '-' + len;
146 this.closeAsyncSlice(ts, 'ext4', eventBase.threadName, eventBase.pid,
147 key, {
148 device: device,
149 inode: inode,
150 error: error
151 });
152 return true;
153 },
154
155 f2fsSyncFileEnterEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
156 var event = new RegExp(
157 'dev = \\((\\d+,\\d+)\\), ino = (\\d+), pino = (\\d+), i_mode = (\\S+), ' +
158 'i_size = (\\d+), i_nlink = (\\d+), i_blocks = (\\d+), i_advise = (\\d+)').
159 exec(eventBase.details);
160 if (!event)
161 return false;
162
163 var device = event[1];
164 var inode = parseInt(event[2]);
165 var key = device + '-' + inode;
166 this.openAsyncSlice(ts, 'f2fs', eventBase.threadName, eventBase.pid,
167 key, 'fsync');
168 return true;
169 },
170
171 f2fsSyncFileExitEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
172 var event = new RegExp('dev = \\((\\d+,\\d+)\\), ino = (\\d+), checkpoint is (\\S+), ' +
173 'datasync = (\\d+), ret = (\\d+)').
174 exec(eventBase.details.replace("not needed", "not_needed"));
175 if (!event)
176 return false;
177
178 var device = event[1];
179 var inode = parseInt(event[2]);
180 var error = parseInt(event[5]);
181 var key = device + '-' + inode;
182 this.closeAsyncSlice(ts, 'f2fs', eventBase.threadName, eventBase.pid,
183 key, {
184 device: device,
185 inode: inode,
186 error: error
187 });
188 return true;
189 },
190
Jeff Brown4849cea2013-04-01 16:56:16 -0700191 ext4SyncFileEnterEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
192 var event = /dev (\d+,\d+) ino (\d+) parent (\d+) datasync (\d+)/.
193 exec(eventBase.details);
194 if (!event)
195 return false;
196
197 var device = event[1];
198 var inode = parseInt(event[2]);
199 var datasync = event[4] == 1;
200 var key = device + '-' + inode;
201 var action = datasync ? 'fdatasync' : 'fsync';
202 this.openAsyncSlice(ts, 'ext4', eventBase.threadName, eventBase.pid,
203 key, action);
204 return true;
205 },
206
207 ext4SyncFileExitEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
208 var event = /dev (\d+,\d+) ino (\d+) ret (\d+)/.exec(eventBase.details);
209 if (!event)
210 return false;
211
212 var device = event[1];
213 var inode = parseInt(event[2]);
214 var error = parseInt(event[3]);
215 var key = device + '-' + inode;
216 this.closeAsyncSlice(ts, 'ext4', eventBase.threadName, eventBase.pid,
217 key, {
Jamie Gennis66a37682013-07-15 18:29:18 -0700218 device: device,
219 inode: inode,
220 error: error
221 });
Jeff Brown4849cea2013-04-01 16:56:16 -0700222 return true;
223 },
224
225 blockRqIssueEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
226 var event = new RegExp('(\\d+,\\d+) (F)?([DWRN])(F)?(A)?(S)?(M)? ' +
227 '\\d+ \\(.*\\) (\\d+) \\+ (\\d+) \\[.*\\]').exec(eventBase.details);
228 if (!event)
229 return false;
230
231 var action;
232 switch (event[3]) {
233 case 'D':
234 action = 'discard';
235 break;
236 case 'W':
237 action = 'write';
238 break;
239 case 'R':
240 action = 'read';
241 break;
242 case 'N':
243 action = 'none';
244 break;
245 default:
246 action = 'unknown';
247 break;
248 }
249
250 if (event[2]) {
251 action += ' flush';
252 }
253 if (event[4] == 'F') {
254 action += ' fua';
255 }
256 if (event[5] == 'A') {
257 action += ' ahead';
258 }
259 if (event[6] == 'S') {
260 action += ' sync';
261 }
262 if (event[7] == 'M') {
263 action += ' meta';
264 }
265 var device = event[1];
266 var sector = parseInt(event[8]);
267 var numSectors = parseInt(event[9]);
268 var key = device + '-' + sector + '-' + numSectors;
269 this.openAsyncSlice(ts, 'block', eventBase.threadName, eventBase.pid,
270 key, action);
271 return true;
272 },
273
274 blockRqCompleteEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
275 var event = new RegExp('(\\d+,\\d+) (F)?([DWRN])(F)?(A)?(S)?(M)? ' +
276 '\\(.*\\) (\\d+) \\+ (\\d+) \\[(.*)\\]').exec(eventBase.details);
277 if (!event)
278 return false;
279
280 var device = event[1];
281 var sector = parseInt(event[8]);
282 var numSectors = parseInt(event[9]);
283 var error = parseInt(event[10]);
284 var key = device + '-' + sector + '-' + numSectors;
285 this.closeAsyncSlice(ts, 'block', eventBase.threadName, eventBase.pid,
286 key, {
Jamie Gennis66a37682013-07-15 18:29:18 -0700287 device: device,
288 sector: sector,
289 numSectors: numSectors,
290 error: error
291 });
Jeff Brown4849cea2013-04-01 16:56:16 -0700292 return true;
Jamie Gennis66a37682013-07-15 18:29:18 -0700293 }
Jeff Brown4849cea2013-04-01 16:56:16 -0700294 };
295
296 Parser.registerSubtype(DiskParser);
297
298 return {
299 DiskParser: DiskParser
300 };
301});