Home | History | Annotate | Download | only in linux_perf
      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  */
     11 base.require('tracing.importer.linux_perf.parser');
     12 base.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('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));
     31     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));
     35     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));
     39     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);
     51       var slice = new tracing.trace_model.AsyncSlice(
     52           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;
     70           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);
     75           delete kthread.openAsyncSlices[key];
     76         }
     77       }
     78     },
     79 
     80     /**
     81      * Parses events and sets up state in the importer.
     82      */
     83     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 
    191     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, {
    218             device: device,
    219             inode: inode,
    220             error: error
    221           });
    222       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, {
    287             device: device,
    288             sector: sector,
    289             numSectors: numSectors,
    290             error: error
    291           });
    292       return true;
    293     }
    294   };
    295 
    296   Parser.registerSubtype(DiskParser);
    297 
    298   return {
    299     DiskParser: DiskParser
    300   };
    301 });
    302