1 // Copyright (c) 2012 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 vmscan events in the Linux event trace format. 9 */ 10 base.require('tracing.importer.linux_perf.parser'); 11 base.exportTo('tracing.importer.linux_perf', function() { 12 13 var Parser = tracing.importer.linux_perf.Parser; 14 15 /** 16 * Parses linux vmscan trace events. 17 * @constructor 18 */ 19 function MemReclaimParser(importer) { 20 Parser.call(this, importer); 21 22 importer.registerEventHandler('mm_vmscan_kswapd_wake', 23 MemReclaimParser.prototype.kswapdWake.bind(this)); 24 importer.registerEventHandler('mm_vmscan_kswapd_sleep', 25 MemReclaimParser.prototype.kswapdSleep.bind(this)); 26 importer.registerEventHandler('mm_vmscan_direct_reclaim_begin', 27 MemReclaimParser.prototype.reclaimBegin.bind(this)); 28 importer.registerEventHandler('mm_vmscan_direct_reclaim_end', 29 MemReclaimParser.prototype.reclaimEnd.bind(this)); 30 } 31 32 // Matches the mm_vmscan_kswapd_wake record 33 // mm_vmscan_kswapd_wake: nid=%d order=%d 34 var kswapdWakeRE = /nid=(\d+) order=(\d+)/; 35 36 // Matches the mm_vmscan_kswapd_sleep record 37 // mm_vmscan_kswapd_sleep: order=%d 38 var kswapdSleepRE = /nid=(\d+)/; 39 40 // Matches the mm_vmscan_direct_reclaim_begin record 41 // mm_vmscan_direct_reclaim_begin: order=%d may_writepage=%d gfp_flags=%s 42 var reclaimBeginRE = /order=(\d+) may_writepage=\d+ gfp_flags=(.+)/; 43 44 // Matches the mm_vmscan_direct_reclaim_end record 45 // mm_vmscan_direct_reclaim_end: nr_reclaimed=%lu 46 var reclaimEndRE = /nr_reclaimed=(\d+)/; 47 48 MemReclaimParser.prototype = { 49 __proto__: Parser.prototype, 50 51 openAsyncSlice: function(ts, category, threadName, pid, key, name) { 52 var kthread = this.importer.getOrCreateKernelThread( 53 category + ':' + threadName, pid); 54 var slice = new tracing.trace_model.AsyncSlice( 55 category, name, tracing.getStringColorId(name), ts); 56 slice.startThread = kthread.thread; 57 58 if (!kthread.openAsyncSlices) { 59 kthread.openAsyncSlices = { }; 60 } 61 kthread.openAsyncSlices[key] = slice; 62 }, 63 64 closeAsyncSlice: function(ts, category, threadName, pid, key, args) { 65 var kthread = this.importer.getOrCreateKernelThread( 66 category + ':' + threadName, pid); 67 if (kthread.openAsyncSlices) { 68 var slice = kthread.openAsyncSlices[key]; 69 if (slice) { 70 slice.duration = ts - slice.start; 71 slice.args = args; 72 slice.endThread = kthread.thread; 73 slice.subSlices = [ 74 new tracing.trace_model.Slice(category, slice.title, 75 slice.colorId, slice.start, slice.args, slice.duration) 76 ]; 77 kthread.thread.asyncSliceGroup.push(slice); 78 delete kthread.openAsyncSlices[key]; 79 } 80 } 81 }, 82 83 /** 84 * Parses memreclaim events and sets up state in the importer. 85 */ 86 kswapdWake: function(eventName, cpuNumber, pid, ts, eventBase) { 87 var event = kswapdWakeRE.exec(eventBase.details); 88 if (!event) 89 return false; 90 91 var nid = parseInt(event[1]) 92 var order = parseInt(event[2]) 93 94 var kthread = this.importer.getOrCreateKernelThread("kswapd: " + eventBase.threadName, 95 pid, pid); 96 if (kthread.openSliceTS) { 97 if (order > kthread.order) { 98 kthread.order = order; 99 } 100 } else { 101 kthread.openSliceTS = ts; 102 kthread.order = order; 103 } 104 return true; 105 }, 106 107 kswapdSleep: function(eventName, cpuNumber, pid, ts, eventBase) { 108 var kthread = this.importer.getOrCreateKernelThread("kswapd: " + eventBase.threadName, 109 pid, pid); 110 if (kthread.openSliceTS) { 111 var slice = new tracing.trace_model.Slice('', eventBase.threadName, 112 tracing.getStringColorId(eventBase.threadName), 113 kthread.openSliceTS, 114 { 115 order: kthread.order, 116 }, 117 ts - kthread.openSliceTS); 118 119 kthread.thread.sliceGroup.pushSlice(slice); 120 } 121 kthread.openSliceTS = undefined; 122 kthread.order = undefined; 123 return true; 124 }, 125 126 reclaimBegin: function(eventName, cpuNumber, pid, ts, eventBase) { 127 var event = reclaimBeginRE.exec(eventBase.details); 128 if (!event) 129 return false; 130 131 var order = parseInt(event[1]); 132 var gfp = event[2] 133 134 var kthread = this.importer.getOrCreateKernelThread("direct reclaim: " + eventBase.threadName, 135 pid, pid); 136 kthread.openSliceTS = ts; 137 kthread.order = order; 138 kthread.gfp = gfp; 139 return true; 140 }, 141 142 reclaimEnd: function(eventName, cpuNumber, pid, ts, eventBase) { 143 var event = reclaimEndRE.exec(eventBase.details); 144 if (!event) 145 return false; 146 147 var nr_reclaimed = parseInt(event[1]); 148 149 var kthread = this.importer.getOrCreateKernelThread("direct reclaim: " + eventBase.threadName, 150 pid, pid); 151 if (kthread.openSliceTS !== undefined) { 152 var slice = new tracing.trace_model.Slice( 153 "", "direct reclaim", 154 tracing.getStringColorId(eventBase.threadName), 155 kthread.openSliceTS, 156 { 157 order: kthread.order, 158 gfp: kthread.gfp, 159 nr_reclaimed: nr_reclaimed, 160 }, 161 ts - kthread.openSliceTS); 162 kthread.thread.sliceGroup.pushSlice(slice); 163 } 164 kthread.openSliceTS = undefined; 165 kthread.order = undefined; 166 kthread.gfp = undefined; 167 return true; 168 } 169 170 }; 171 172 Parser.registerSubtype(MemReclaimParser); 173 174 return { 175 MemReclaimParser: MemReclaimParser 176 }; 177 }); 178