• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// 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
5'use strict';
6
7/**
8 * @fileoverview Parses filesystem and block device events in the Linux event
9 * trace format.
10 */
11base.require('tracing.importer.linux_perf.parser');
12base.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
23    importer.registerEventHandler('ext4_sync_file_enter',
24        DiskParser.prototype.ext4SyncFileEnterEvent.bind(this));
25    importer.registerEventHandler('ext4_sync_file_exit',
26        DiskParser.prototype.ext4SyncFileExitEvent.bind(this));
27    importer.registerEventHandler('block_rq_issue',
28        DiskParser.prototype.blockRqIssueEvent.bind(this));
29    importer.registerEventHandler('block_rq_complete',
30        DiskParser.prototype.blockRqCompleteEvent.bind(this));
31  }
32
33  DiskParser.prototype = {
34    __proto__: Parser.prototype,
35
36    openAsyncSlice: function(ts, category, threadName, pid, key, name) {
37      var kthread = this.importer.getOrCreateKernelThread(
38          category + ':' + threadName, pid);
39      var slice = new tracing.trace_model.AsyncSlice(
40          category, name, tracing.getStringColorId(name), ts);
41      slice.startThread = kthread.thread;
42
43      if (!kthread.openAsyncSlices) {
44        kthread.openAsyncSlices = { };
45      }
46      kthread.openAsyncSlices[key] = slice;
47    },
48
49    closeAsyncSlice: function(ts, category, threadName, pid, key, args) {
50      var kthread = this.importer.getOrCreateKernelThread(
51          category + ':' + threadName, pid);
52      if (kthread.openAsyncSlices) {
53        var slice = kthread.openAsyncSlices[key];
54        if (slice) {
55          slice.duration = ts - slice.start;
56          slice.args = args;
57          slice.endThread = kthread.thread;
58          slice.subSlices = [
59            new tracing.trace_model.Slice(category, slice.title,
60                slice.colorId, slice.start, slice.args, slice.duration)
61          ];
62          kthread.thread.asyncSliceGroup.push(slice);
63          delete kthread.openAsyncSlices[key];
64        }
65      }
66    },
67
68    /**
69     * Parses events and sets up state in the importer.
70     */
71    ext4SyncFileEnterEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
72      var event = /dev (\d+,\d+) ino (\d+) parent (\d+) datasync (\d+)/.
73          exec(eventBase.details);
74      if (!event)
75        return false;
76
77      var device = event[1];
78      var inode = parseInt(event[2]);
79      var datasync = event[4] == 1;
80      var key = device + '-' + inode;
81      var action = datasync ? 'fdatasync' : 'fsync';
82      this.openAsyncSlice(ts, 'ext4', eventBase.threadName, eventBase.pid,
83          key, action);
84      return true;
85    },
86
87    ext4SyncFileExitEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
88      var event = /dev (\d+,\d+) ino (\d+) ret (\d+)/.exec(eventBase.details);
89      if (!event)
90        return false;
91
92      var device = event[1];
93      var inode = parseInt(event[2]);
94      var error = parseInt(event[3]);
95      var key = device + '-' + inode;
96      this.closeAsyncSlice(ts, 'ext4', eventBase.threadName, eventBase.pid,
97          key, {
98            device: device,
99            inode: inode,
100            error: error
101          });
102      return true;
103    },
104
105    blockRqIssueEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
106      var event = new RegExp('(\\d+,\\d+) (F)?([DWRN])(F)?(A)?(S)?(M)? ' +
107          '\\d+ \\(.*\\) (\\d+) \\+ (\\d+) \\[.*\\]').exec(eventBase.details);
108      if (!event)
109        return false;
110
111      var action;
112      switch (event[3]) {
113        case 'D':
114          action = 'discard';
115          break;
116        case 'W':
117          action = 'write';
118          break;
119        case 'R':
120          action = 'read';
121          break;
122        case 'N':
123          action = 'none';
124          break;
125        default:
126          action = 'unknown';
127          break;
128      }
129
130      if (event[2]) {
131        action += ' flush';
132      }
133      if (event[4] == 'F') {
134        action += ' fua';
135      }
136      if (event[5] == 'A') {
137        action += ' ahead';
138      }
139      if (event[6] == 'S') {
140        action += ' sync';
141      }
142      if (event[7] == 'M') {
143        action += ' meta';
144      }
145      var device = event[1];
146      var sector = parseInt(event[8]);
147      var numSectors = parseInt(event[9]);
148      var key = device + '-' + sector + '-' + numSectors;
149      this.openAsyncSlice(ts, 'block', eventBase.threadName, eventBase.pid,
150          key, action);
151      return true;
152    },
153
154    blockRqCompleteEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
155      var event = new RegExp('(\\d+,\\d+) (F)?([DWRN])(F)?(A)?(S)?(M)? ' +
156          '\\(.*\\) (\\d+) \\+ (\\d+) \\[(.*)\\]').exec(eventBase.details);
157      if (!event)
158        return false;
159
160      var device = event[1];
161      var sector = parseInt(event[8]);
162      var numSectors = parseInt(event[9]);
163      var error = parseInt(event[10]);
164      var key = device + '-' + sector + '-' + numSectors;
165      this.closeAsyncSlice(ts, 'block', eventBase.threadName, eventBase.pid,
166          key, {
167            device: device,
168            sector: sector,
169            numSectors: numSectors,
170            error: error
171          });
172      return true;
173    }
174  };
175
176  Parser.registerSubtype(DiskParser);
177
178  return {
179    DiskParser: DiskParser
180  };
181});
182