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