Jeff Brown | 4849cea | 2013-04-01 16:56:16 -0700 | [diff] [blame] | 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 | |
Jamie Gennis | 66a3768 | 2013-07-15 18:29:18 -0700 | [diff] [blame] | 5 | 'use strict'; |
| 6 | |
Jeff Brown | 4849cea | 2013-04-01 16:56:16 -0700 | [diff] [blame] | 7 | /** |
| 8 | * @fileoverview Parses filesystem and block device events in the Linux event |
| 9 | * trace format. |
| 10 | */ |
Jamie Gennis | 66a3768 | 2013-07-15 18:29:18 -0700 | [diff] [blame] | 11 | base.require('tracing.importer.linux_perf.parser'); |
Jeff Brown | 4849cea | 2013-04-01 16:56:16 -0700 | [diff] [blame] | 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 | |
Mohamad Ayyash | 0d58d5e | 2014-04-11 17:56:30 -0700 | [diff] [blame^] | 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)); |
Jeff Brown | 4849cea | 2013-04-01 16:56:16 -0700 | [diff] [blame] | 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)); |
Mohamad Ayyash | 0d58d5e | 2014-04-11 17:56:30 -0700 | [diff] [blame^] | 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)); |
Jeff Brown | 4849cea | 2013-04-01 16:56:16 -0700 | [diff] [blame] | 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); |
Jamie Gennis | 66a3768 | 2013-07-15 18:29:18 -0700 | [diff] [blame] | 51 | var slice = new tracing.trace_model.AsyncSlice( |
Jeff Brown | 4849cea | 2013-04-01 16:56:16 -0700 | [diff] [blame] | 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; |
Jamie Gennis | 66a3768 | 2013-07-15 18:29:18 -0700 | [diff] [blame] | 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); |
Jeff Brown | 4849cea | 2013-04-01 16:56:16 -0700 | [diff] [blame] | 75 | delete kthread.openAsyncSlices[key]; |
| 76 | } |
| 77 | } |
| 78 | }, |
| 79 | |
| 80 | /** |
| 81 | * Parses events and sets up state in the importer. |
| 82 | */ |
Mohamad Ayyash | 0d58d5e | 2014-04-11 17:56:30 -0700 | [diff] [blame^] | 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 | |
Jeff Brown | 4849cea | 2013-04-01 16:56:16 -0700 | [diff] [blame] | 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, { |
Jamie Gennis | 66a3768 | 2013-07-15 18:29:18 -0700 | [diff] [blame] | 218 | device: device, |
| 219 | inode: inode, |
| 220 | error: error |
| 221 | }); |
Jeff Brown | 4849cea | 2013-04-01 16:56:16 -0700 | [diff] [blame] | 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, { |
Jamie Gennis | 66a3768 | 2013-07-15 18:29:18 -0700 | [diff] [blame] | 287 | device: device, |
| 288 | sector: sector, |
| 289 | numSectors: numSectors, |
| 290 | error: error |
| 291 | }); |
Jeff Brown | 4849cea | 2013-04-01 16:56:16 -0700 | [diff] [blame] | 292 | return true; |
Jamie Gennis | 66a3768 | 2013-07-15 18:29:18 -0700 | [diff] [blame] | 293 | } |
Jeff Brown | 4849cea | 2013-04-01 16:56:16 -0700 | [diff] [blame] | 294 | }; |
| 295 | |
| 296 | Parser.registerSubtype(DiskParser); |
| 297 | |
| 298 | return { |
| 299 | DiskParser: DiskParser |
| 300 | }; |
| 301 | }); |