sysview.py 43 KB

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