1*270e3f07SIan Rogers# SPDX-License-Identifier: GPL-2.0 2*270e3f07SIan Rogers""" 3*270e3f07SIan RogersLive event session helper using perf.evlist. 4*270e3f07SIan Rogers 5*270e3f07SIan RogersThis module provides a LiveSession class that allows running a callback 6*270e3f07SIan Rogersfor each event collected live from the system, similar to perf.session 7*270e3f07SIan Rogersbut without requiring a perf.data file. 8*270e3f07SIan Rogers""" 9*270e3f07SIan Rogers 10*270e3f07SIan Rogersimport perf 11*270e3f07SIan Rogers 12*270e3f07SIan Rogers 13*270e3f07SIan Rogersclass LiveSession: 14*270e3f07SIan Rogers """Represents a live event collection session.""" 15*270e3f07SIan Rogers 16*270e3f07SIan Rogers def __init__(self, event_string: str, sample_callback): 17*270e3f07SIan Rogers self.event_string = event_string 18*270e3f07SIan Rogers self.sample_callback = sample_callback 19*270e3f07SIan Rogers # Create a cpu map for all online CPUs 20*270e3f07SIan Rogers self.cpus = perf.cpu_map() 21*270e3f07SIan Rogers # Parse events and set maps 22*270e3f07SIan Rogers self.evlist = perf.parse_events(self.event_string, self.cpus) 23*270e3f07SIan Rogers self.evlist.config() 24*270e3f07SIan Rogers 25*270e3f07SIan Rogers def run(self): 26*270e3f07SIan Rogers """Run the live session.""" 27*270e3f07SIan Rogers try: 28*270e3f07SIan Rogers self.evlist.open() 29*270e3f07SIan Rogers self.evlist.mmap() 30*270e3f07SIan Rogers self.evlist.enable() 31*270e3f07SIan Rogers 32*270e3f07SIan Rogers while True: 33*270e3f07SIan Rogers # Poll for events with 100ms timeout 34*270e3f07SIan Rogers try: 35*270e3f07SIan Rogers self.evlist.poll(100) 36*270e3f07SIan Rogers except InterruptedError: 37*270e3f07SIan Rogers continue 38*270e3f07SIan Rogers for cpu in self.cpus: 39*270e3f07SIan Rogers for _ in range(1000): # Limit to 1000 events per CPU per poll to prevent starvation 40*270e3f07SIan Rogers try: 41*270e3f07SIan Rogers event = self.evlist.read_on_cpu(cpu) 42*270e3f07SIan Rogers except TypeError as e: 43*270e3f07SIan Rogers if "Unknown CPU" in str(e): 44*270e3f07SIan Rogers # CPU might be unmapped or offline, wait for mmap event 45*270e3f07SIan Rogers break 46*270e3f07SIan Rogers if "Unexpected header type" in str(e): 47*270e3f07SIan Rogers # Ignore valid but unsupported event types 48*270e3f07SIan Rogers continue 49*270e3f07SIan Rogers raise 50*270e3f07SIan Rogers 51*270e3f07SIan Rogers if event is None: 52*270e3f07SIan Rogers break 53*270e3f07SIan Rogers 54*270e3f07SIan Rogers if event.type == perf.RECORD_SAMPLE: 55*270e3f07SIan Rogers self.sample_callback(event) 56*270e3f07SIan Rogers except KeyboardInterrupt: 57*270e3f07SIan Rogers pass 58*270e3f07SIan Rogers finally: 59*270e3f07SIan Rogers self.evlist.close() 60