1import copy
2import json
3import re
4import struct
5
6import espytrace.apptrace as apptrace
7
8SYSVIEW_EVTID_NOP                 = 0  # Dummy packet.
9SYSVIEW_EVTID_OVERFLOW            = 1
10SYSVIEW_EVTID_ISR_ENTER           = 2
11SYSVIEW_EVTID_ISR_EXIT            = 3
12SYSVIEW_EVTID_TASK_START_EXEC     = 4
13SYSVIEW_EVTID_TASK_STOP_EXEC      = 5
14SYSVIEW_EVTID_TASK_START_READY    = 6
15SYSVIEW_EVTID_TASK_STOP_READY     = 7
16SYSVIEW_EVTID_TASK_CREATE         = 8
17SYSVIEW_EVTID_TASK_INFO           = 9
18SYSVIEW_EVTID_TRACE_START         = 10
19SYSVIEW_EVTID_TRACE_STOP          = 11
20SYSVIEW_EVTID_SYSTIME_CYCLES      = 12
21SYSVIEW_EVTID_SYSTIME_US          = 13
22SYSVIEW_EVTID_SYSDESC             = 14
23SYSVIEW_EVTID_USER_START          = 15
24SYSVIEW_EVTID_USER_STOP           = 16
25SYSVIEW_EVTID_IDLE                = 17
26SYSVIEW_EVTID_ISR_TO_SCHEDULER    = 18
27SYSVIEW_EVTID_TIMER_ENTER         = 19
28SYSVIEW_EVTID_TIMER_EXIT          = 20
29SYSVIEW_EVTID_STACK_INFO          = 21
30SYSVIEW_EVTID_MODULEDESC          = 22
31SYSVIEW_EVTID_INIT                = 24
32SYSVIEW_EVENT_ID_PREDEF_LEN_MAX   = SYSVIEW_EVTID_INIT
33SYSVIEW_EVTID_NAME_RESOURCE       = 25
34SYSVIEW_EVTID_PRINT_FORMATTED     = 26
35SYSVIEW_EVTID_NUMMODULES          = 27
36SYSVIEW_EVENT_ID_PREDEF_MAX       = SYSVIEW_EVTID_NUMMODULES
37
38SYSVIEW_EVENT_ID_MAX             = 200
39
40SYSVIEW_MODULE_EVENT_OFFSET      = 512
41
42SYSVIEW_SYNC_LEN                  = 10
43
44_sysview_events_map = {
45    'SYS_NOP': SYSVIEW_EVTID_NOP,
46    'SYS_OVERFLOW': SYSVIEW_EVTID_OVERFLOW,
47    'SYS_ISR_ENTER': SYSVIEW_EVTID_ISR_ENTER,
48    'SYS_ISR_EXIT': SYSVIEW_EVTID_ISR_EXIT,
49    'SYS_TASK_START_EXEC': SYSVIEW_EVTID_TASK_START_EXEC,
50    'SYS_TASK_STOP_EXEC': SYSVIEW_EVTID_TASK_STOP_EXEC,
51    'SYS_TASK_START_READY': SYSVIEW_EVTID_TASK_START_READY,
52    'SYS_TASK_STOP_READY': SYSVIEW_EVTID_TASK_STOP_READY,
53    'SYS_TASK_CREATE': SYSVIEW_EVTID_TASK_CREATE,
54    'SYS_TASK_INFO': SYSVIEW_EVTID_TASK_INFO,
55    'SYS_TRACE_START': SYSVIEW_EVTID_TRACE_START,
56    'SYS_TRACE_STOP': SYSVIEW_EVTID_TRACE_STOP,
57    'SYS_SYSTIME_CYCLES': SYSVIEW_EVTID_SYSTIME_CYCLES,
58    'SYS_SYSTIME_US': SYSVIEW_EVTID_SYSTIME_US,
59    'SYS_SYSDESC': SYSVIEW_EVTID_SYSDESC,
60    'SYS_USER_START': SYSVIEW_EVTID_USER_START,
61    'SYS_USER_STOP': SYSVIEW_EVTID_USER_STOP,
62    'SYS_IDLE': SYSVIEW_EVTID_IDLE,
63    'SYS_ISR_TO_SCHEDULER': SYSVIEW_EVTID_ISR_TO_SCHEDULER,
64    'SYS_TIMER_ENTER': SYSVIEW_EVTID_TIMER_ENTER,
65    'SYS_TIMER_EXIT': SYSVIEW_EVTID_TIMER_EXIT,
66    'SYS_STACK_INFO': SYSVIEW_EVTID_STACK_INFO,
67    'SYS_MODULEDESC': SYSVIEW_EVTID_INIT,
68    'SYS_INIT': SYSVIEW_EVTID_INIT,
69    'SYS_NAME_RESOURCE': SYSVIEW_EVTID_NAME_RESOURCE,
70    'SYS_PRINT_FORMATTED': SYSVIEW_EVTID_PRINT_FORMATTED,
71    'SYS_NUMMODULES': SYSVIEW_EVTID_NUMMODULES
72}
73
74_os_events_map = {}
75
76
77def parse_trace(reader, parser, os_evt_map_file=''):
78    """
79    Parses trace.
80
81    Parameters
82    ----------
83    reader : apptrace.Reader
84        Trace reader object.
85    parser : SysViewTraceDataParser
86        Top level parser object.
87    os_evt_map_file : string
88        Path to file containg events format description.
89    """
90    global _os_events_map
91    # parse OS events formats file
92    _os_events_map = _read_events_map(os_evt_map_file)
93    parser.esp_ext = ('; ESP_Extension\n' in _read_file_header(reader))
94    _read_init_seq(reader)
95    while True:
96        event = parser.read_event(reader, _os_events_map)
97        parser.on_new_event(event)
98
99
100def _read_events_map(os_evt_map_file):
101    """
102    Reads SystemView events format description from file.
103
104    Parameters
105    ----------
106    os_evt_map_file : string
107        Path to file containg events format description.
108
109    Returns
110    -------
111    dict
112        a dict with event IDs as keys and values as tuples containg event name and a list of parameters.
113    """
114    os_evt_map = {}
115    with open(os_evt_map_file) as f:
116        for line in f:
117            comps = line.split()
118            if len(comps) < 2:
119                continue
120            params = []
121            if len(comps) > 2:
122                for p in comps[2:]:
123                    sp = p.split('=')
124                    if sp[1].startswith('%'):
125                        sp[1] = sp[1][1:]
126                    if sp[1] == 'u':
127                        params.append(SysViewEventParamSimple(sp[0], _decode_u32))
128                    elif sp[1] == 's':
129                        params.append(SysViewEventParamSimple(sp[0], _decode_str))
130                    elif sp[1] == 't' or sp[1] == 'T' or sp[1] == 'I' or sp[1] == 'p':
131                        # TODO: handle shrinked task/queue ID and addresses
132                        params.append(SysViewEventParamSimple(sp[0], _decode_u32))
133            os_evt_map[int(comps[0])] = (comps[1], params)
134    return os_evt_map
135
136
137def _read_file_header(reader):
138    """
139    Reads SystemView trace file header.
140
141    Parameters
142    ----------
143    reader : apptrace.Reader
144        Trace reader object.
145
146    Returns
147    -------
148    list
149        a list of header lines.
150    """
151    empty_count = 0
152    lines = []
153    while empty_count < 2:
154        lines.append(reader.readline(linesep='\n'))
155        if lines[-1] == ';\n':
156            empty_count += 1
157    return lines
158
159
160def _read_init_seq(reader):
161    """
162    Reads SystemView trace initial synchronisation sequence of bytes.
163
164    Parameters
165    ----------
166    reader : apptrace.Reader
167        Trace reader object.
168
169    Raises
170    -------
171    SysViewTraceParseError
172        If sync sequence is broken.
173    """
174    SYNC_SEQ_FMT = '<%dB' % SYSVIEW_SYNC_LEN
175    sync_bytes = struct.unpack(SYNC_SEQ_FMT, reader.read(struct.calcsize(SYNC_SEQ_FMT)))
176    for b in sync_bytes:
177        if b != 0:
178            raise SysViewTraceParseError('Invalid sync sequense!')
179
180
181def _decode_u32(reader):
182    """
183    Reads and decodes unsigned 32-bit integer.
184
185    Parameters
186    ----------
187    reader : apptrace.Reader
188        Trace reader object.
189
190    Returns
191    -------
192    tuple
193        a tuple containg number of read bytes and decoded value.
194    """
195    sz = 0
196    val = 0
197    while True:
198        b, = struct.unpack('<B', reader.read(1))
199        if b & 0x80:
200            val |= (b & 0x7F) << (7 * sz)
201        else:
202            val |= b << (7 * sz)
203            break
204        sz += 1
205    return (sz + 1,val)
206
207
208def _decode_id(reader):
209    """
210    Reads and decodes ID (task ID, queue handle, semaphore handle etc.).
211
212    Parameters
213    ----------
214    reader : apptrace.Reader
215        Trace reader object.
216
217    Returns
218    -------
219    tuple
220        a tuple containg number of read bytes and decoded value.
221    """
222    return _decode_u32(reader)
223
224
225def _decode_u64(reader):
226    """
227    Reads and decodes unsigned 64-bit integer.
228
229    Parameters
230    ----------
231    reader : apptrace.Reader
232        Trace reader object.
233
234    Returns
235    -------
236    tuple
237        a tuple containg number of read bytes and decoded value.
238    """
239    sz,val = _decode_u32(reader)
240    sz2,high = _decode_u32(reader)
241    sz += sz2
242    return sz,(val | (high << 32))
243
244
245def _decode_str(reader):
246    """
247    Reads and decodes string.
248
249    Parameters
250    ----------
251    reader : apptrace.Reader
252        Trace reader object.
253
254    Returns
255    -------
256    tuple
257        a tuple containg number of read bytes and decoded value.
258    """
259    sz = 0
260    val = ''
261    sz, = struct.unpack('<B', reader.read(1))
262    if sz == 0xFF:
263        buf = struct.unpack('<2B', reader.read(2))
264        sz = (buf[1] << 8) | buf[0]
265    val, = struct.unpack('<%ds' % sz, reader.read(sz))
266    val = val.decode('utf-8')
267    if sz < 0xFF:
268        return (sz + 1,val)  # one extra byte for length
269    return (sz + 3,val)  # 3 extra bytes for length
270
271
272def _decode_plen(reader):
273    """
274    Reads and decodes event's payload length.
275
276    Parameters
277    ----------
278    reader : apptrace.Reader
279        Trace reader object.
280
281    Returns
282    -------
283    int
284        decoded value.
285    """
286    plen = 0
287    b0, = struct.unpack('<B', reader.read(1))
288    if b0 & 0x80:
289        b1, = struct.unpack('<B', reader.read(1))
290        plen = b1  # higher part
291        plen = (plen << 7) | (b0 & ~0x80)  # lower 7 bits
292    else:
293        plen = b0
294    return plen
295
296
297class SysViewTraceParseError(apptrace.ParseError):
298    """
299    SystemView parse error exception.
300    """
301    pass
302
303
304class SysViewEvent(apptrace.TraceEvent):
305    """
306        Generic SystemView event class. This is a base class for all events.
307    """
308    def __init__(self, evt_id, core_id, reader, events_fmt_map=None):
309        """
310            Constructor. Reads and optionally decodes event.
311
312            Parameters
313            ----------
314            evt_id : int
315                Event ID.
316            reader : apptrace.Reader
317                Trace reader object.
318            core_id : int
319                Core ID event has been generated on.
320            events_fmt_map : dict
321                see return value of _read_events_map()
322        """
323        apptrace.TraceEvent.__init__(self, 'SysViewEvent', core_id, evt_id)
324        self.plen = 0
325        if self.id >= SYSVIEW_EVENT_ID_PREDEF_LEN_MAX:
326            self.plen = _decode_plen(reader)
327        if events_fmt_map:
328            self._read_payload(reader, events_fmt_map)
329        else:
330            reader.forward(self.plen)
331        _,self.ts = _decode_u32(reader)
332
333    def _read_payload(self, reader, events_fmt_map):
334        """
335            Reads event's payload and populates its parameters dictionary.
336
337            Parameters
338            ----------
339            reader : apptrace.Reader
340                Trace reader object.
341            events_fmt_map : dict
342                see return value of _read_events_map()
343
344            Raises
345            -------
346            SysViewTraceParseError
347                if event has unknown or invalid format.
348        """
349        if self.id not in events_fmt_map:
350            raise SysViewTraceParseError('Unknown event ID %d!' % self.id)
351        self.name = events_fmt_map[self.id][0]
352        evt_params_templates = events_fmt_map[self.id][1]
353        params_len = 0
354        for i in range(len(evt_params_templates)):
355            event_param = copy.deepcopy(evt_params_templates[i])
356            try:
357                cur_pos = reader.get_pos()
358                sz,param_val = event_param.decode(reader, self.plen - params_len)
359            except Exception as e:
360                raise SysViewTraceParseError('Failed to decode event {}({:d}) {:d} param @ 0x{:x}! {}'.format(self.name, self.id, self.plen, cur_pos, e))
361            event_param.idx = i
362            event_param.value = param_val
363            self.params[event_param.name] = event_param
364            params_len += sz
365        if self.id >= SYSVIEW_EVENT_ID_PREDEF_LEN_MAX and self.plen != params_len:
366            raise SysViewTraceParseError('Invalid event {}({:d}) payload len {:d}! Must be {:d}.'.format(self.name, self.id, self.plen, params_len))
367
368    def __str__(self):
369        params = ''
370        for param in sorted(self.params.values(), key=lambda x: x.idx):
371            params += '{}, '.format(param)
372        if len(params):
373            params = params[:-2]  # remove trailing ', '
374        return '{:.9f} - core[{:d}].{}({:d}), plen {:d}: [{}]'.format(self.ts, self.core_id, self.name, self.id, self.plen, params)
375
376
377class SysViewEventParam:
378    """
379        Abstract base SystemView event's parameter class. This is a base class for all event's parameters.
380    """
381    def __init__(self, name, decode_func):
382        """
383            Constructor.
384
385            Parameters
386            ----------
387            name : string
388                Event parameter name.
389            decode_func : callable object
390                Parameter decoding function.
391        """
392        self.name = name
393        self.decode_func = decode_func
394        self.value = None
395        # positional index, used for sorting parameters before printing to make them looking as they appear in the event
396        self.idx = 0
397
398    def decode(self, reader, max_sz):
399        """
400            Reads and decodes events parameter.
401
402            Parameters
403            ----------
404            reader : apptrace.Reader
405                Trace reader object.
406            max_sz : int
407                Maximum number of bytes to read.
408
409            Returns
410            -------
411            tuple
412                a tuple containg number of read bytes and decoded value.
413        """
414        pass
415
416    def __str__(self):
417        return '{}: {}'.format(self.name, self.value)
418
419    def to_jsonable(self):
420        return {self.name: self.value}
421
422
423class SysViewEventParamSimple(SysViewEventParam):
424    """
425        Simple SystemView event's parameter class.
426    """
427    def decode(self, reader, max_sz):
428        """
429            see SysViewEventParam.decode()
430        """
431        return self.decode_func(reader)
432
433
434class SysViewEventParamArray(SysViewEventParamSimple):
435    """
436        Array SystemView event's parameter class.
437    """
438    def __init__(self, name, decode_func, size=-1):
439        """
440            Constructor.
441
442            Parameters
443            ----------
444            name : string
445                see SysViewEventParam.__init__()
446            decode_func : callable object
447                see SysViewEventParam.__init__()
448            size : int
449                Array's size. If -1 decode() will try to read all bytes from reader.
450        """
451        SysViewEventParamSimple.__init__(self, name, decode_func)
452        self.arr_size = size
453
454    def decode(self, reader, max_sz):
455        """
456            see SysViewEventParam.decode()
457        """
458        tottal_sz = 0
459        vals = []
460        i = 0
461        while tottal_sz < max_sz:
462            sz,val = self.decode_func(reader)
463            vals.append(val)
464            tottal_sz += sz
465            i += 1
466            if self.arr_size != -1 and i == self.arr_size:
467                break
468        return tottal_sz,vals
469
470
471class SysViewPredefinedEvent(SysViewEvent):
472    """
473        Pre-defined SystemView events class.
474    """
475    _predef_events_fmt = {
476        SYSVIEW_EVTID_NOP:              ('svNop', []),
477        SYSVIEW_EVTID_OVERFLOW:         ('svOverflow', [SysViewEventParamSimple('drop_cnt', _decode_u32)]),
478        SYSVIEW_EVTID_ISR_ENTER:        ('svIsrEnter', [SysViewEventParamSimple('irq_num', _decode_u32)]),
479        SYSVIEW_EVTID_ISR_EXIT:         ('svIsrExit', []),
480        SYSVIEW_EVTID_TASK_START_EXEC:  ('svTaskStartExec', [SysViewEventParamSimple('tid', _decode_id)]),
481        SYSVIEW_EVTID_TASK_STOP_EXEC:   ('svTaskStopExec', []),
482        SYSVIEW_EVTID_TASK_START_READY: ('svTaskStartReady', [SysViewEventParamSimple('tid', _decode_id)]),
483        SYSVIEW_EVTID_TASK_STOP_READY:  ('svTaskStopReady', [SysViewEventParamSimple('tid', _decode_id),
484                                                             SysViewEventParamSimple('cause', _decode_u32)]),
485        SYSVIEW_EVTID_TASK_CREATE:      ('svTaskCreate', [SysViewEventParamSimple('tid', _decode_id)]),
486        SYSVIEW_EVTID_TASK_INFO:        ('svTaskInfo', [SysViewEventParamSimple('tid', _decode_id),
487                                                        SysViewEventParamSimple('prio', _decode_u32),
488                                                        SysViewEventParamSimple('name', _decode_str)]),
489        SYSVIEW_EVTID_TRACE_START:      ('svTraceStart', []),
490        SYSVIEW_EVTID_TRACE_STOP:       ('svTraceStop', []),
491        SYSVIEW_EVTID_SYSTIME_CYCLES:   ('svSysTimeCycles', [SysViewEventParamSimple('cycles', _decode_u32)]),
492        SYSVIEW_EVTID_SYSTIME_US:       ('svSysTimeUs', [SysViewEventParamSimple('time', _decode_u64)]),
493        SYSVIEW_EVTID_SYSDESC:          ('svSysDesc', [SysViewEventParamSimple('desc', _decode_str)]),
494        SYSVIEW_EVTID_USER_START:       ('svUserStart', [SysViewEventParamSimple('user_id', _decode_u32)]),
495        SYSVIEW_EVTID_USER_STOP:        ('svUserStart', [SysViewEventParamSimple('user_id', _decode_u32)]),
496        SYSVIEW_EVTID_IDLE:             ('svIdle', []),
497        SYSVIEW_EVTID_ISR_TO_SCHEDULER: ('svExitIsrToScheduler', []),
498        SYSVIEW_EVTID_TIMER_ENTER:      ('svTimerEnter', [SysViewEventParamSimple('tim_id', _decode_u32)]),
499        SYSVIEW_EVTID_TIMER_EXIT:       ('svTimerExit', []),
500        SYSVIEW_EVTID_STACK_INFO:       ('svStackInfo', [SysViewEventParamSimple('tid', _decode_id),
501                                                         SysViewEventParamSimple('base', _decode_u32),
502                                                         SysViewEventParamSimple('sz', _decode_u32),
503                                                         SysViewEventParamSimple('unused', _decode_u32)]),
504        SYSVIEW_EVTID_MODULEDESC:       ('svModuleDesc', [SysViewEventParamSimple('mod_id', _decode_u32),
505                                                          SysViewEventParamSimple('evt_off', _decode_u32),
506                                                          SysViewEventParamSimple('desc', _decode_str)]),
507        SYSVIEW_EVTID_INIT:             ('svInit', [SysViewEventParamSimple('sys_freq', _decode_u32),
508                                                    SysViewEventParamSimple('cpu_freq', _decode_u32),
509                                                    SysViewEventParamSimple('ram_base', _decode_u32),
510                                                    SysViewEventParamSimple('id_shift', _decode_u32)]),
511        SYSVIEW_EVTID_NAME_RESOURCE:    ('svNameResource', [SysViewEventParamSimple('res_id', _decode_u32),
512                                                            SysViewEventParamSimple('name', _decode_str)]),
513        SYSVIEW_EVTID_PRINT_FORMATTED:  ('svPrint', [SysViewEventParamSimple('msg', _decode_str),
514                                                     SysViewEventParamSimple('lvl', _decode_u32),
515                                                     SysViewEventParamSimple('unused', _decode_u32)]),
516        SYSVIEW_EVTID_NUMMODULES:       ('svNumModules', [SysViewEventParamSimple('mod_cnt', _decode_u32)]),
517    }
518
519    def __init__(self, evt_id, core_id, reader):
520        """
521            see SysViewEvent.__init__()
522        """
523        SysViewEvent.__init__(self, evt_id, core_id, reader, self._predef_events_fmt)
524        # self.name = 'SysViewPredefinedEvent'
525
526
527class SysViewOSEvent(SysViewEvent):
528    """
529        OS related SystemView events class.
530    """
531    def __init__(self, evt_id, core_id, reader, events_fmt_map):
532        """
533            see SysViewEvent.__init__()
534        """
535        SysViewEvent.__init__(self, evt_id, core_id, reader, events_fmt_map)
536        # self.name = 'SysViewOSEvent'
537
538
539class SysViewHeapEvent(SysViewEvent):
540    """
541        Heap related SystemView events class.
542
543        Attributes
544        ----------
545        events_fmt : dict
546            see return value of _read_events_map()
547    """
548    events_fmt = {
549        0:       ('esp_sysview_heap_trace_alloc', [SysViewEventParamSimple('addr', _decode_u32),
550                                                   SysViewEventParamSimple('size', _decode_u32),
551                                                   SysViewEventParamArray('callers', _decode_u32)]),
552        1:       ('esp_sysview_heap_trace_free', [SysViewEventParamSimple('addr', _decode_u32),
553                                                  SysViewEventParamArray('callers', _decode_u32)]),
554    }
555
556    def __init__(self, evt_id, core_id, events_off, reader):
557        """
558            Constructor. Reads and optionally decodes event.
559
560            Parameters
561            ----------
562            evt_id : int
563                see SysViewEvent.__init__()
564            events_off : int
565                Offset for heap events IDs. Greater or equal to SYSVIEW_MODULE_EVENT_OFFSET.
566            reader : apptrace.Reader
567                see SysViewEvent.__init__()
568            core_id : int
569                see SysViewEvent.__init__()
570        """
571        cur_events_map = {}
572        for id in self.events_fmt:
573            cur_events_map[events_off + id] = self.events_fmt[id]
574        SysViewEvent.__init__(self, evt_id, core_id, reader, cur_events_map)
575        # self.name = 'SysViewHeapEvent'
576
577
578class SysViewTraceDataParser(apptrace.TraceDataProcessor):
579    """
580        Base SystemView trace data parser class.
581
582        Attributes
583        ----------
584        STREAMID_SYS : int
585            system events stream ID. Reserved for internal uses.
586        STREAMID_LOG : int
587            log events stream ID.
588        STREAMID_HEAP : int
589            heap events stream ID.
590    """
591    STREAMID_SYS = -1
592    STREAMID_LOG = 0
593    STREAMID_HEAP = 1
594
595    def __init__(self, print_events=False, core_id=0):
596        """
597            Constructor.
598
599            Parameters
600            ----------
601            print_events : bool
602                see apptrace.TraceDataProcessor.__init__()
603            core_id : int
604                id of the core this parser object relates to.
605        """
606        apptrace.TraceDataProcessor.__init__(self, print_events=print_events, keep_all_events=True)
607        self.sys_info = None
608        self._last_ts = 0
609        self.irqs_info = {}
610        self.tasks_info = {}
611        self.core_id = core_id
612        self.esp_ext = False
613
614    def _parse_irq_desc(self, desc):
615        """
616            Parses IRQ description.
617
618            Parameters
619            ----------
620            desc : string
621                IRQ description string.
622
623            Returns
624            -------
625            tuple
626                a tuple with IRQ number and name or None on error.
627        """
628        m = re.match('I#([0-9]+)=(.+)', desc)
629        if m:
630            return m.group(2),m.group(1)
631        return None
632
633    def _update_ts(self, ts):
634        """
635            Calculates real event timestamp.
636
637            Parameters
638            ----------
639            ts : int
640                Event timestamp offset.
641
642            Returns
643            -------
644            float
645                real event timestamp.
646        """
647        self._last_ts += ts
648        return float(self._last_ts) / self.sys_info.params['sys_freq'].value
649
650    def read_extension_event(self, evt_id, core_id, reader):
651        """
652            Reads extension event.
653            Default implementation which just reads out event.
654
655            Parameters
656            ----------
657            evt_id : int
658                Event ID.
659            reader : apptrace.Reader
660                Trace reader object.
661
662            Returns
663            -------
664            SysViewEvent
665                if this is top level parser returns object for generic event,
666                otherwise returns None indicating to the calling top level parser
667                that extension event are not supported.
668        """
669        if self.root_proc == self:
670            # by default just read out and skip unknown event
671            return SysViewEvent(evt_id, core_id, reader)
672        return None  # let decide to root parser
673
674    @staticmethod
675    def _decode_core_id(high_b):
676        if high_b & (1 << 6):
677            core_id = 1
678            high_b &= ~(1 << 6)
679        else:
680            core_id = 0
681        return high_b,core_id
682
683    def read_event(self, reader, os_evt_map):
684        """
685            Reads pre-defined or OS-related event.
686
687            Parameters
688            ----------
689            reader : apptrace.Reader
690                Trace reader object.
691            os_evt_map : dict
692                see return value of _read_events_map()
693
694            Returns
695            -------
696            SysViewEvent
697                pre-defined, OS-related or extension event object.
698        """
699        evt_hdr, = struct.unpack('<B', reader.read(1))
700        # read ID and core num
701        evt_id = 0
702        if evt_hdr & 0x80:
703            # evt_id (2 bytes)
704            b, = struct.unpack('<B', reader.read(1))
705            # higher part
706            if self.esp_ext:
707                evt_id,core_id = self._decode_core_id(b)
708            else:
709                evt_id = b
710                core_id = self.core_id
711            evt_id = (evt_id << 7) | (evt_hdr & ~0x80)  # lower 7 bits
712        else:
713            # evt_id (1 byte)
714            if self.esp_ext:
715                evt_id,core_id = self._decode_core_id(evt_hdr)
716            else:
717                evt_id = evt_hdr
718                core_id = self.core_id
719        if evt_id <= SYSVIEW_EVENT_ID_PREDEF_MAX:
720            return SysViewPredefinedEvent(evt_id, core_id, reader)
721        elif evt_id < SYSVIEW_MODULE_EVENT_OFFSET:
722            return SysViewOSEvent(evt_id, core_id, reader, os_evt_map)
723        else:
724            return self.read_extension_event(evt_id, core_id, reader)
725
726    def event_supported(self, event):
727        return False
728
729    def on_new_event(self, event):
730        """
731            Does essential processing of event. Must be called for every read event.
732            Assigns real timestamp to event. Updates global system info: system description,
733            mapping of tasks IDs to names and IRQ names to numbers.
734
735            Parameters
736            ----------
737            event : SysViewEvent
738                Event object.
739        """
740        if event.id == SYSVIEW_EVTID_TRACE_START:
741            event.ts = 0
742            self._last_ts = 0
743        elif self.sys_info:
744            event.ts = self._update_ts(event.ts)
745
746        if event.id == SYSVIEW_EVTID_INIT:
747            self.sys_info = event
748            event.ts = self._update_ts(event.ts)
749        elif event.id == SYSVIEW_EVTID_TASK_INFO:
750            self.tasks_info[event.params['tid'].value] = event.params['name'].value
751        elif event.id == SYSVIEW_EVTID_SYSDESC:
752            irq = self._parse_irq_desc(event.params['desc'].value)
753            if irq:
754                irq_num = int(irq[1])
755                self.irqs_info[irq_num] = irq[0]
756        # count event and save it to the list
757        apptrace.TraceDataProcessor.on_new_event(self, event)
758
759
760class SysViewTraceDataExtEventParser(SysViewTraceDataParser):
761    def __init__(self, events_num, print_events=False, core_id=0):
762        """
763            Constructor.
764
765            Parameters
766            ----------
767            print_events : bool
768                see apptrace.TraceDataProcessor.__init__()
769            core_id : int
770                id of the core this parser object relates to.
771        """
772        SysViewTraceDataParser.__init__(self, core_id=core_id, print_events=print_events)
773        self.events_off = 0
774        self.events_num = events_num
775
776    def event_supported(self, event):
777        return False if (self.events_off < SYSVIEW_MODULE_EVENT_OFFSET or event.id < self.events_off or
778                        event.id >= (self.events_off + self.events_num)) else True
779
780
781class SysViewMultiTraceDataParser(SysViewTraceDataParser):
782    """
783        SystemView trace data parser supporting multiple event streams.
784    """
785    def __init__(self, print_events=False, core_id=0):
786        """
787            see SysViewTraceDataParser.__init__()
788        """
789        SysViewTraceDataParser.__init__(self, print_events, core_id)
790        self.stream_parsers = {}
791
792    def add_stream_parser(self, stream_id, parser):
793        """
794            Assigns parser for events stream.
795
796            Parameters
797            ----------
798            stream_id : int
799                stream ID. See SysViewTraceDataParser.STREAMID_xxx.
800                Parsers for SysViewTraceDataParser.STREAMID_SYS are ignored.
801                Top level parser is the default for SysViewTraceDataParser.STREAMID_SYS.
802            parser : SysViewTraceDataParser
803                parser object.
804        """
805        if stream_id == SysViewTraceDataParser.STREAMID_SYS:
806            return
807        parser.root_proc = self
808        self.stream_parsers[stream_id] = parser
809
810    def read_extension_event(self, evt_id, core_id, reader):
811        """
812            Reads extension event.
813            Iterates over registered stream parsers trying to find one which supports that type of event.
814
815            Parameters
816            ----------
817            evt_id : int
818                see SysViewTraceDataParser.read_extension_event()
819            reader : apptrace.Reader
820                see SysViewTraceDataParser.read_extension_event()
821
822            Returns
823            -------
824            SysViewEvent
825                object for extension event, if extension event is not supported return SysViewEvent instance.
826        """
827        for stream_id in self.stream_parsers:
828            evt = self.stream_parsers[stream_id].read_extension_event(evt_id, core_id, reader)
829            if evt:
830                return evt
831        return SysViewTraceDataParser.read_extension_event(self, evt_id, core_id, reader)
832
833    def on_new_event(self, event):
834        """
835            Iterates over registered stream parsers allowing them to do
836            essential processing of event. Must be called for every read event.
837
838            Parameters
839            ----------
840            event : SysViewEvent
841                Event object.
842        """
843        SysViewTraceDataParser.on_new_event(self, event)
844        for stream_id in self.stream_parsers:
845            self.stream_parsers[stream_id].on_new_event(event)
846
847
848class SysViewEventContext():
849    """
850        SystemView event context.
851    """
852    def __init__(self, handle, irq, name=''):
853        """
854            Constructor.
855
856            Parameters
857            ----------
858            handle : int
859                handle of the context: task ID or IRQ number.
860            irq : bool
861                flag indicating whether this is IRQ or task context.
862            name : string
863                name of the context: task or IRQ name. Empty if context is unknown.
864       """
865        self.handle = handle
866        self.irq = irq
867        self.name = name
868
869
870class SysViewTraceDataProcessor(apptrace.TraceDataProcessor):
871    """
872        Base SystemView trace data processor class.
873    """
874    def __init__(self, traces, root_proc=None, print_events=False, keep_all_events=False):
875        """
876            Constructor.
877
878            Parameters
879            ----------
880            traces : list
881                list of parsers to process data from.
882            print_events : bool
883                see apptrace.TraceDataProcessor.__init__()
884            keep_all_events : bool
885                see apptrace.TraceDataProcessor.__init__()
886        """
887        apptrace.TraceDataProcessor.__init__(self, print_events, keep_all_events)
888        self.event_ids = {}
889        self.name = ''
890        self.root_proc = root_proc if root_proc else self
891        self.traces = {}
892        self.ctx_stack = {}
893        self.prev_ctx = {}
894        self.no_ctx_events = []
895        for t in traces:
896            self.traces[t.core_id] = t
897            # current context item is a tuple of task ID or IRQ num and 'in_irq' flag
898            # empty list means IDLE context or self.start_ctx
899            self.ctx_stack[t.core_id] = []
900            # context is undefined, we do not know have we started the tracing in task/IDLE or IRQ context
901            # in general there are three scenarious when we can start tracing: when core is in task, IDLE task or IRQ context
902            self.prev_ctx[t.core_id] = None
903
904    def _get_curr_context(self, core_id):
905        """
906            Returns current context.
907
908            Parameters
909            ----------
910            core_id : int
911                core ID for requested context.
912
913            Returns
914            -------
915            SysViewEventContext
916                context object
917            None
918                if there current is undefined
919        """
920        if len(self.root_proc.ctx_stack[core_id]):
921            return self.root_proc.ctx_stack[core_id][-1]
922        if self._get_prev_context(core_id):
923            return SysViewEventContext(None, False, 'IDLE%d' % core_id)
924        return None
925
926    def _get_prev_context(self, core_id):
927        """
928            Returns current context.
929
930            Parameters
931            ----------
932            core_id : int
933                core ID for requested context.
934
935            Returns
936            -------
937            SysViewEventContext
938                context object
939        """
940        return self.root_proc.prev_ctx[core_id]
941
942    def get_trace_stream(self, core_id, stream_id):
943        """
944            Retrieves parser for specified stream and core.
945
946            Parameters
947            ----------
948            core_id : int
949                Parser's core ID.
950            stream_id : int
951                Parser's stream ID.
952
953            Returns
954            -------
955            SysViewTraceDataParser
956                parser object for specified stream and core
957        """
958        if self.root_proc == self:
959            return self.traces[core_id]
960        return self.root_proc.get_trace_stream(core_id, stream_id)
961
962    def event_supported(self, e):
963        """
964            Should be overriden in child class.
965        """
966        return False
967
968    def handle_event(self, e):
969        """
970            Should be overriden in child class.
971        """
972        pass
973
974    def print_report(self):
975        """
976            see apptrace.TraceDataProcessor.print_report()
977        """
978        apptrace.TraceDataProcessor.print_report(self)
979
980    def _process_event(self, event):
981        """
982            Processes event.
983            Keeps track of execution context on every core.
984
985            Parameters
986            ----------
987            event : SysViewEvent
988                Event object.
989
990            Raises
991            ----------
992            SysViewTraceParseError
993                if there is no parser for event's core or
994                if SYSVIEW_EVTID_ISR_ENTER is received for unknown IRQ or
995                if SYSVIEW_EVTID_TASK_START_EXEC or SYSVIEW_EVTID_TASK_STOP_READY is received for unknown task.
996        """
997        if event.core_id not in self.traces:
998            if 0 in self.traces and self.traces[0].esp_ext:
999                # for Espressif extension there is one trace for all cores
1000                trace = self.traces[0]
1001                if event.core_id not in self.ctx_stack:
1002                    self.ctx_stack[event.core_id] = []
1003                if event.core_id not in self.prev_ctx:
1004                    self.prev_ctx[event.core_id] = None
1005            else:
1006                raise SysViewTraceParseError('Event for unknown core %d' % event.core_id)
1007        else:
1008            trace = self.traces[event.core_id]
1009        if event.id == SYSVIEW_EVTID_ISR_ENTER:
1010            if event.params['irq_num'].value not in trace.irqs_info:
1011                raise SysViewTraceParseError('Enter unknown ISR %d' % event.params['irq_num'].value)
1012            if len(self.ctx_stack[event.core_id]):
1013                self.prev_ctx[event.core_id] = self.ctx_stack[event.core_id][-1]
1014            else:
1015                # the 1st context switching event after trace start is SYSVIEW_EVTID_ISR_ENTER, so we have been in IDLE context
1016                self.prev_ctx[event.core_id] = SysViewEventContext(None, False, 'IDLE%d' % event.core_id)
1017            # put new ISR context on top of the stack (the last in the list)
1018            self.ctx_stack[event.core_id].append(SysViewEventContext(event.params['irq_num'].value, True, trace.irqs_info[event.params['irq_num'].value]))
1019        elif event.id == SYSVIEW_EVTID_ISR_EXIT or event.id == SYSVIEW_EVTID_ISR_TO_SCHEDULER:
1020            if len(self.ctx_stack[event.core_id]):
1021                # return to the previous context (the last in the list)
1022                self.prev_ctx[event.core_id] = self.ctx_stack[event.core_id].pop()
1023            else:
1024                # the 1st context switching event after trace start is SYSVIEW_EVTID_ISR_EXIT, so we have been in ISR context,
1025                # but we do not know which one because SYSVIEW_EVTID_ISR_EXIT do not include the IRQ number
1026                self.prev_ctx[event.core_id] = SysViewEventContext(None, True, 'IRQ_oncore%d' % event.core_id)
1027        elif event.id == SYSVIEW_EVTID_TASK_START_EXEC:
1028            if event.params['tid'].value not in trace.tasks_info:
1029                raise SysViewTraceParseError('Start exec unknown task 0x%x' % event.params['tid'].value)
1030            if len(self.ctx_stack[event.core_id]):
1031                # return to the previous context (the last in the list)
1032                self.prev_ctx[event.core_id] = self.ctx_stack[event.core_id][-1]
1033            else:
1034                # the 1st context switching event after trace start is SYSVIEW_EVTID_TASK_START_EXEC, so we have been in IDLE context
1035                self.prev_ctx[event.core_id] = SysViewEventContext(None, False, 'IDLE%d' % event.core_id)
1036            # only one task at a time in context stack (can be interrupted by a bunch of ISRs)
1037            self.ctx_stack[event.core_id] = [SysViewEventContext(event.params['tid'].value, False, trace.tasks_info[event.params['tid'].value])]
1038        elif event.id == SYSVIEW_EVTID_TASK_STOP_EXEC:
1039            # delete task from context stack
1040            for ctx in self.ctx_stack[event.core_id]:
1041                if not ctx.irq:
1042                    if len(self.ctx_stack[event.core_id]) == 1:
1043                        # if this is the only ctx in context stack
1044                        self.prev_ctx[event.core_id] = ctx
1045                    del ctx
1046                    break
1047        elif event.id == SYSVIEW_EVTID_TASK_STOP_READY:
1048            if event.params['tid'].value not in trace.tasks_info:
1049                raise SysViewTraceParseError('Stop ready unknown task 0x%x' % event.params['tid'].value)
1050            if len(self.ctx_stack[event.core_id]):
1051                if (not self.ctx_stack[event.core_id][-1].irq and event.params['tid'].value == self.ctx_stack[event.core_id][-1].handle):
1052                    # return to the previous context (the last in the list)
1053                    self.prev_ctx[event.core_id] = self.ctx_stack[event.core_id].pop()
1054            else:
1055                # the 1st context switching event after trace start is SYSVIEW_EVTID_TASK_STOP_READY, so we have been in task context
1056                self.prev_ctx[event.core_id] = SysViewEventContext(event.params['tid'].value, False, trace.tasks_info[event.params['tid'].value])
1057
1058    def on_new_event(self, event):
1059        """
1060            Processes heap events.
1061        """
1062        if self.root_proc == self:
1063            SysViewTraceDataProcessor._process_event(self, event)
1064        curr_ctx = self._get_curr_context(event.core_id)
1065        if not curr_ctx:
1066            # postpone events handling till their context is known
1067            self.no_ctx_events.append(event)
1068            return
1069        event.in_irq = curr_ctx.irq
1070        event.ctx_name = curr_ctx.name
1071        # here we know the previous context: we switched from it or implied upon the 1st context switching event
1072        prev_ctx = self._get_prev_context(event.core_id)
1073        if len(self.no_ctx_events):
1074            for cached_evt in self.no_ctx_events:
1075                cached_evt.ctx_name = prev_ctx.name
1076                cached_evt.in_irq = prev_ctx.irq
1077                # count and save the event
1078                apptrace.TraceDataProcessor.on_new_event(self, cached_evt)
1079                if self.event_supported(event):
1080                    self.handle_event(event)
1081            del self.no_ctx_events[:]
1082        # count and save the event
1083        apptrace.TraceDataProcessor.on_new_event(self, event)
1084        if self.event_supported(event):
1085            self.handle_event(event)
1086
1087    def merge_and_process(self):
1088        """
1089            Merges events from all registered parsers, sorts them by timestamp and processes them.
1090        """
1091        all_events = []
1092        for t in self.traces.values():
1093            all_events.extend(t.events)
1094        all_events.sort(key=lambda x: x.ts)
1095        for event in all_events:
1096            self.on_new_event(event)
1097
1098
1099class SysViewMultiStreamTraceDataProcessor(SysViewTraceDataProcessor):
1100    """
1101        SystemView trace data processor supporting multiple event streams.
1102    """
1103    def __init__(self, traces, print_events=False, keep_all_events=False):
1104        """
1105            see SysViewTraceDataProcessor.__init__()
1106        """
1107        SysViewTraceDataProcessor.__init__(self, traces, print_events=print_events, keep_all_events=keep_all_events)
1108        self.stream_procs = {}
1109
1110    def add_stream_processor(self, stream_id, proc):
1111        """
1112            Assigns processor for events stream.
1113
1114            Parameters
1115            ----------
1116            stream_id : int
1117                stream ID. See SysViewTraceDataParser.STREAMID_xxx.
1118                Parsers for SysViewTraceDataParser.STREAMID_SYS are ignored.
1119                Top level parser is the default for SysViewTraceDataParser.STREAMID_SYS.
1120            proc : SysViewTraceDataProcessor
1121                processor object.
1122        """
1123        if stream_id == SysViewTraceDataParser.STREAMID_SYS:
1124            return
1125        proc.root_proc = self  # common processing data is kept by this processor
1126        self.stream_procs[stream_id] = proc
1127
1128    def get_trace_stream(self, core_id, stream_id):
1129        """
1130            Retrieves parser for specified stream and core.
1131
1132            Parameters
1133            ----------
1134            core_id : int
1135                Parser's core ID.
1136            stream_id : int
1137                Parser's stream ID.
1138
1139            Returns
1140            -------
1141            SysViewTraceDataParser
1142                parser object for specified stream and core
1143        """
1144        if core_id not in self.traces and 0 in self.traces and self.traces[0].esp_ext:
1145            # for Espressif extension there is one trace for all cores
1146            trace = self.traces[0]
1147        else:
1148            trace = self.traces[core_id]
1149        if stream_id == SysViewTraceDataParser.STREAMID_SYS:
1150            return trace
1151        if isinstance(trace, SysViewMultiTraceDataParser):
1152            return trace.stream_parsers[stream_id]
1153        return trace
1154
1155    def print_report(self):
1156        """
1157            Iterates over registered stream processors and prints their reports.
1158        """
1159        SysViewTraceDataProcessor.print_report(self)
1160        # need to sort stream procs by keys to print reports in the same order regardless of Python version
1161        stream_ids = list(self.stream_procs.keys())
1162        stream_ids.sort()
1163        for stream_id in stream_ids:
1164            self.stream_procs[stream_id].print_report()
1165
1166    def cleanup(self):
1167        """
1168            Iterates over registered stream processors and cleans them up.
1169        """
1170        for stream_id in self.stream_procs:
1171            self.stream_procs[stream_id].cleanup()
1172        SysViewTraceDataProcessor.cleanup(self)
1173
1174    def on_new_event(self, event):
1175        """
1176            Iterates over registered stream processors allowing them to do
1177            the processing of event.
1178
1179            Parameters
1180            ----------
1181            event : SysViewEvent
1182                Event object.
1183        """
1184        SysViewTraceDataProcessor.on_new_event(self, event)
1185        for stream_id in self.stream_procs:
1186            self.stream_procs[stream_id].on_new_event(event)
1187
1188
1189class SysViewTraceDataJsonEncoder(json.JSONEncoder):
1190    JSON_TRACE_VER = '1.0'
1191
1192    def default(self, obj):
1193        global _sysview_events_map
1194        global _os_events_map
1195        if isinstance(obj, SysViewMultiStreamTraceDataProcessor):
1196            json_event_ids = {'system': _sysview_events_map, 'os': {}}
1197            for eid in _os_events_map:
1198                ename = _os_events_map[eid][0]
1199                json_event_ids['os'][ename] = eid
1200            for stream in obj.stream_procs.values():
1201                json_event_ids[stream.name] = stream.event_ids
1202            json_events = []
1203            for e in obj.events:
1204                for stream in obj.stream_procs.values():
1205                    if stream.event_supported(e):
1206                        json_events.append(e)
1207                        break
1208                # include also OS and pre-defined events
1209                if isinstance(e, SysViewPredefinedEvent) or isinstance(e, SysViewOSEvent):
1210                    json_events.append(e)
1211            return {'version': self.JSON_TRACE_VER, 'streams': json_event_ids, 'events': json_events}
1212        if isinstance(obj, SysViewHeapEvent):
1213            blk_size = 0
1214            if 'size' in obj.params:
1215                blk_size = obj.params['size'].value
1216            blk_addr = '0x{:x}'.format(obj.params['addr'].value)
1217            callers = []
1218            for addr in obj.params['callers'].value:
1219                callers.append('0x{:x}'.format(addr))
1220            return {'ctx_name': obj.ctx_name, 'in_irq': obj.in_irq, 'id': obj.id, 'core_id': obj.core_id,
1221                    'ts': obj.ts, 'addr': blk_addr, 'size': blk_size, 'callers': callers}
1222        if isinstance(obj, SysViewPredefinedEvent) and obj.id == SYSVIEW_EVTID_PRINT_FORMATTED:
1223            return {'ctx_name': obj.ctx_name, 'in_irq': obj.in_irq, 'id': obj.id, 'core_id': obj.core_id,
1224                    'ts': obj.ts, 'msg': obj.params['msg'].value, 'lvl': obj.params['lvl'].value}
1225        if isinstance(obj, SysViewEvent):
1226            jobj = obj.to_jsonable()
1227            # remove unused fields
1228            if 'name' in jobj:
1229                del jobj['name']
1230            if 'plen' in jobj:
1231                del jobj['plen']
1232            return jobj
1233        # Let the base class default method raise the TypeError
1234        return json.JSONEncoder.default(self, obj)
1235
1236
1237class SysViewHeapTraceDataParser(SysViewTraceDataExtEventParser):
1238    """
1239        SystemView trace data parser supporting heap events.
1240    """
1241    def __init__(self, print_events=False, core_id=0):
1242        """
1243            SystemView trace data parser supporting multiple event streams.
1244            see SysViewTraceDataExtEventParser.__init__()
1245        """
1246        SysViewTraceDataExtEventParser.__init__(self, events_num=len(SysViewHeapEvent.events_fmt.keys()), core_id=core_id, print_events=print_events)
1247
1248    def read_extension_event(self, evt_id, core_id, reader):
1249        """
1250            Reads heap event.
1251            see SysViewTraceDataParser.read_extension_event()
1252        """
1253        if (self.events_off >= SYSVIEW_MODULE_EVENT_OFFSET and evt_id >= self.events_off and
1254                evt_id < self.events_off + self.events_num):
1255            return SysViewHeapEvent(evt_id, core_id, self.events_off, reader)
1256        return SysViewTraceDataParser.read_extension_event(self, evt_id, core_id, reader)
1257
1258    def on_new_event(self, event):
1259        """
1260            Keeps track of heap module descriptions.
1261        """
1262        if self.root_proc == self:
1263            SysViewTraceDataParser.on_new_event(self, event)
1264        if event.id == SYSVIEW_EVTID_MODULEDESC and event.params['desc'].value == 'ESP32 SystemView Heap Tracing Module':
1265            self.events_off = event.params['evt_off'].value
1266
1267
1268class SysViewHeapTraceDataProcessor(SysViewTraceDataProcessor, apptrace.BaseHeapTraceDataProcessorImpl):
1269    """
1270        SystemView trace data processor supporting heap events.
1271    """
1272    def __init__(self, toolchain_pref, elf_path, root_proc=None, traces=[], print_events=False, print_heap_events=False):
1273        """
1274            Constructor.
1275            see SysViewTraceDataProcessor.__init__()
1276            see apptrace.BaseHeapTraceDataProcessorImpl.__init__()
1277        """
1278        SysViewTraceDataProcessor.__init__(self, traces, root_proc=root_proc, print_events=print_events)
1279        apptrace.BaseHeapTraceDataProcessorImpl.__init__(self, print_heap_events)
1280        self.toolchain = toolchain_pref
1281        self.elf_path = elf_path
1282        # self.no_ctx_events = []
1283        self.name = 'heap'
1284        stream = self.root_proc.get_trace_stream(0, SysViewTraceDataParser.STREAMID_HEAP)
1285        self.event_ids = {'alloc': stream.events_off, 'free': stream.events_off + 1}
1286
1287    def event_supported(self, event):
1288        heap_stream = self.root_proc.get_trace_stream(event.core_id, SysViewTraceDataParser.STREAMID_HEAP)
1289        return heap_stream.event_supported(event)
1290
1291    def handle_event(self, event):
1292        heap_stream = self.root_proc.get_trace_stream(event.core_id, SysViewTraceDataParser.STREAMID_HEAP)
1293        if (event.id - heap_stream.events_off) == 0:
1294            heap_event = apptrace.HeapTraceEvent(event, True, toolchain=self.toolchain,
1295                                                 elf_path=self.elf_path)
1296        else:
1297            heap_event = apptrace.HeapTraceEvent(event, False, toolchain=self.toolchain,
1298                                                 elf_path=self.elf_path)
1299        apptrace.BaseHeapTraceDataProcessorImpl.on_new_event(self, heap_event)
1300
1301    def print_report(self):
1302        """
1303            see apptrace.TraceDataProcessor.print_report()
1304        """
1305        if self.root_proc == self:
1306            SysViewTraceDataProcessor.print_report(self)
1307        apptrace.BaseHeapTraceDataProcessorImpl.print_report(self)
1308
1309
1310class SysViewLogTraceEvent(apptrace.LogTraceEvent):
1311    """
1312        SystemView log event.
1313    """
1314    def __init__(self, ts, msg):
1315        """
1316            Constructor.
1317
1318            Parameters
1319            ----------
1320            msg : string
1321                Log message string.
1322        """
1323        self.msg = msg
1324        self.ts = ts
1325
1326    def get_message(self, unused):
1327        """
1328            Retrieves log message.
1329
1330            Returns
1331            -------
1332            string
1333                formatted log message
1334        """
1335        return '[{:.9f}] LOG: {}'.format(self.ts, self.msg)
1336
1337
1338class SysViewLogTraceDataParser(SysViewTraceDataParser):
1339    """
1340        SystemView trace data parser supporting log events.
1341    """
1342    def event_supported(self, event):
1343        return event.id == SYSVIEW_EVTID_PRINT_FORMATTED
1344
1345    def on_new_event(self, event):
1346        """
1347            see SysViewTraceDataParser.on_new_event()
1348        """
1349        if self.root_proc == self:
1350            SysViewTraceDataParser.on_new_event(self, event)
1351
1352
1353class SysViewLogTraceDataProcessor(SysViewTraceDataProcessor, apptrace.BaseLogTraceDataProcessorImpl):
1354    """
1355        SystemView trace data processor supporting heap events.
1356    """
1357    def __init__(self, traces=[], root_proc=None, print_events=False, print_log_events=False):
1358        """
1359            Constructor.
1360            see SysViewTraceDataProcessor.__init__()
1361            see apptrace.BaseLogTraceDataProcessorImpl.__init__()
1362        """
1363        SysViewTraceDataProcessor.__init__(self, traces, root_proc=root_proc, print_events=print_events)
1364        apptrace.BaseLogTraceDataProcessorImpl.__init__(self, print_log_events)
1365        self.name = 'log'
1366        self.event_ids = {'print': SYSVIEW_EVTID_PRINT_FORMATTED}
1367
1368    def event_supported(self, event):
1369        return event.id == SYSVIEW_EVTID_PRINT_FORMATTED
1370
1371    def on_new_event(self, event):
1372        """
1373            Processes log events.
1374        """
1375        if self.root_proc == self:
1376            SysViewTraceDataProcessor.on_new_event(self, event)
1377        if event.id == SYSVIEW_EVTID_PRINT_FORMATTED:
1378            log_evt = SysViewLogTraceEvent(event.ts, event.params['msg'].value)
1379            apptrace.BaseLogTraceDataProcessorImpl.on_new_event(self, log_evt)
1380
1381    def print_report(self):
1382        """
1383            see apptrace.TraceDataProcessor.print_report()
1384        """
1385        if self.root_proc == self:
1386            SysViewTraceDataProcessor.print_report(self)
1387        apptrace.BaseLogTraceDataProcessorImpl.print_report(self)
1388