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