Home | History | Annotate | Download | only in linux_perf
      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  */
     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 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