• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 Mali DDK/kernel events in the Linux event trace format.
9 */
10base.require('tracing.importer.linux_perf.parser');
11base.exportTo('tracing.importer.linux_perf', function() {
12
13  var Parser = tracing.importer.linux_perf.Parser;
14
15  /**
16   * Parses Mali DDK/kernel trace events.
17   * @constructor
18   */
19  function MaliParser(importer) {
20    Parser.call(this, importer);
21
22    // kernel DVFS events
23    importer.registerEventHandler('mali_dvfs_event',
24        MaliParser.prototype.dvfsEventEvent.bind(this));
25    importer.registerEventHandler('mali_dvfs_set_clock',
26        MaliParser.prototype.dvfsSetClockEvent.bind(this));
27    importer.registerEventHandler('mali_dvfs_set_voltage',
28        MaliParser.prototype.dvfsSetVoltageEvent.bind(this));
29
30    // kernel Mali hw counter events
31    this.addJMCounter('mali_hwc_MESSAGES_SENT', 'Messages Sent');
32    this.addJMCounter('mali_hwc_MESSAGES_RECEIVED', 'Messages Received');
33    this.addJMCycles('mali_hwc_GPU_ACTIVE', 'GPU Active');
34    this.addJMCycles('mali_hwc_IRQ_ACTIVE', 'IRQ Active');
35
36    for (var i = 0; i < 7; i++) {
37      var jobStr = 'JS' + i;
38      var jobHWCStr = 'mali_hwc_' + jobStr;
39      this.addJMCounter(jobHWCStr + '_JOBS', jobStr + ' Jobs');
40      this.addJMCounter(jobHWCStr + '_TASKS', jobStr + ' Tasks');
41      this.addJMCycles(jobHWCStr + '_ACTIVE', jobStr + ' Active');
42      this.addJMCycles(jobHWCStr + '_WAIT_READ', jobStr + ' Wait Read');
43      this.addJMCycles(jobHWCStr + '_WAIT_ISSUE', jobStr + ' Wait Issue');
44      this.addJMCycles(jobHWCStr + '_WAIT_DEPEND', jobStr + ' Wait Depend');
45      this.addJMCycles(jobHWCStr + '_WAIT_FINISH', jobStr + ' Wait Finish');
46    }
47
48    this.addTilerCounter('mali_hwc_TRIANGLES', 'Triangles');
49    this.addTilerCounter('mali_hwc_QUADS', 'Quads');
50    this.addTilerCounter('mali_hwc_POLYGONS', 'Polygons');
51    this.addTilerCounter('mali_hwc_POINTS', 'Points');
52    this.addTilerCounter('mali_hwc_LINES', 'Lines');
53    this.addTilerCounter('mali_hwc_VCACHE_HIT', 'VCache Hit');
54    this.addTilerCounter('mali_hwc_VCACHE_MISS', 'VCache Miss');
55    this.addTilerCounter('mali_hwc_FRONT_FACING', 'Front Facing');
56    this.addTilerCounter('mali_hwc_BACK_FACING', 'Back Facing');
57    this.addTilerCounter('mali_hwc_PRIM_VISIBLE', 'Prim Visible');
58    this.addTilerCounter('mali_hwc_PRIM_CULLED', 'Prim Culled');
59    this.addTilerCounter('mali_hwc_PRIM_CLIPPED', 'Prim Clipped');
60
61    this.addTilerCounter('mali_hwc_WRBUF_HIT', 'Wrbuf Hit');
62    this.addTilerCounter('mali_hwc_WRBUF_MISS', 'Wrbuf Miss');
63    this.addTilerCounter('mali_hwc_WRBUF_LINE', 'Wrbuf Line');
64    this.addTilerCounter('mali_hwc_WRBUF_PARTIAL', 'Wrbuf Partial');
65    this.addTilerCounter('mali_hwc_WRBUF_STALL', 'Wrbuf Stall');
66
67    this.addTilerCycles('mali_hwc_ACTIVE', 'Tiler Active');
68    this.addTilerCycles('mali_hwc_INDEX_WAIT', 'Index Wait');
69    this.addTilerCycles('mali_hwc_INDEX_RANGE_WAIT', 'Index Range Wait');
70    this.addTilerCycles('mali_hwc_VERTEX_WAIT', 'Vertex Wait');
71    this.addTilerCycles('mali_hwc_PCACHE_WAIT', 'Pcache Wait');
72    this.addTilerCycles('mali_hwc_WRBUF_WAIT', 'Wrbuf Wait');
73    this.addTilerCycles('mali_hwc_BUS_READ', 'Bus Read');
74    this.addTilerCycles('mali_hwc_BUS_WRITE', 'Bus Write');
75
76    this.addTilerCycles('mali_hwc_TILER_UTLB_STALL', 'Tiler UTLB Stall');
77    this.addTilerCycles('mali_hwc_TILER_UTLB_HIT', 'Tiler UTLB Hit');
78
79    this.addFragCycles('mali_hwc_FRAG_ACTIVE', 'Active');
80    /* NB: don't propagate spelling mistakes to labels */
81    this.addFragCounter('mali_hwc_FRAG_PRIMATIVES', 'Primitives');
82    this.addFragCounter('mali_hwc_FRAG_PRIMATIVES_DROPPED',
83        'Primitives Dropped');
84    this.addFragCycles('mali_hwc_FRAG_CYCLE_DESC', 'Descriptor Processing');
85    this.addFragCycles('mali_hwc_FRAG_CYCLES_PLR', 'PLR Processing??');
86    this.addFragCycles('mali_hwc_FRAG_CYCLES_VERT', 'Vertex Processing');
87    this.addFragCycles('mali_hwc_FRAG_CYCLES_TRISETUP', 'Triangle Setup');
88    this.addFragCycles('mali_hwc_FRAG_CYCLES_RAST', 'Rasterization???');
89    this.addFragCounter('mali_hwc_FRAG_THREADS', 'Threads');
90    this.addFragCounter('mali_hwc_FRAG_DUMMY_THREADS', 'Dummy Threads');
91    this.addFragCounter('mali_hwc_FRAG_QUADS_RAST', 'Quads Rast');
92    this.addFragCounter('mali_hwc_FRAG_QUADS_EZS_TEST', 'Quads EZS Test');
93    this.addFragCounter('mali_hwc_FRAG_QUADS_EZS_KILLED', 'Quads EZS Killed');
94    this.addFragCounter('mali_hwc_FRAG_QUADS_LZS_TEST', 'Quads LZS Test');
95    this.addFragCounter('mali_hwc_FRAG_QUADS_LZS_KILLED', 'Quads LZS Killed');
96    this.addFragCycles('mali_hwc_FRAG_CYCLE_NO_TILE', 'No Tiles');
97    this.addFragCounter('mali_hwc_FRAG_NUM_TILES', 'Tiles');
98    this.addFragCounter('mali_hwc_FRAG_TRANS_ELIM', 'Transactions Eliminated');
99
100    this.addComputeCycles('mali_hwc_COMPUTE_ACTIVE', 'Active');
101    this.addComputeCounter('mali_hwc_COMPUTE_TASKS', 'Tasks');
102    this.addComputeCounter('mali_hwc_COMPUTE_THREADS', 'Threads Started');
103    this.addComputeCycles('mali_hwc_COMPUTE_CYCLES_DESC',
104        'Waiting for Descriptors');
105
106    this.addTripipeCycles('mali_hwc_TRIPIPE_ACTIVE', 'Active');
107
108    this.addArithCounter('mali_hwc_ARITH_WORDS', 'Instructions (/Pipes)');
109    this.addArithCycles('mali_hwc_ARITH_CYCLES_REG',
110        'Reg scheduling stalls (/Pipes)');
111    this.addArithCycles('mali_hwc_ARITH_CYCLES_L0',
112        'L0 cache miss stalls (/Pipes)');
113    this.addArithCounter('mali_hwc_ARITH_FRAG_DEPEND',
114        'Frag dep check failures (/Pipes)');
115
116    this.addLSCounter('mali_hwc_LS_WORDS', 'Instruction Words Completed');
117    this.addLSCounter('mali_hwc_LS_ISSUES', 'Full Pipeline Issues');
118    this.addLSCounter('mali_hwc_LS_RESTARTS', 'Restarts (unpairable insts)');
119    this.addLSCounter('mali_hwc_LS_REISSUES_MISS',
120        'Pipeline reissue (cache miss/uTLB)');
121    this.addLSCounter('mali_hwc_LS_REISSUES_VD',
122        'Pipeline reissue (varying data)');
123    /* TODO(sleffler) fix kernel event typo */
124    this.addLSCounter('mali_hwc_LS_REISSUE_ATTRIB_MISS',
125        'Pipeline reissue (attribute cache miss)');
126    this.addLSCounter('mali_hwc_LS_REISSUE_NO_WB', 'Writeback not used');
127
128    this.addTexCounter('mali_hwc_TEX_WORDS', 'Words');
129    this.addTexCounter('mali_hwc_TEX_BUBBLES', 'Bubbles');
130    this.addTexCounter('mali_hwc_TEX_WORDS_L0', 'Words L0');
131    this.addTexCounter('mali_hwc_TEX_WORDS_DESC', 'Words Desc');
132    this.addTexCounter('mali_hwc_TEX_THREADS', 'Threads');
133    this.addTexCounter('mali_hwc_TEX_RECIRC_FMISS', 'Recirc due to Full Miss');
134    this.addTexCounter('mali_hwc_TEX_RECIRC_DESC', 'Recirc due to Desc Miss');
135    this.addTexCounter('mali_hwc_TEX_RECIRC_MULTI', 'Recirc due to Multipass');
136    this.addTexCounter('mali_hwc_TEX_RECIRC_PMISS',
137        'Recirc due to Partial Cache Miss');
138    this.addTexCounter('mali_hwc_TEX_RECIRC_CONF',
139        'Recirc due to Cache Conflict');
140
141    this.addLSCCounter('mali_hwc_LSC_READ_HITS', 'Read Hits');
142    this.addLSCCounter('mali_hwc_LSC_READ_MISSES', 'Read Misses');
143    this.addLSCCounter('mali_hwc_LSC_WRITE_HITS', 'Write Hits');
144    this.addLSCCounter('mali_hwc_LSC_WRITE_MISSES', 'Write Misses');
145    this.addLSCCounter('mali_hwc_LSC_ATOMIC_HITS', 'Atomic Hits');
146    this.addLSCCounter('mali_hwc_LSC_ATOMIC_MISSES', 'Atomic Misses');
147    this.addLSCCounter('mali_hwc_LSC_LINE_FETCHES', 'Line Fetches');
148    this.addLSCCounter('mali_hwc_LSC_DIRTY_LINE', 'Dirty Lines');
149    this.addLSCCounter('mali_hwc_LSC_SNOOPS', 'Snoops');
150
151    this.addAXICounter('mali_hwc_AXI_TLB_STALL', 'Address channel stall');
152    this.addAXICounter('mali_hwc_AXI_TLB_MISS', 'Cache Miss');
153    this.addAXICounter('mali_hwc_AXI_TLB_TRANSACTION', 'Transactions');
154    this.addAXICounter('mali_hwc_LS_TLB_MISS', 'LS Cache Miss');
155    this.addAXICounter('mali_hwc_LS_TLB_HIT', 'LS Cache Hit');
156    this.addAXICounter('mali_hwc_AXI_BEATS_READ', 'Read Beats');
157    this.addAXICounter('mali_hwc_AXI_BEATS_WRITE', 'Write Beats');
158
159    this.addMMUCounter('mali_hwc_MMU_TABLE_WALK', 'Page Table Walks');
160    this.addMMUCounter('mali_hwc_MMU_REPLAY_MISS',
161        'Cache Miss from Replay Buffer');
162    this.addMMUCounter('mali_hwc_MMU_REPLAY_FULL', 'Replay Buffer Full');
163    this.addMMUCounter('mali_hwc_MMU_NEW_MISS', 'Cache Miss on New Request');
164    this.addMMUCounter('mali_hwc_MMU_HIT', 'Cache Hit');
165
166    this.addMMUCycles('mali_hwc_UTLB_STALL', 'UTLB Stalled');
167    this.addMMUCycles('mali_hwc_UTLB_REPLAY_MISS', 'UTLB Replay Miss');
168    this.addMMUCycles('mali_hwc_UTLB_REPLAY_FULL', 'UTLB Replay Full');
169    this.addMMUCycles('mali_hwc_UTLB_NEW_MISS', 'UTLB New Miss');
170    this.addMMUCycles('mali_hwc_UTLB_HIT', 'UTLB Hit');
171
172    this.addL2Counter('mali_hwc_L2_READ_BEATS', 'Read Beats');
173    this.addL2Counter('mali_hwc_L2_WRITE_BEATS', 'Write Beats');
174    this.addL2Counter('mali_hwc_L2_ANY_LOOKUP', 'Any Lookup');
175    this.addL2Counter('mali_hwc_L2_READ_LOOKUP', 'Read Lookup');
176    this.addL2Counter('mali_hwc_L2_SREAD_LOOKUP', 'Shareable Read Lookup');
177    this.addL2Counter('mali_hwc_L2_READ_REPLAY', 'Read Replayed');
178    this.addL2Counter('mali_hwc_L2_READ_SNOOP', 'Read Snoop');
179    this.addL2Counter('mali_hwc_L2_READ_HIT', 'Read Cache Hit');
180    this.addL2Counter('mali_hwc_L2_CLEAN_MISS', 'CleanUnique Miss');
181    this.addL2Counter('mali_hwc_L2_WRITE_LOOKUP', 'Write Lookup');
182    this.addL2Counter('mali_hwc_L2_SWRITE_LOOKUP', 'Shareable Write Lookup');
183    this.addL2Counter('mali_hwc_L2_WRITE_REPLAY', 'Write Replayed');
184    this.addL2Counter('mali_hwc_L2_WRITE_SNOOP', 'Write Snoop');
185    this.addL2Counter('mali_hwc_L2_WRITE_HIT', 'Write Cache Hit');
186    this.addL2Counter('mali_hwc_L2_EXT_READ_FULL', 'ExtRD with BIU Full');
187    this.addL2Counter('mali_hwc_L2_EXT_READ_HALF', 'ExtRD with BIU >1/2 Full');
188    this.addL2Counter('mali_hwc_L2_EXT_WRITE_FULL', 'ExtWR with BIU Full');
189    this.addL2Counter('mali_hwc_L2_EXT_WRITE_HALF', 'ExtWR with BIU >1/2 Full');
190
191    this.addL2Counter('mali_hwc_L2_EXT_READ', 'External Read (ExtRD)');
192    this.addL2Counter('mali_hwc_L2_EXT_READ_LINE', 'ExtRD (linefill)');
193    this.addL2Counter('mali_hwc_L2_EXT_WRITE', 'External Write (ExtWR)');
194    this.addL2Counter('mali_hwc_L2_EXT_WRITE_LINE', 'ExtWR (linefill)');
195    this.addL2Counter('mali_hwc_L2_EXT_WRITE_SMALL', 'ExtWR (burst size <64B)');
196    this.addL2Counter('mali_hwc_L2_EXT_BARRIER', 'External Barrier');
197    this.addL2Counter('mali_hwc_L2_EXT_AR_STALL', 'Address Read stalls');
198    this.addL2Counter('mali_hwc_L2_EXT_R_BUF_FULL',
199        'Response Buffer full stalls');
200    this.addL2Counter('mali_hwc_L2_EXT_RD_BUF_FULL',
201        'Read Data Buffer full stalls');
202    this.addL2Counter('mali_hwc_L2_EXT_R_RAW', 'RAW hazard stalls');
203    this.addL2Counter('mali_hwc_L2_EXT_W_STALL', 'Write Data stalls');
204    this.addL2Counter('mali_hwc_L2_EXT_W_BUF_FULL', 'Write Data Buffer full');
205    this.addL2Counter('mali_hwc_L2_EXT_R_W_HAZARD', 'WAW or WAR hazard stalls');
206    this.addL2Counter('mali_hwc_L2_TAG_HAZARD', 'Tag hazard replays');
207    this.addL2Cycles('mali_hwc_L2_SNOOP_FULL', 'Snoop buffer full');
208    this.addL2Cycles('mali_hwc_L2_REPLAY_FULL', 'Replay buffer full');
209
210    // DDK events (from X server)
211    importer.registerEventHandler('tracing_mark_write:mali_driver',
212        MaliParser.prototype.maliDDKEvent.bind(this));
213
214    this.model_ = importer.model_;
215  }
216
217  MaliParser.prototype = {
218    __proto__: Parser.prototype,
219
220    maliDDKOpenSlice: function(pid, tid, ts, func, blockinfo) {
221      var thread = this.importer.model_.getOrCreateProcess(pid)
222        .getOrCreateThread(tid);
223      var funcArgs = /^([\w\d_]*)(?:\(\))?:?\s*(.*)$/.exec(func);
224      thread.sliceGroup.beginSlice('gpu-driver', funcArgs[1], ts,
225          { 'args': funcArgs[2],
226            'blockinfo': blockinfo });
227    },
228
229    maliDDKCloseSlice: function(pid, tid, ts, args, blockinfo) {
230      var thread = this.importer.model_.getOrCreateProcess(pid)
231        .getOrCreateThread(tid);
232      if (!thread.sliceGroup.openSliceCount) {
233        // Discard unmatched ends.
234        return;
235      }
236      thread.sliceGroup.endSlice(ts);
237    },
238
239    /**
240     * Deduce the format of Mali perf events.
241     *
242     * @return {RegExp} the regular expression for parsing data when the format
243     * is recognized; otherwise null.
244     */
245    autoDetectLineRE: function(line) {
246      // Matches Mali perf events with thread info
247      var lineREWithThread =
248          /^\s*\(([\w\-]*)\)\s*(\w+):\s*([\w\\\/\.\-]*@\d*):?\s*(.*)$/;
249      if (lineREWithThread.test(line))
250        return lineREWithThread;
251
252      // Matches old-style Mali perf events
253      var lineRENoThread = /^s*()(\w+):\s*([\w\\\/.\-]*):?\s*(.*)$/;
254      if (lineRENoThread.test(line))
255        return lineRENoThread;
256      return null;
257    },
258
259    lineRE: null,
260
261    /**
262     * Parses maliDDK events and sets up state in the importer.
263     * events will come in pairs with a cros_trace_print_enter
264     * like this (line broken here for formatting):
265     *
266     * tracing_mark_write: mali_driver: (mali-012345) cros_trace_print_enter: \
267     *   gles/src/texture/mali_gles_texture_slave.c@1505: gles2_texturep_upload
268     *
269     * and a cros_trace_print_exit like this:
270     *
271     * tracing_mark_write: mali_driver: (mali-012345) cros_trace_print_exit: \
272     *   gles/src/texture/mali_gles_texture_slave.c@1505:
273     */
274    maliDDKEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
275      if (this.lineRE == null) {
276        this.lineRE = this.autoDetectLineRE(eventBase.details);
277        if (this.lineRE == null)
278          return false;
279      }
280      var maliEvent = this.lineRE.exec(eventBase.details);
281      // Old-style Mali perf events have no thread id, so make one.
282      var tid = (maliEvent[1] === '' ? 'mali' : maliEvent[1]);
283      switch (maliEvent[2]) {
284        case 'cros_trace_print_enter':
285          this.maliDDKOpenSlice(pid, tid, ts, maliEvent[4],
286              maliEvent[3]);
287          break;
288        case 'cros_trace_print_exit':
289          this.maliDDKCloseSlice(pid, tid, ts, [], maliEvent[3]);
290      }
291      return true;
292    },
293
294    /*
295     * Kernel event support.
296     */
297
298    dvfsSample: function(counterName, seriesName, ts, s) {
299      var value = parseInt(s);
300      var counter = this.model_.getOrCreateProcess(0).
301          getOrCreateCounter('DVFS', counterName);
302      if (counter.numSeries === 0) {
303        counter.addSeries(new tracing.trace_model.CounterSeries(seriesName,
304            tracing.getStringColorId(counter.name)));
305      }
306      counter.series.forEach(function(series) {
307        series.addSample(ts, value);
308      });
309    },
310
311    dvfsEventEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
312      var event = /utilization=(\d+)/.exec(eventBase.details);
313      if (!event)
314        return false;
315
316      this.dvfsSample('DVFS Utilization', 'utilization', ts, event[1]);
317      return true;
318    },
319
320    dvfsSetClockEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
321      var event = /frequency=(\d+)/.exec(eventBase.details);
322      if (!event)
323        return false;
324
325      this.dvfsSample('DVFS Frequency', 'frequency', ts, event[1]);
326      return true;
327    },
328
329    dvfsSetVoltageEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
330      var event = /voltage=(\d+)/.exec(eventBase.details);
331      if (!event)
332        return false;
333
334      this.dvfsSample('DVFS Voltage', 'voltage', ts, event[1]);
335      return true;
336    },
337
338    hwcSample: function(cat, counterName, seriesName, ts, eventBase) {
339      var event = /val=(\d+)/.exec(eventBase.details);
340      if (!event)
341        return false;
342      var value = parseInt(event[1]);
343
344      var counter = this.model_.getOrCreateProcess(0).
345          getOrCreateCounter(cat, counterName);
346      if (counter.numSeries === 0) {
347        counter.addSeries(new tracing.trace_model.CounterSeries(seriesName,
348            tracing.getStringColorId(counter.name)));
349      }
350      counter.series.forEach(function(series) {
351        series.addSample(ts, value);
352      });
353      return true;
354    },
355
356    /*
357     * Job Manager block counters.
358     */
359    jmSample: function(ctrName, seriesName, ts, eventBase) {
360      return this.hwcSample('mali:jm', 'JM: ' + ctrName, seriesName, ts,
361          eventBase);
362    },
363    addJMCounter: function(hwcEventName, hwcTitle) {
364      function handler(eventName, cpuNumber, pid, ts, eventBase) {
365        return this.jmSample(hwcTitle, 'count', ts, eventBase);
366      }
367      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
368    },
369    addJMCycles: function(hwcEventName, hwcTitle) {
370      function handler(eventName, cpuNumber, pid, ts, eventBase) {
371        return this.jmSample(hwcTitle, 'cycles', ts, eventBase);
372      }
373      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
374    },
375
376    /*
377     * Tiler block counters.
378     */
379    tilerSample: function(ctrName, seriesName, ts, eventBase) {
380      return this.hwcSample('mali:tiler', 'Tiler: ' + ctrName, seriesName,
381          ts, eventBase);
382    },
383    addTilerCounter: function(hwcEventName, hwcTitle) {
384      function handler(eventName, cpuNumber, pid, ts, eventBase) {
385        return this.tilerSample(hwcTitle, 'count', ts, eventBase);
386      }
387      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
388    },
389    addTilerCycles: function(hwcEventName, hwcTitle) {
390      function handler(eventName, cpuNumber, pid, ts, eventBase) {
391        return this.tilerSample(hwcTitle, 'cycles', ts, eventBase);
392      }
393      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
394    },
395
396    /*
397     * Fragment counters.
398     */
399    fragSample: function(ctrName, seriesName, ts, eventBase) {
400      return this.hwcSample('mali:fragment', 'Fragment: ' + ctrName,
401          seriesName, ts, eventBase);
402    },
403    addFragCounter: function(hwcEventName, hwcTitle) {
404      function handler(eventName, cpuNumber, pid, ts, eventBase) {
405        return this.fragSample(hwcTitle, 'count', ts, eventBase);
406      }
407      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
408    },
409    addFragCycles: function(hwcEventName, hwcTitle) {
410      function handler(eventName, cpuNumber, pid, ts, eventBase) {
411        return this.fragSample(hwcTitle, 'cycles', ts, eventBase);
412      }
413      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
414    },
415
416    /*
417     * Compute counters.
418     */
419    computeSample: function(ctrName, seriesName, ts, eventBase) {
420      return this.hwcSample('mali:compute', 'Compute: ' + ctrName,
421          seriesName, ts, eventBase);
422    },
423    addComputeCounter: function(hwcEventName, hwcTitle) {
424      function handler(eventName, cpuNumber, pid, ts, eventBase) {
425        return this.computeSample(hwcTitle, 'count', ts, eventBase);
426      }
427      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
428    },
429    addComputeCycles: function(hwcEventName, hwcTitle) {
430      function handler(eventName, cpuNumber, pid, ts, eventBase) {
431        return this.computeSample(hwcTitle, 'cycles', ts, eventBase);
432      }
433      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
434    },
435
436    /*
437     * Tripipe counters.
438     */
439    addTripipeCycles: function(hwcEventName, hwcTitle) {
440      function handler(eventName, cpuNumber, pid, ts, eventBase) {
441        return this.hwcSample('mali:shader', 'Tripipe: ' + hwcTitle, 'cycles',
442            ts, eventBase);
443      }
444      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
445    },
446
447    /*
448     * Arith counters.
449     */
450    arithSample: function(ctrName, seriesName, ts, eventBase) {
451      return this.hwcSample('mali:arith', 'Arith: ' + ctrName, seriesName, ts,
452          eventBase);
453    },
454    addArithCounter: function(hwcEventName, hwcTitle) {
455      function handler(eventName, cpuNumber, pid, ts, eventBase) {
456        return this.arithSample(hwcTitle, 'count', ts, eventBase);
457      }
458      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
459    },
460    addArithCycles: function(hwcEventName, hwcTitle) {
461      function handler(eventName, cpuNumber, pid, ts, eventBase) {
462        return this.arithSample(hwcTitle, 'cycles', ts, eventBase);
463      }
464      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
465    },
466
467    /*
468     * Load/Store counters.
469     */
470    addLSCounter: function(hwcEventName, hwcTitle) {
471      function handler(eventName, cpuNumber, pid, ts, eventBase) {
472        return this.hwcSample('mali:ls', 'LS: ' + hwcTitle, 'count', ts,
473            eventBase);
474      }
475      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
476    },
477
478    /*
479     * Texture counters.
480     */
481    textureSample: function(ctrName, seriesName, ts, eventBase) {
482      return this.hwcSample('mali:texture', 'Texture: ' + ctrName,
483          seriesName, ts, eventBase);
484    },
485    addTexCounter: function(hwcEventName, hwcTitle) {
486      function handler(eventName, cpuNumber, pid, ts, eventBase) {
487        return this.textureSample(hwcTitle, 'count', ts, eventBase);
488      }
489      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
490    },
491
492    /*
493     * LSC counters.
494     */
495    addLSCCounter: function(hwcEventName, hwcTitle) {
496      function handler(eventName, cpuNumber, pid, ts, eventBase) {
497        return this.hwcSample('mali:lsc', 'LSC: ' + hwcTitle, 'count', ts,
498            eventBase);
499      }
500      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
501    },
502
503    /*
504     * TLB counters.
505     */
506    addAXICounter: function(hwcEventName, hwcTitle) {
507      function handler(eventName, cpuNumber, pid, ts, eventBase) {
508        return this.hwcSample('mali:axi', 'AXI: ' + hwcTitle, 'count', ts,
509            eventBase);
510      }
511      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
512    },
513
514    /*
515     * MMU counters.
516     */
517    mmuSample: function(ctrName, seriesName, ts, eventBase) {
518      return this.hwcSample('mali:mmu', 'MMU: ' + ctrName, seriesName, ts,
519          eventBase);
520    },
521    addMMUCounter: function(hwcEventName, hwcTitle) {
522      function handler(eventName, cpuNumber, pid, ts, eventBase) {
523        return this.mmuSample(hwcTitle, 'count', ts, eventBase);
524      }
525      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
526    },
527    addMMUCycles: function(hwcEventName, hwcTitle) {
528      function handler(eventName, cpuNumber, pid, ts, eventBase) {
529        return this.mmuSample(hwcTitle, 'cycles', ts, eventBase);
530      }
531      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
532    },
533
534    /*
535     * L2 counters.
536     */
537    l2Sample: function(ctrName, seriesName, ts, eventBase) {
538      return this.hwcSample('mali:l2', 'L2: ' + ctrName, seriesName, ts,
539          eventBase);
540    },
541    addL2Counter: function(hwcEventName, hwcTitle) {
542      function handler(eventName, cpuNumber, pid, ts, eventBase) {
543        return this.l2Sample(hwcTitle, 'count', ts, eventBase);
544      }
545      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
546    },
547    addL2Cycles: function(hwcEventName, hwcTitle) {
548      function handler(eventName, cpuNumber, pid, ts, eventBase) {
549        return this.l2Sample(hwcTitle, 'cycles', ts, eventBase);
550      }
551      this.importer.registerEventHandler(hwcEventName, handler.bind(this));
552    }
553  };
554
555  Parser.registerSubtype(MaliParser);
556
557  return {
558    MaliParser: MaliParser
559  };
560});
561