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