#!/usr/bin/env python # -*- coding: utf-8 -*- from typing import List, Union, Dict from collections import namedtuple class FieldType: def __init__(self, c_type: str): self.c_type = c_type VariableLength = None ThreadId = FieldType('EventThreadID') KernelThreadId = FieldType('EventKernelThreadId') CapNo = FieldType('EventCapNo') CapsetType = FieldType('EventCapsetType') Timestamp = FieldType('EventTimestamp') CapsetId = FieldType('EventCapsetID') TaskId = FieldType('EventTaskId') Word8 = FieldType('StgWord8') Word16 = FieldType('StgWord16') Word32 = FieldType('StgWord32') Word64 = FieldType('StgWord64') class EventType: def __init__(self, n: int, name: str, fields: Union[VariableLength, List[FieldType]], description: str): self.n = n self.name = name self.fields = fields self.description = description def __str__(self): return '(n={n}, name={name})'.format(n=self.n, name=self.name) # When adding a new event type used by GHC you should also update # NUM_GHC_EVENT_TAGS in rts/include/rts/EventLogFormat.h. event_types = [ EventType( 0, 'CREATE_THREAD', [ThreadId], 'Create thread'), EventType( 1, 'RUN_THREAD', [ThreadId], 'Run thread'), EventType( 2, 'STOP_THREAD', [ThreadId, Word16, ThreadId], 'Stop thread'), EventType( 3, 'THREAD_RUNNABLE', [ThreadId], 'Thread runnable'), EventType( 4, 'MIGRATE_THREAD', [ThreadId, CapNo], 'Migrate thread'), # 5, 6, 7 deprecated EventType( 8, 'THREAD_WAKEUP', [ThreadId, CapNo], 'Wakeup thread'), EventType( 9, 'GC_START', [], 'Starting GC'), EventType(10, 'GC_END', [], 'Finished GC'), EventType(11, 'REQUEST_SEQ_GC', [], 'Request sequential GC'), EventType(12, 'REQUEST_PAR_GC', [], 'Request parallel GC'), # 13, 14 deprecated EventType(15, 'CREATE_SPARK_THREAD', [ThreadId], 'Create spark thread'), EventType(16, 'LOG_MSG', VariableLength, 'Log message'), # 17 deprecated EventType(18, 'BLOCK_MARKER', [Word32, Timestamp, CapNo], 'Block marker'), EventType(19, 'USER_MSG', VariableLength, 'User message'), EventType(20, 'GC_IDLE', [], 'GC idle'), EventType(21, 'GC_WORK', [], 'GC working'), EventType(22, 'GC_DONE', [], 'GC done'), # 23, 24 used by eden EventType(25, 'CAPSET_CREATE', [CapsetId, CapsetType], 'Create capability set'), EventType(26, 'CAPSET_DELETE', [CapsetId], 'Delete capability set'), EventType(27, 'CAPSET_ASSIGN_CAP',[CapsetId, CapNo], 'Add capability to capability set'), EventType(28, 'CAPSET_REMOVE_CAP',[CapsetId, CapNo], 'Remove capability from capability set'), EventType(29, 'RTS_IDENTIFIER', VariableLength, 'RTS name and version'), EventType(30, 'PROGRAM_ARGS', VariableLength, 'Program arguments'), EventType(31, 'PROGRAM_ENV', VariableLength, 'Program environment variables'), EventType(32, 'OSPROCESS_PID', [CapsetId, Word32], 'Process ID'), EventType(33, 'OSPROCESS_PPID', [CapsetId, Word32], 'Parent process ID'), EventType(34, 'SPARK_COUNTERS', 7*[Word64], 'Spark counters'), EventType(35, 'SPARK_CREATE', [], 'Spark create'), EventType(36, 'SPARK_DUD', [], 'Spark dud'), EventType(37, 'SPARK_OVERFLOW', [], 'Spark overflow'), EventType(38, 'SPARK_RUN', [], 'Spark run'), EventType(39, 'SPARK_STEAL', [CapNo], 'Spark steal'), EventType(40, 'SPARK_FIZZLE', [], 'Spark fizzle'), EventType(41, 'SPARK_GC', [], 'Spark GC'), EventType(42, 'INTERN_STRING', VariableLength, 'Intern string'), EventType(43, 'WALL_CLOCK_TIME', [CapsetId, Word64, Word32], 'Wall clock time'), EventType(44, 'THREAD_LABEL', VariableLength, 'Thread label'), EventType(45, 'CAP_CREATE', [CapNo], 'Create capability'), EventType(46, 'CAP_DELETE', [CapNo], 'Delete capability'), EventType(47, 'CAP_DISABLE', [CapNo], 'Disable capability'), EventType(48, 'CAP_ENABLE', [CapNo], 'Enable capability'), EventType(49, 'HEAP_ALLOCATED', [CapsetId, Word64], 'Total heap memory ever allocated'), EventType(50, 'HEAP_SIZE', [CapsetId, Word64], 'Current heap size (number of allocated mblocks)'), EventType(51, 'HEAP_LIVE', [CapsetId, Word64], 'Current heap live data'), EventType(52, 'HEAP_INFO_GHC', [CapsetId, Word16] + 4*[Word64], 'Heap static parameters'), EventType(53, 'GC_STATS_GHC', [CapsetId, Word16] + 3*[Word64] + [Word32] + 3*[Word64], 'GC statistics'), EventType(54, 'GC_GLOBAL_SYNC', [], 'Synchronise stop-the-world GC'), EventType(55, 'TASK_CREATE', [TaskId, CapNo, KernelThreadId], 'Task create'), EventType(56, 'TASK_MIGRATE', [TaskId, CapNo, CapNo], 'Task migrate'), EventType(57, 'TASK_DELETE', [TaskId], 'Task delete'), EventType(58, 'USER_MARKER', VariableLength, 'User marker'), EventType(59, 'HACK_BUG_T9003', [], 'Empty event for bug #9003'), # Range 60 - 80 is used by eden for parallel tracing. # See http://www.mathematik.uni-marburg.de/~eden/ EventType(90, 'MEM_RETURN', [CapsetId, Word32, Word32, Word32], 'The RTS attempted to return heap memory to the OS'), EventType(91, 'BLOCKS_SIZE', [CapsetId, Word64], 'Report the size of the heap in blocks'), # Range 100 - 139 is reserved for Mercury. # Range 140 - 159 is reserved for Perf events. # Range 160 - 180 is reserved for cost-centre heap profiling events. # Cost-centre profiler EventType(160, 'HEAP_PROF_BEGIN', VariableLength, 'Start of heap profile'), EventType(161, 'HEAP_PROF_COST_CENTRE', VariableLength, 'Cost-centre definition'), EventType(162, 'HEAP_PROF_SAMPLE_BEGIN', [Word64], 'Start of heap profile sample'), EventType(163, 'HEAP_PROF_SAMPLE_COST_CENTRE', VariableLength, 'Heap profile cost-centre sample'), EventType(164, 'HEAP_PROF_SAMPLE_STRING', VariableLength, 'Heap profile string sample'), EventType(165, 'HEAP_PROF_SAMPLE_END', [Word64], 'End of heap profile sample'), EventType(166, 'HEAP_BIO_PROF_SAMPLE_BEGIN', [Word64, Word64], 'Start of heap profile (biographical) sample'), EventType(167, 'PROF_SAMPLE_COST_CENTRE', VariableLength, 'Time profile cost-centre stack'), EventType(168, 'PROF_BEGIN', [Word64], 'Start of a time profile'), EventType(169, 'IPE', VariableLength, 'An IPE entry'), EventType(181, 'USER_BINARY_MSG', VariableLength, 'User binary message'), # Non-moving GC EventType(200, 'CONC_MARK_BEGIN', [], 'Begin concurrent mark phase'), EventType(201, 'CONC_MARK_END', [Word32], 'End concurrent mark phase'), EventType(202, 'CONC_SYNC_BEGIN', [], 'Begin concurrent GC synchronisation'), EventType(203, 'CONC_SYNC_END', [], 'End concurrent mark synchronisation'), EventType(204, 'CONC_SWEEP_BEGIN', [], 'Begin concurrent sweep phase'), EventType(205, 'CONC_SWEEP_END', [], 'End concurrent sweep phase'), EventType(206, 'CONC_UPD_REM_SET_FLUSH', [CapNo], 'Update remembered set flushed'), EventType(207, 'NONMOVING_HEAP_CENSUS', [Word8, Word32, Word32, Word32], 'Nonmoving heap census'), # Ticky-ticky profiling EventType(210, 'TICKY_COUNTER_DEF', VariableLength, 'Ticky-ticky entry counter definition'), EventType(211, 'TICKY_COUNTER_SAMPLE', 4*[Word64], 'Ticky-ticky entry counter sample'), EventType(212, 'TICKY_COUNTER_BEGIN_SAMPLE', [], 'Ticky-ticky entry counter begin sample'), ] def check_events() -> Dict[int, EventType]: seen_ids = {} for ty in event_types: if ty.n in seen_ids: print('Duplicate event type {n}:'.format(n=ty.n)) print(' {name}'.format(name=ty.name)) print(' {seen}'.format(seen=seen_ids[ty.n].name)) assert False seen_ids[ty.n] = ty return seen_ids def generate_event_types_array() -> str: x = [] pr = lambda s: x.append(s) pr('/*') pr(' * Do not edit: This file is generated by event_types.py') pr(' */') pr('') pr('EventType eventTypes[] = {') for ty in event_types: if ty.fields is VariableLength: length = '0xffff' elif len(ty.fields) == 0: length = '0' else: length = ' + '.join('sizeof({c_type})'.format(c_type=field.c_type) for field in ty.fields) pr(' [EVENT_{}] = {{'.format(ty.name)) pr(' .etNum = {},'.format(ty.n)) pr(' .size = {},'.format(length)) pr(' .desc = "{}"'.format(ty.description)) pr(' },') pr('};') return '\n'.join(x) def generate_event_types_defines() -> str: x = [] pr = lambda s: x.append(s) pr('/*') pr(' * Do not edit: This file is generated by event_types.py') pr(' */') pr('') pr('#pragma once') pr('') for ty in event_types: pr('#define EVENT_{name} {n}'.format(name=ty.name, n=ty.n)) return '\n'.join(x) def main() -> None: import argparse parser = argparse.ArgumentParser() parser.add_argument('--event-types-array', type=argparse.FileType('w'), metavar='FILE') parser.add_argument('--event-types-defines', type=argparse.FileType('w'), metavar='FILE') args = parser.parse_args() check_events() if args.event_types_array: args.event_types_array.write(generate_event_types_array()) if args.event_types_defines: args.event_types_defines.write(generate_event_types_defines()) if __name__ == '__main__': main()