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('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