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/**
6 * @fileoverview Parses i915 driver events in the Linux event trace format.
7 */
8base.require('linux_perf_parser');
9base.exportTo('tracing', function() {
10
11  var LinuxPerfParser = tracing.LinuxPerfParser;
12
13  /**
14   * Parses linux i915 trace events.
15   * @constructor
16   */
17  function LinuxPerfI915Parser(importer) {
18    LinuxPerfParser.call(this, importer);
19
20    importer.registerEventHandler('i915_gem_object_create',
21        LinuxPerfI915Parser.prototype.gemObjectCreateEvent.bind(this));
22    importer.registerEventHandler('i915_gem_object_bind',
23        LinuxPerfI915Parser.prototype.gemObjectBindEvent.bind(this));
24    importer.registerEventHandler('i915_gem_object_unbind',
25        LinuxPerfI915Parser.prototype.gemObjectBindEvent.bind(this));
26    importer.registerEventHandler('i915_gem_object_change_domain',
27        LinuxPerfI915Parser.prototype.gemObjectChangeDomainEvent.bind(this));
28    importer.registerEventHandler('i915_gem_object_pread',
29        LinuxPerfI915Parser.prototype.gemObjectPreadWriteEvent.bind(this));
30    importer.registerEventHandler('i915_gem_object_pwrite',
31        LinuxPerfI915Parser.prototype.gemObjectPreadWriteEvent.bind(this));
32    importer.registerEventHandler('i915_gem_object_fault',
33        LinuxPerfI915Parser.prototype.gemObjectFaultEvent.bind(this));
34    importer.registerEventHandler('i915_gem_object_clflush',
35        // NB: reuse destroy handler
36        LinuxPerfI915Parser.prototype.gemObjectDestroyEvent.bind(this));
37    importer.registerEventHandler('i915_gem_object_destroy',
38        LinuxPerfI915Parser.prototype.gemObjectDestroyEvent.bind(this));
39    importer.registerEventHandler('i915_gem_ring_dispatch',
40        LinuxPerfI915Parser.prototype.gemRingDispatchEvent.bind(this));
41    importer.registerEventHandler('i915_gem_ring_flush',
42        LinuxPerfI915Parser.prototype.gemRingFlushEvent.bind(this));
43    importer.registerEventHandler('i915_gem_request',
44        LinuxPerfI915Parser.prototype.gemRequestEvent.bind(this));
45    importer.registerEventHandler('i915_gem_request_add',
46        LinuxPerfI915Parser.prototype.gemRequestEvent.bind(this));
47    importer.registerEventHandler('i915_gem_request_complete',
48        LinuxPerfI915Parser.prototype.gemRequestEvent.bind(this));
49    importer.registerEventHandler('i915_gem_request_retire',
50        LinuxPerfI915Parser.prototype.gemRequestEvent.bind(this));
51    importer.registerEventHandler('i915_gem_request_wait_begin',
52        LinuxPerfI915Parser.prototype.gemRequestEvent.bind(this));
53    importer.registerEventHandler('i915_gem_request_wait_end',
54        LinuxPerfI915Parser.prototype.gemRequestEvent.bind(this));
55    importer.registerEventHandler('i915_gem_ring_wait_begin',
56        LinuxPerfI915Parser.prototype.gemRingWaitEvent.bind(this));
57    importer.registerEventHandler('i915_gem_ring_wait_end',
58        LinuxPerfI915Parser.prototype.gemRingWaitEvent.bind(this));
59    importer.registerEventHandler('i915_reg_rw',
60        LinuxPerfI915Parser.prototype.regRWEvent.bind(this));
61    importer.registerEventHandler('i915_flip_request',
62        LinuxPerfI915Parser.prototype.flipEvent.bind(this));
63    importer.registerEventHandler('i915_flip_complete',
64        LinuxPerfI915Parser.prototype.flipEvent.bind(this));
65  }
66
67  LinuxPerfI915Parser.prototype = {
68    __proto__: LinuxPerfParser.prototype,
69
70    i915FlipOpenSlice: function(ts, obj, plane) {
71      // use i915_flip_obj_plane?
72      var kthread = this.importer.getOrCreatePseudoThread('i915_flip');
73      kthread.openSliceTS = ts;
74      kthread.openSlice = 'flip:' + obj + '/' + plane;
75    },
76
77    i915FlipCloseSlice: function(ts, args) {
78      var kthread = this.importer.getOrCreatePseudoThread('i915_flip');
79      if (kthread.openSlice) {
80        var slice = new tracing.TimelineSlice('', kthread.openSlice,
81            tracing.getStringColorId(kthread.openSlice),
82            kthread.openSliceTS,
83            args,
84            ts - kthread.openSliceTS);
85
86        kthread.thread.pushSlice(slice);
87      }
88      kthread.openSlice = undefined;
89    },
90
91    i915GemObjectSlice: function(ts, eventName, obj, args) {
92      var kthread = this.importer.getOrCreatePseudoThread('i915_gem');
93      kthread.openSlice = eventName + ':' + obj;
94      var slice = new tracing.TimelineSlice('', kthread.openSlice,
95          tracing.getStringColorId(kthread.openSlice), ts, args, 0);
96
97      kthread.thread.pushSlice(slice);
98    },
99
100    i915GemRingSlice: function(ts, eventName, dev, ring, args) {
101      var kthread = this.importer.getOrCreatePseudoThread('i915_gem_ring');
102      kthread.openSlice = eventName + ':' + dev + '.' + ring;
103      var slice = new tracing.TimelineSlice('', kthread.openSlice,
104          tracing.getStringColorId(kthread.openSlice), ts, args, 0);
105
106      kthread.thread.pushSlice(slice);
107    },
108
109    i915RegSlice: function(ts, eventName, reg, args) {
110      var kthread = this.importer.getOrCreatePseudoThread('i915_reg');
111      kthread.openSlice = eventName + ':' + reg;
112      var slice = new tracing.TimelineSlice('', kthread.openSlice,
113          tracing.getStringColorId(kthread.openSlice), ts, args, 0);
114
115      kthread.thread.pushSlice(slice);
116    },
117
118    /**
119     * Parses i915 driver events and sets up state in the importer.
120     */
121    gemObjectCreateEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
122      var event = /obj=(\w+), size=(\d+)/.exec(eventBase[5]);
123      if (!event)
124        return false;
125
126      var obj = event[1];
127      var size = parseInt(event[2]);
128      this.i915GemObjectSlice(ts, eventName, obj,
129          {
130            obj: obj,
131            size: size
132          });
133      return true;
134    },
135
136    gemObjectBindEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
137      // TODO(sleffler) mappable
138      var event = /obj=(\w+), offset=(\w+), size=(\d+)/.exec(eventBase[5]);
139      if (!event)
140        return false;
141
142      var obj = event[1];
143      var offset = event[2];
144      var size = parseInt(event[3]);
145      this.i915ObjectGemSlice(ts, eventName + ':' + obj,
146          {
147            obj: obj,
148            offset: offset,
149            size: size
150          });
151      return true;
152    },
153
154    gemObjectChangeDomainEvent: function(eventName, cpuNumber, pid, ts,
155                                         eventBase) {
156      var event = /obj=(\w+), read=(\w+=>\w+), write=(\w+=>\w+)/
157          .exec(eventBase[5]);
158      if (!event)
159        return false;
160
161      var obj = event[1];
162      var read = event[2];
163      var write = event[3];
164      this.i915GemObjectSlice(ts, eventName, obj,
165          {
166            obj: obj,
167            read: read,
168            write: write
169          });
170      return true;
171    },
172
173    gemObjectPreadWriteEvent: function(eventName, cpuNumber, pid, ts,
174                                       eventBase) {
175      var event = /obj=(\w+), offset=(\d+), len=(\d+)/.exec(eventBase[5]);
176      if (!event)
177        return false;
178
179      var obj = event[1];
180      var offset = parseInt(event[2]);
181      var len = parseInt(event[3]);
182      this.i915GemObjectSlice(ts, eventName, obj,
183          {
184            obj: obj,
185            offset: offset,
186            len: len
187          });
188      return true;
189    },
190
191    gemObjectFaultEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
192      // TODO(sleffler) writable
193      var event = /obj=(\w+), (\w+) index=(\d+)/.exec(eventBase[5]);
194      if (!event)
195        return false;
196
197      var obj = event[1];
198      var type = event[2];
199      var index = parseInt(event[3]);
200      this.i915GemObjectSlice(ts, eventName, obj,
201          {
202            obj: obj,
203            type: type,
204            index: index
205          });
206      return true;
207    },
208
209    gemObjectDestroyEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
210      var event = /obj=(\w+)/.exec(eventBase[5]);
211      if (!event)
212        return false;
213
214      var obj = event[1];
215      this.i915GemObjectSlice(ts, eventName, obj,
216          {
217            obj: obj
218          });
219      return true;
220    },
221
222    gemRingDispatchEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
223      var event = /dev=(\d+), ring=(\d+), seqno=(\d+)/.exec(eventBase[5]);
224      if (!event)
225        return false;
226
227      var dev = parseInt(event[1]);
228      var ring = parseInt(event[2]);
229      var seqno = parseInt(event[3]);
230      this.i915GemRingSlice(ts, eventName, dev, ring,
231          {
232            dev: dev,
233            ring: ring,
234            seqno: seqno
235          });
236      return true;
237    },
238
239    gemRingFlushEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
240      var event = /dev=(\d+), ring=(\w+), invalidate=(\w+), flush=(\w+)/
241          .exec(eventBase[5]);
242      if (!event)
243        return false;
244
245      var dev = parseInt(event[1]);
246      var ring = parseInt(event[2]);
247      var invalidate = event[3];
248      var flush = event[4];
249      this.i915GemRingSlice(ts, eventName, dev, ring,
250          {
251            dev: dev,
252            ring: ring,
253            invalidate: invalidate,
254            flush: flush
255          });
256      return true;
257    },
258
259    gemRequestEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
260      var event = /dev=(\d+), ring=(\d+), seqno=(\d+)/.exec(eventBase[5]);
261      if (!event)
262        return false;
263
264      var dev = parseInt(event[1]);
265      var ring = parseInt(event[2]);
266      var seqno = parseInt(event[3]);
267      this.i915GemRingSlice(ts, eventName, dev, ring,
268          {
269            dev: dev,
270            ring: ring,
271            seqno: seqno
272          });
273      return true;
274    },
275
276    gemRingWaitEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
277      var event = /dev=(\d+), ring=(\d+)/.exec(eventBase[5]);
278      if (!event)
279        return false;
280
281      var dev = parseInt(event[1]);
282      var ring = parseInt(event[2]);
283      this.i915GemRingSlice(ts, eventName, dev, ring,
284          {
285            dev: dev,
286            ring: ring
287          });
288      return true;
289    },
290
291    regRWEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
292      var event = /(\w+) reg=(\w+), len=(\d+), val=(\(\w+, \w+\))/
293          .exec(eventBase[5]);
294      if (!event)
295        return false;
296
297      var rw = event[1];
298      var reg = event[2];
299      var len = event[3];
300      var data = event[3];
301      this.i915RegSlice(ts, rw, reg,
302          {
303            rw: rw,
304            reg: reg,
305            len: len,
306            data: data
307          });
308      return true;
309    },
310
311    flipEvent: function(eventName, cpuNumber, pid, ts, eventBase) {
312      var event = /plane=(\d+), obj=(\w+)/.exec(eventBase[5]);
313      if (!event)
314        return false;
315
316      var plane = parseInt(event[1]);
317      var obj = event[2];
318      if (eventName == 'i915_flip_request')
319        this.i915FlipOpenSlice(ts, obj, plane);
320      else
321        this.i915FlipCloseSlice(ts,
322            {
323              obj: obj,
324              plane: plane
325            });
326      return true;
327    }
328  };
329
330  LinuxPerfParser.registerSubtype(LinuxPerfI915Parser);
331
332  return {
333    LinuxPerfI915Parser: LinuxPerfI915Parser
334  };
335});
336