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