def __init__(self, stream=None, event_close=None, log_lvl=logging.WARNING): plt.rcParams['toolbar'] = 'None' plt.ioff() self.plot_config = PlotNordicConfig self.draw_state = DrawState( self.plot_config['timeline_width_init'], self.plot_config['event_processing_rect_height'], self.plot_config['event_submit_markersize']) self.ani = None self.close_event_flag = False self.processed_events = ProcessedEvents() if stream is not None: timeouts = { 'descriptions': 1, 'events': 0 } self.in_stream = stream self.in_stream.set_timeouts(timeouts) if event_close is not None: self.event_close = event_close self.logger = logging.getLogger('Plot Nordic') self.logger_console = logging.StreamHandler() self.logger.setLevel(log_lvl) self.log_format = logging.Formatter( '[%(levelname)s] %(name)s: %(message)s') self.logger_console.setFormatter(self.log_format) self.logger.addHandler(self.logger_console)
def __init__(self, events_filename, events_types_filename, log_lvl): self.data_name = events_filename.split('.')[0] self.processed_data = ProcessedEvents() self.processed_data.read_data_from_files(events_filename, events_types_filename) self.logger = logging.getLogger('Stats Nordic') self.logger_console = logging.StreamHandler() self.logger.setLevel(log_lvl) self.log_format = logging.Formatter( '[%(levelname)s] %(name)s: %(message)s') self.logger_console.setFormatter(self.log_format) self.logger.addHandler(self.logger_console)
def __init__(self, own_recv_socket_dict, own_send_socket_dict=None, remote_socket_dict=None, config=RttNordicConfig, event_filename=None, event_types_filename=None, log_lvl=logging.INFO): self.config = config self.event_filename = event_filename self.event_types_filename = event_types_filename self.csvfile = None timeouts = {'descriptions': None, 'events': None} self.in_stream = Stream(own_recv_socket_dict, timeouts) if own_send_socket_dict is not None and remote_socket_dict is not None: self.sending = True self.out_stream = Stream(own_send_socket_dict, timeouts, remote_socket_dict=remote_socket_dict) else: self.sending = False self.timestamp_overflows = 0 self.after_half = False self.processed_events = ProcessedEvents() self.temp_events = [] self.submitted_event_type = None self.raw_data = EventsData([], {}) self.event_processing_start_id = None self.event_processing_end_id = None self.submit_event = None self.start_event = None self.bufs = list() self.bcnt = 0 self.logger = logging.getLogger('Profiler model creator') self.logger_console = logging.StreamHandler() self.logger.setLevel(log_lvl) self.log_format = logging.Formatter( '[%(levelname)s] %(name)s: %(message)s') self.logger_console.setFormatter(self.log_format) self.logger.addHandler(self.logger_console)
def __init__(self, stream, event_close, sending_events=False, config=RttNordicConfig, event_filename=None, event_types_filename=None, log_lvl=logging.INFO): self.config = config self.event_filename = event_filename self.event_types_filename = event_types_filename self.csvfile = None self.event_close = event_close timeouts = { 'descriptions': 1, 'events': 1 } self.stream = stream self.stream.set_timeouts(timeouts) self.sending = sending_events self.timestamp_overflows = 0 self.after_half = False self.processed_events = ProcessedEvents() self.temp_events = [] self.submitted_event_type = None self.raw_data = EventsData([], {}) self.event_processing_start_id = None self.event_processing_end_id = None self.submit_event = None self.start_event = None self.bufs = list() self.bcnt = 0 self.logger = logging.getLogger('Profiler model creator') self.logger_console = logging.StreamHandler() self.logger.setLevel(log_lvl) self.log_format = logging.Formatter('[%(levelname)s] %(name)s: %(message)s') self.logger_console.setFormatter(self.log_format) self.logger.addHandler(self.logger_console)
def __init__(self, log_lvl=logging.WARNING): plt.rcParams['toolbar'] = 'None' plt.ioff() self.plot_config = PlotNordicConfig self.draw_state = DrawState( self.plot_config['timeline_width_init'], self.plot_config['event_processing_rect_height'], self.plot_config['event_submit_markersize']) self.processed_events = ProcessedEvents() self.submitted_event_type = None self.temp_events = [] self.logger = logging.getLogger('RTT Plot Nordic') self.logger_console = logging.StreamHandler() self.logger.setLevel(log_lvl) self.log_format = logging.Formatter( '[%(levelname)s] %(name)s: %(message)s') self.logger_console.setFormatter(self.log_format) self.logger.addHandler(self.logger_console)
class ModelCreator: def __init__(self, own_recv_socket_dict, own_send_socket_dict=None, remote_socket_dict=None, config=RttNordicConfig, event_filename=None, event_types_filename=None, log_lvl=logging.INFO): self.config = config self.event_filename = event_filename self.event_types_filename = event_types_filename self.csvfile = None timeouts = {'descriptions': None, 'events': None} self.in_stream = Stream(own_recv_socket_dict, timeouts) if own_send_socket_dict is not None and remote_socket_dict is not None: self.sending = True self.out_stream = Stream(own_send_socket_dict, timeouts, remote_socket_dict=remote_socket_dict) else: self.sending = False self.timestamp_overflows = 0 self.after_half = False self.processed_events = ProcessedEvents() self.temp_events = [] self.submitted_event_type = None self.raw_data = EventsData([], {}) self.event_processing_start_id = None self.event_processing_end_id = None self.submit_event = None self.start_event = None self.bufs = list() self.bcnt = 0 self.logger = logging.getLogger('Profiler model creator') self.logger_console = logging.StreamHandler() self.logger.setLevel(log_lvl) self.log_format = logging.Formatter( '[%(levelname)s] %(name)s: %(message)s') self.logger_console.setFormatter(self.log_format) self.logger.addHandler(self.logger_console) def shutdown(self): if self.csvfile is not None: self.processed_events.finish_writing_data_to_files( self.csvfile, self.event_filename, self.event_types_filename) def _get_buffered_data(self, num_bytes): buf = bytearray() while len(buf) < num_bytes: tbuf = self.bufs[0] size = num_bytes - len(buf) if len(tbuf) <= size: buf.extend(tbuf) del self.bufs[0] else: buf.extend(tbuf[0:size]) self.bufs[0] = tbuf[size:] self.bcnt -= num_bytes return buf def _read_bytes(self, num_bytes): while True: if self.bcnt >= num_bytes: break try: buf = self.in_stream.recv_ev() except StreamError as err: self.logger.error("Receiving error: {}".format(err)) self.close() if len(buf) > 0: self.bufs.append(buf) self.bcnt += len(buf) return self._get_buffered_data(num_bytes) def _timestamp_from_ticks(self, clock_ticks): ts_ticks_aggregated = self.timestamp_overflows * self.config[ 'timestamp_raw_max'] ts_ticks_aggregated += clock_ticks ts_s = ts_ticks_aggregated * self.config['ms_per_timestamp_tick'] / 1000 return ts_s def transmit_all_events_descriptions(self): try: bytes = self.in_stream.recv_desc() except StreamError as err: self.logger.error("Receiving error: {}. Exiting".format(err)) sys.exit() desc_buf = bytes.decode() f = StringIO(desc_buf) reader = csv.reader(f, delimiter=',') for row in reader: # Empty field is send after last event description if len(row) == 0: break name = row[0] id = int(row[1]) data_type = row[2:len(row) // 2 + 1] data = row[len(row) // 2 + 1:] self.raw_data.registered_events_types[id] = EventType( name, data_type, data) if name not in ('event_processing_start', 'event_processing_end'): self.processed_events.registered_events_types[id] = EventType( name, data_type, data) self.event_processing_start_id = \ self.raw_data.get_event_type_id('event_processing_start') self.event_processing_end_id = \ self.raw_data.get_event_type_id('event_processing_end') if self.sending: event_types_dict = dict( (k, v.serialize()) for k, v in self.processed_events.registered_events_types.items()) json_et_string = json.dumps(event_types_dict) try: self.out_stream.send_desc(json_et_string.encode()) except StreamError as err: self.logger.error("Error: {}. Unable to send data".format(err)) sys.exit() def _read_single_event(self): id = int.from_bytes(self._read_bytes(1), byteorder=self.config['byteorder'], signed=False) et = self.raw_data.registered_events_types[id] buf = self._read_bytes(4) timestamp_raw = (int.from_bytes(buf, byteorder=self.config['byteorder'], signed=False)) if self.after_half \ and timestamp_raw < 0.4 * self.config['timestamp_raw_max']: self.timestamp_overflows += 1 self.after_half = False if timestamp_raw > 0.6 * self.config['timestamp_raw_max']: self.after_half = True timestamp = self._timestamp_from_ticks(timestamp_raw) def process_int32(self, data): buf = self._read_bytes(4) data.append( int.from_bytes(buf, byteorder=self.config['byteorder'], signed=True)) def process_uint32(self, data): buf = self._read_bytes(4) data.append( int.from_bytes(buf, byteorder=self.config['byteorder'], signed=False)) def process_int16(self, data): buf = self._read_bytes(2) data.append( int.from_bytes(buf, byteorder=self.config['byteorder'], signed=True)) def process_uint16(self, data): buf = self._read_bytes(2) data.append( int.from_bytes(buf, byteorder=self.config['byteorder'], signed=False)) def process_int8(self, data): buf = self._read_bytes(1) data.append( int.from_bytes(buf, byteorder=self.config['byteorder'], signed=True)) def process_uint8(self, data): buf = self._read_bytes(1) data.append( int.from_bytes(buf, byteorder=self.config['byteorder'], signed=False)) def process_string(self, data): buf = self._read_bytes(1) buf = self._read_bytes( int.from_bytes(buf, byteorder=self.config['byteorder'], signed=False)) data.append(buf.decode()) READ_BYTES = { "u8": process_uint8, "s8": process_int8, "u16": process_uint16, "s16": process_int16, "u32": process_uint32, "s32": process_int32, "s": process_string, "t": process_uint32 } data = [] for event_data_type in et.data_types: READ_BYTES[event_data_type](self, data) return Event(id, timestamp, data) def _send_event(self, tracked_event): event_string = tracked_event.serialize() try: self.out_stream.send_ev(event_string.encode()) except StreamError as err: if err.args[1] != 'closed': self.logger.error("Error. Unable to send data: {}".format(err)) # Receiver has been closed self.close() def _write_event_to_file(self, csvfile, tracked_event): try: csvfile.write(tracked_event.serialize() + '\r\n') except IOError: self.logger.error("Problem with accessing csv file") self.close() def transmit_events(self): if self.event_filename and self.event_types_filename: self.csvfile = self.processed_events.init_writing_data_to_files( self.event_filename, self.event_types_filename) while True: event = self._read_single_event() if event.type_id == self.event_processing_start_id: self.start_event = event for i in range(len(self.temp_events) - 1, -1, -1): # comparing memory addresses of event processing start # and event submit to identify matching events if self.temp_events[i].data[0] == self.start_event.data[0]: self.submit_event = self.temp_events[i] self.submitted_event_type = self.submit_event.type_id del self.temp_events[i] break elif event.type_id == self.event_processing_end_id: # comparing memory addresses of event processing start and # end to identify matching events if self.submitted_event_type is not None and event.data[0] \ == self.start_event.data[0]: tracked_event = TrackedEvent(self.submit_event, self.start_event.timestamp, event.timestamp) if self.csvfile is not None: self._write_event_to_file(self.csvfile, tracked_event) if self.sending: self._send_event(tracked_event) self.submitted_event_type = None elif not self.processed_events.is_event_tracked(event.type_id): tracked_event = TrackedEvent(event, None, None) if self.csvfile is not None: self._write_event_to_file(self.csvfile, tracked_event) if self.sending: self._send_event(tracked_event) else: self.temp_events.append(event) def start(self): self.transmit_all_events_descriptions() self.transmit_events() def close(self): self.logger.info("Real time transmission closed") self.shutdown() self.logger.info("Events data saved to files") sys.exit()
class StatsNordic(): def __init__(self, events_filename, events_types_filename, log_lvl): self.data_name = events_filename.split('.')[0] self.processed_data = ProcessedEvents() self.processed_data.raw_data.read_data_from_files( events_filename, events_types_filename) self.processed_data.match_event_processing() self.logger = logging.getLogger('Stats Nordic') self.logger_console = logging.StreamHandler() self.logger.setLevel(log_lvl) self.log_format = logging.Formatter( '[%(levelname)s] %(name)s: %(message)s') self.logger_console.setFormatter(self.log_format) self.logger.addHandler(self.logger_console) def calculate_stats_preset1(self): self.time_between_events("hid_report_sent_event", EventState.PROC_END, "motion_event", EventState.SUBMIT, 4000) self.time_between_events("motion_event", EventState.SUBMIT, "hid_report_sent_event", EventState.PROC_END, 4000) plt.show() def _get_timestamps(self, event_name, event_state): event_type_id = self.processed_data.raw_data.get_event_type_id( event_name) if event_type_id == None: self.logger.error("Event name not found: " + event_name) return None trackings = list( filter(lambda x: x.submit.type_id == event_type_id, self.processed_data.tracked_events)) if type(event_state) is not EventState: self.logger.error("Event state should be EventState enum") return None if event_state == EventState.SUBMIT: timestamps = list(map(lambda x: x.submit.timestamp, trackings)) if event_state == EventState.PROC_START: timestamps = list(map(lambda x: x.proc_start_time, trackings)) if event_state == EventState.PROC_END: timestamps = list(map(lambda x: x.proc_end_time, trackings)) return timestamps def time_between_events(self, start_event_name, start_event_state, end_event_name, end_event_state, hist_bin_cnt): if not self.processed_data.tracking_execution: if start_event_state != EventState.SUBMIT or \ end_event_state != EventState.SUBMIT: self.logger.error("Events processing is not tracked: " + \ start_event_name + "->" + end_event_name) return start_times = self._get_timestamps(start_event_name, start_event_state) end_times = self._get_timestamps(end_event_name, end_event_state) if start_times is None or end_times is None: return times_between = [] for start in start_times: for end in end_times: if start < end: #converting times to ms - multiply by 1000 times_between.append((end - start) * 1000) break plt.figure() stats_text = "Max time: " stats_text += "{0:.3f}".format(max(times_between)) + "ms\n" stats_text += "Min time: " stats_text += "{0:.3f}".format(min(times_between)) + "ms\n" stats_text += "Mean time: " stats_text += "{0:.3f}".format(np.mean(times_between)) + "ms\n" ax = plt.gca() stats_textbox = ax.text(0.05, 0.95, stats_text, transform=ax.transAxes, fontsize=12, verticalalignment='top', bbox=dict(boxstyle='round', alpha=0.5, facecolor='linen')) plt.xlabel('Duration[ms]') plt.ylabel('Number of occurences') event_status_str = { EventState.SUBMIT: "submission", EventState.PROC_START: "processing start", EventState.PROC_END: "processing end" } title = "From " + start_event_name + ' ' + \ event_status_str[start_event_state] + "\nto " + \ end_event_name + ' ' + event_status_str[end_event_state] + \ ' (' + self.data_name + ')' plt.title(title) plt.hist(times_between, bins=hist_bin_cnt) plt.yscale('log') plt.grid(True)
class StatsNordic(): def __init__(self, events_filename, events_types_filename, log_lvl): self.data_name = events_filename.split('.')[0] self.processed_data = ProcessedEvents() self.processed_data.raw_data.read_data_from_files( events_filename, events_types_filename) self.processed_data.match_event_processing() self.logger = logging.getLogger('Stats Nordic') self.logger_console = logging.StreamHandler() self.logger.setLevel(log_lvl) self.log_format = logging.Formatter( '[%(levelname)s] %(name)s: %(message)s') self.logger_console.setFormatter(self.log_format) self.logger.addHandler(self.logger_console) def calculate_stats_preset1(self, start_meas, end_meas): self.time_between_events("hid_mouse_event_dongle", EventState.SUBMIT, "hid_report_sent_event_device", EventState.SUBMIT, 0.05, start_meas, end_meas) self.time_between_events("hid_mouse_event_dongle", EventState.SUBMIT, "hid_report_sent_event_device", EventState.SUBMIT, 0.05, start_meas, end_meas) self.time_between_events("hid_report_sent_event_dongle", EventState.SUBMIT, "hid_report_sent_event_dongle", EventState.SUBMIT, 0.05, start_meas, end_meas) self.time_between_events("hid_mouse_event_dongle", EventState.SUBMIT, "hid_report_sent_event_dongle", EventState.SUBMIT, 0.05, start_meas, end_meas) self.time_between_events("hid_mouse_event_device", EventState.SUBMIT, "hid_mouse_event_dongle", EventState.SUBMIT, 0.05, start_meas, end_meas) plt.show() def _get_timestamps(self, event_name, event_state, start_meas, end_meas): event_type_id = self.processed_data.raw_data.get_event_type_id( event_name) if event_type_id == None: self.logger.error("Event name not found: " + event_name) return None trackings = list( filter(lambda x: x.submit.type_id == event_type_id, self.processed_data.tracked_events)) if type(event_state) is not EventState: self.logger.error("Event state should be EventState enum") return None if event_state == EventState.SUBMIT: timestamps = np.fromiter(map(lambda x: x.submit.timestamp, trackings), dtype=np.float) elif event_state == EventState.PROC_START: timestamps = np.fromiter(map(lambda x: x.proc_start_time, trackings), dtype=np.float) elif event_state == EventState.PROC_END: timestamps = np.fromiter(map(lambda x: x.proc_end_time, trackings), dtype=np.float) timestamps = timestamps[np.where((timestamps > start_meas) & (timestamps < end_meas))] return timestamps def calculate_times_between(self, start_times, end_times): if end_times[0] <= start_times[0]: end_times = end_times[1:] if len(start_times) > len(end_times): start_times = start_times[:-1] return (end_times - start_times) * 1000 def prepare_stats_txt(self, times_between): stats_text = "Max time: " stats_text += "{0:.3f}".format(max(times_between)) + "ms\n" stats_text += "Min time: " stats_text += "{0:.3f}".format(min(times_between)) + "ms\n" stats_text += "Mean time: " stats_text += "{0:.3f}".format(np.mean(times_between)) + "ms\n" stats_text += "Std dev of time: " stats_text += "{0:.3f}".format(np.std(times_between)) + "ms\n" stats_text += "Median time: " stats_text += "{0:.3f}".format(np.median(times_between)) + "ms\n" stats_text += "Number of records: {}".format(len(times_between)) + "\n" return stats_text def time_between_events(self, start_event_name, start_event_state, end_event_name, end_event_state, hist_bin_width=0.01, start_meas=0, end_meas=float('inf')): self.logger.info("Stats calculating: {}->{}".format( start_event_name, end_event_name)) if not self.processed_data.tracking_execution: if start_event_state != EventState.SUBMIT or \ end_event_state != EventState.SUBMIT: self.logger.error("Events processing is not tracked: " + \ start_event_name + "->" + end_event_name) return start_times = self._get_timestamps(start_event_name, start_event_state, start_meas, end_meas) end_times = self._get_timestamps(end_event_name, end_event_state, start_meas, end_meas) if start_times is None or end_times is None: return if len(start_times) == 0: self.logger.error("No events logged: " + start_event_name) return if len(end_times) == 0: self.logger.error("No events logged: " + stop_event_name) return if len(start_times) != len(end_times): self.logger.error( "Number of start_times and end_times is not equal") self.logger.error("Got {} start_times and {} end_times".format( len(start_times), len(end_times))) return times_between = self.calculate_times_between(start_times, end_times) stats_text = self.prepare_stats_txt(times_between) plt.figure() ax = plt.gca() stats_textbox = ax.text(0.05, 0.95, stats_text, transform=ax.transAxes, fontsize=12, verticalalignment='top', bbox=dict(boxstyle='round', alpha=0.5, facecolor='linen')) plt.xlabel('Duration[ms]') plt.ylabel('Number of occurrences') event_status_str = { EventState.SUBMIT: "submission", EventState.PROC_START: "processing start", EventState.PROC_END: "processing end" } title = "From " + start_event_name + ' ' + \ event_status_str[start_event_state] + "\nto " + \ end_event_name + ' ' + event_status_str[end_event_state] + \ ' (' + self.data_name + ')' plt.title(title) plt.hist(times_between, bins=(int)((max(times_between) - min(times_between)) / hist_bin_width)) plt.yscale('log') plt.grid(True) dir_name = "{}{}_{}_{}/".format(OUTPUT_FOLDER, self.data_name, int(start_meas), int(end_meas)) if not os.path.exists(dir_name): os.makedirs(dir_name) plt.savefig(dir_name + title.lower().replace(' ', '_').replace('\n', '_') + '.png')
def main(): descr = "Merge data from Peripheral and Central. Synchronization events" \ " should be registered at the beginning and at the end of" \ " measurements (used to compensate clock drift)." parser = argparse.ArgumentParser(description=descr) parser.add_argument("peripheral_dataset", help="Name of Peripheral dataset") parser.add_argument("peripheral_sync_event", help="Event used for synchronization - Peripheral") parser.add_argument("central_dataset", help="Name of Central dataset") parser.add_argument("central_sync_event", help="Event used for synchronization - Central") parser.add_argument("result_dataset", help="Name for result dataset") args = parser.parse_args() evt_peripheral = ProcessedEvents() evt_peripheral.read_data_from_files(args.peripheral_dataset + ".csv", args.peripheral_dataset + ".json") evt_central = ProcessedEvents() evt_central.read_data_from_files(args.central_dataset + ".csv", args.central_dataset + ".json") # Compensating clock drift - based on synchronization events sync_evt_peripheral = evt_peripheral.get_event_type_id(args.peripheral_sync_event) sync_evt_central = evt_central.get_event_type_id(args.central_sync_event) sync_peripheral = list(filter(lambda x: x.submit.type_id == sync_evt_peripheral, evt_peripheral.tracked_events)) sync_central = list(filter(lambda x: x.submit.type_id == sync_evt_central, evt_central.tracked_events)) ts_peripheral = np.array(list(map(lambda x: list([x.submit.timestamp, x.proc_start_time, x.proc_end_time]), evt_peripheral.tracked_events))) sync_ts_peripheral = list(map(lambda x: x.submit.timestamp, sync_peripheral)) sync_ts_central = list(map(lambda x: x.submit.timestamp, sync_central)) sync_diffs_central = np.subtract(sync_ts_central[1:], sync_ts_central[:-1]) sync_diffs_peripheral = np.subtract(sync_ts_peripheral[1:], sync_ts_peripheral[:-1]) rounded_diffs_central = list(map(lambda x: round(x, 1), sync_diffs_central)) rounded_diffs_peripheral = list(map(lambda x: round(x, 1), sync_diffs_peripheral)) shift_c = rounded_diffs_central.index(rounded_diffs_peripheral[0]) shift_p = rounded_diffs_peripheral.index(rounded_diffs_central[0]) if shift_c < shift_p: sync_ts_central = sync_ts_central[shift_c:] elif shift_p < shift_c: sync_ts_peripheral = sync_ts_peripheral[shift_p:] if len(sync_ts_central) < len(sync_ts_peripheral): sync_ts_peripheral = sync_ts_peripheral[:len(sync_ts_central)] elif len(sync_ts_peripheral) < len(sync_ts_central): sync_ts_central = sync_ts_central[:len(sync_ts_peripheral)] new_ts_peripheral = ts_peripheral.copy() new_ts_peripheral[list(list(elem is not None for elem in row) for row in new_ts_peripheral)] = \ sync_peripheral_ts(ts_peripheral, sync_ts_peripheral, sync_ts_central) assert len(new_ts_peripheral) == len(ts_peripheral) # Reindexing, renaming and compensating time differences for peripheral events max_central_id = max([int(i) for i in evt_central.registered_events_types]) assert len(new_ts_peripheral) == len(evt_peripheral.tracked_events) evt_peripheral.tracked_events = list(map(lambda x, y: TrackedEvent(Event(x.submit.type_id + max_central_id + 1, y[0], x.submit.data), y[1], y[2]), evt_peripheral.tracked_events, new_ts_peripheral)) evt_peripheral.registered_events_types = {k + max_central_id + 1 : EventType(v.name + "_peripheral", v.data_types, v.data_descriptions) for k, v in evt_peripheral.registered_events_types.items()} evt_central.registered_events_types = { k : EventType(v.name + "_central", v.data_types, v.data_descriptions) for k, v in evt_central.registered_events_types.items()} # Filter out events that are out of synchronization period TIME_DIFF = 0.5 start_time = sync_ts_central[0] - TIME_DIFF end_time = sync_ts_central[-1] + TIME_DIFF evt_peripheral.tracked_events = list(filter(lambda x: x.submit.timestamp >= start_time and (x.proc_end_time <= end_time if x.proc_end_time is not None \ else x.submit.timestamp <= end_time), evt_peripheral.tracked_events)) evt_central.tracked_events = list(filter(lambda x: x.submit.timestamp >= start_time and (x.proc_end_time <= end_time if x.proc_end_time is not None \ else x.submit.timestamp <= end_time), evt_central.tracked_events)) # Filter out events that were out of interpolation range evt_peripheral.tracked_events = list(filter(lambda x: INTERP_OUT_OF_RANGE_VAL not in (x.submit.timestamp, x.proc_start_time, x.proc_end_time), evt_peripheral.tracked_events)) all_registered_events_types = evt_peripheral.registered_events_types.copy() all_registered_events_types.update(evt_central.registered_events_types) result_events = ProcessedEvents() result_events.tracked_events = evt_peripheral.tracked_events + evt_central.tracked_events result_events.registered_events_types = all_registered_events_types result_events.write_data_to_files(args.result_dataset + ".csv", args.result_dataset + ".json") print('Profiler data merged successfully')
class PlotNordic(): def __init__(self, log_lvl=logging.WARNING): plt.rcParams['toolbar'] = 'None' plt.ioff() self.plot_config = PlotNordicConfig self.draw_state = DrawState( self.plot_config['timeline_width_init'], self.plot_config['event_processing_rect_height'], self.plot_config['event_submit_markersize']) self.processed_events = ProcessedEvents() self.finish_event = None self.submitted_event_type = None self.temp_events = [] self.logger = logging.getLogger('RTT Plot Nordic') self.logger_console = logging.StreamHandler() self.logger.setLevel(log_lvl) self.log_format = logging.Formatter( '[%(levelname)s] %(name)s: %(message)s') self.logger_console.setFormatter(self.log_format) self.logger.addHandler(self.logger_console) def read_data_from_files(self, events_filename, events_types_filename): self.processed_events.raw_data.read_data_from_files( events_filename, events_types_filename) if not self.processed_events.raw_data.verify(): self.logger.warning("Missing event descriptions") def write_data_to_files(self, events_filename, events_types_filename): self.processed_events.raw_data.write_data_to_files( events_filename, events_types_filename) def on_click_start_stop(self, event): if self.draw_state.paused: if self.draw_state.l_line is not None: self.draw_state.l_line.remove() self.draw_state.l_line = None self.draw_state.l_line_coord = None if self.draw_state.r_line is not None: self.draw_state.r_line.remove() self.draw_state.r_line = None self.draw_state.r_line_coord = None if self.draw_state.duration_marker is not None: self.draw_state.duration_marker.remove() self.draw_state.paused = not self.draw_state.paused def _prepare_plot(self, selected_events_types): self.draw_state.ax = plt.gca() self.draw_state.ax.set_navigate(False) fig = plt.gcf() fig.set_size_inches(self.plot_config['window_width_inch'], self.plot_config['window_height_inch'], forward=True) fig.canvas.draw() plt.xlabel("Time [s]") plt.title("Custom events") plt.grid(True) minimum = selected_events_types[0] maximum = selected_events_types[0] ticks = [] labels = [] for j in selected_events_types: if j not in (self.processed_events.event_processing_start_id, self.processed_events.event_processing_end_id): if j > maximum: maximum = j if j < minimum: minimum = j ticks.append(j) labels.append(self.processed_events.raw_data. registered_events_types[j].name) plt.yticks(ticks, labels) # min and max range of y axis are bigger by one so markers fit nicely # on plot self.draw_state.y_max = maximum + 1 self.draw_state.y_height = maximum - minimum + 2 plt.ylim([minimum - 1, maximum + 1]) self.draw_state.selected_event_textbox = self.draw_state.ax.text( 0.05, 0.95, self.draw_state.selected_event_text, fontsize=10, transform=self.draw_state.ax.transAxes, verticalalignment='top', bbox=dict(boxstyle='round', alpha=0.5, facecolor='linen')) self.draw_state.selected_event_textbox.set_visible(False) fig.canvas.mpl_connect('scroll_event', self.scroll_event) fig.canvas.mpl_connect('button_press_event', self.button_press_event) fig.canvas.mpl_connect('button_release_event', self.button_release_event) fig.canvas.mpl_connect('resize_event', PlotNordic.resize_event) fig.canvas.mpl_connect('close_event', self.close_event) plt.tight_layout() return fig def _get_relative_coords(self, event): # relative position of plot - x0, y0, width, height ax_loc = self.draw_state.ax.get_position().bounds window_size = plt.gcf().get_size_inches() * \ plt.gcf().dpi # window size - width, height x_rel = (event.x - ax_loc[0] * window_size[0]) \ / ax_loc[2] / window_size[0] y_rel = (event.y - ax_loc[1] * window_size[1]) \ / ax_loc[3] / window_size[1] return x_rel, y_rel def scroll_event(self, event): x_rel, _ = self._get_relative_coords(event) if event.button == 'up': if self.draw_state.paused: self.draw_state.timeline_max = self.draw_state.timeline_max - (1 - x_rel) * \ (self.draw_state.timeline_width - self.draw_state.timeline_width * self.plot_config['timeline_scale_factor']) self.draw_state.timeline_width = self.draw_state.timeline_width * \ self.plot_config['timeline_scale_factor'] if event.button == 'down': if self.draw_state.paused: self.draw_state.timeline_max = self.draw_state.timeline_max + (1 - x_rel) * \ (self.draw_state.timeline_width / self.plot_config['timeline_scale_factor'] - self.draw_state.timeline_width) self.draw_state.timeline_width = self.draw_state.timeline_width / \ self.plot_config['timeline_scale_factor'] self.draw_state.ax.set_xlim( self.draw_state.timeline_max - self.draw_state.timeline_width, self.draw_state.timeline_max) plt.draw() def _find_closest_event(self, x_coord, y_coord): if self.processed_events.tracking_execution: filtered_id = list( filter(lambda x: x.submit.type_id == round(y_coord), self.processed_events.tracked_events)) if len(filtered_id) == 0: return None matching_processing = list( filter(lambda x: x.proc_start_time < x_coord < x.proc_end_time, filtered_id)) if matching_processing: return matching_processing[0] dists = list( map( lambda x: min([ abs(x.submit.timestamp - x_coord), abs(x.proc_start_time - x_coord), abs(x.proc_end_time - x_coord) ]), filtered_id)) return filtered_id[np.argmin(dists)] else: filtered_id = list( filter(lambda x: x.type_id == round(y_coord), self.processed_events.raw_data.events)) if len(filtered_id) == 0: return None dists = list(map(lambda x: abs(x.timestamp - x_coord), filtered_id)) return filtered_id[np.argmin(dists)] @staticmethod def _stringify_time(time_seconds): if time_seconds > 0.1: return '%.5f' % (time_seconds) + ' s' return '%.5f' % (1000 * time_seconds) + ' ms' def button_press_event(self, event): x_rel, y_rel = self._get_relative_coords(event) if event.button == MouseButton.LEFT.value: self.draw_state.pan_x_start1 = x_rel if event.button == MouseButton.MIDDLE.value: if self.draw_state.selected_event_submit is not None: for i in self.draw_state.selected_event_submit: i.remove() self.draw_state.selected_event_submit = None if self.draw_state.selected_event_processing is not None: self.draw_state.selected_event_processing.remove() self.draw_state.selected_event_processing = None self.draw_state.selected_event_textbox.set_visible(False) if x_rel > 1 or x_rel < 0 or y_rel > 1 or y_rel < 0: plt.draw() return coord_x = self.draw_state.timeline_max - \ (1 - x_rel) * self.draw_state.timeline_width coord_y = self.draw_state.y_max - \ (1 - y_rel) * self.draw_state.y_height selected_event = self._find_closest_event(coord_x, coord_y) if selected_event is None: return if self.processed_events.tracking_execution: event_submit = selected_event.submit else: event_submit = selected_event self.draw_state.selected_event_submit = self.draw_state.ax.plot( event_submit.timestamp, event_submit.type_id, markersize=2 * self.draw_state.event_submit_markersize, color='g', marker='o', linestyle=' ') if self.processed_events.tracking_execution: self.draw_state.selected_event_processing = matplotlib.patches.Rectangle( (selected_event.proc_start_time, selected_event.submit.type_id - self.draw_state.event_processing_rect_height), selected_event.proc_end_time - selected_event.proc_start_time, 2 * self.draw_state.event_processing_rect_height, color='g') self.draw_state.ax.add_artist( self.draw_state.selected_event_processing) self.draw_state.selected_event_text = \ self.processed_events.raw_data.registered_events_types[event_submit.type_id].name + '\n' self.draw_state.selected_event_text += 'Submit: ' + \ PlotNordic._stringify_time(event_submit.timestamp) + '\n' if self.processed_events.tracking_execution: self.draw_state.selected_event_text += 'Processing start: ' + \ PlotNordic._stringify_time( selected_event.proc_start_time) + '\n' self.draw_state.selected_event_text += 'Processing end: ' + \ PlotNordic._stringify_time( selected_event.proc_end_time) + '\n' self.draw_state.selected_event_text += 'Processing time: ' + \ PlotNordic._stringify_time(selected_event.proc_end_time - \ selected_event.proc_start_time) + '\n' ev_type = self.processed_events.raw_data.registered_events_types[ event_submit.type_id] for i in range(0, len(ev_type.data_descriptions)): if ev_type.data_descriptions[i] == 'mem_address': continue self.draw_state.selected_event_text += ev_type.data_descriptions[ i] + ' = ' self.draw_state.selected_event_text += str( event_submit.data[i]) + '\n' self.draw_state.selected_event_textbox.set_visible(True) self.draw_state.selected_event_textbox.set_text( self.draw_state.selected_event_text) plt.draw() if event.button == MouseButton.RIGHT.value: self.draw_state.pan_x_start2 = x_rel def button_release_event(self, event): x_rel, y_rel = self._get_relative_coords(event) if event.button == MouseButton.LEFT.value: if self.draw_state.paused: if abs(x_rel - self.draw_state.pan_x_start1) < 0.01: if self.draw_state.l_line is not None: self.draw_state.l_line.remove() self.draw_state.l_line = None self.draw_state.l_line_coord = None if 0 <= x_rel <= 1: if 0 <= y_rel <= 1: self.draw_state.l_line_coord = self.draw_state.timeline_max - \ (1 - x_rel) * self.draw_state.timeline_width self.draw_state.l_line = plt.axvline( self.draw_state.l_line_coord) plt.draw() else: self.draw_state.timeline_max = self.draw_state.timeline_max - \ (x_rel - self.draw_state.pan_x_start1) * \ self.draw_state.timeline_width self.draw_state.ax.set_xlim( self.draw_state.timeline_max - self.draw_state.timeline_width, self.draw_state.timeline_max) plt.draw() if event.button == MouseButton.RIGHT.value: if self.draw_state.paused: if abs(x_rel - self.draw_state.pan_x_start2) < 0.01: if self.draw_state.r_line is not None: self.draw_state.r_line.remove() self.draw_state.r_line = None self.draw_state.r_line_coord = None if 0 <= x_rel <= 1: if 0 <= y_rel <= 1: self.draw_state.r_line_coord = self.draw_state.timeline_max - \ (1 - x_rel) * self.draw_state.timeline_width self.draw_state.r_line = plt.axvline( self.draw_state.r_line_coord, color='r') plt.draw() if self.draw_state.r_line_coord is not None and self.draw_state.l_line_coord is not None: if self.draw_state.duration_marker is not None: self.draw_state.duration_marker.remove() bigger_coord = max(self.draw_state.r_line_coord, self.draw_state.l_line_coord) smaller_coord = min(self.draw_state.r_line_coord, self.draw_state.l_line_coord) self.draw_state.duration_marker = plt.annotate( s=PlotNordic._stringify_time(bigger_coord - smaller_coord), xy=(smaller_coord, 0.5), xytext=(bigger_coord, 0.5), arrowprops=dict(arrowstyle='<->')) else: if self.draw_state.duration_marker is not None: self.draw_state.duration_marker.remove() self.draw_state.duration_marker = None @staticmethod def resize_event(event): plt.tight_layout() def close_event(self, event): if self.finish_event is not None: self.finish_event.set() plt.close('all') sys.exit() def animate_events_real_time(self, fig, selected_events_types, one_line): rects = [] events = [] xranges = [] for i in range(0, len(selected_events_types)): xranges.append([]) while not self.queue.empty(): event = self.queue.get() if event is None: self.logger.info("Stopped collecting new events") self.close_event(None) if self.processed_events.tracking_execution: if event.type_id == self.processed_events.event_processing_start_id: self.processed_events.start_event = event for i in range(len(self.temp_events) - 1, -1, -1): # comparing memory addresses of event processing start # and event submit to identify matching events if self.temp_events[i].data[ 0] == self.processed_events.start_event.data[ 0]: self.processed_events.submit_event = self.temp_events[ i] events.append(self.temp_events[i]) self.submitted_event_type = self.processed_events.submit_event.type_id del self.temp_events[i] break elif event.type_id == self.processed_events.event_processing_end_id: # comparing memory addresses of event processing start and # end to identify matching events if self.submitted_event_type is not None and event.data[0] \ == self.processed_events.start_event.data[0]: rects.append( matplotlib.patches.Rectangle( (self.processed_events.start_event.timestamp, self.processed_events.submit_event.type_id - self.draw_state.event_processing_rect_height / 2), event.timestamp - self.processed_events.start_event.timestamp, self.draw_state.event_processing_rect_height, edgecolor='black')) self.processed_events.tracked_events.append( TrackedEvent( self.processed_events.submit_event, self.processed_events.start_event.timestamp, event.timestamp)) self.submitted_event_type = None else: self.temp_events.append(event) if event.timestamp > time.time() - self.start_time + self.draw_state.added_time - \ 0.2 * self.draw_state.timeline_width: self.draw_state.added_time += 0.05 if event.timestamp < time.time() - self.start_time + self.draw_state.added_time - \ 0.8 * self.draw_state.timeline_width: self.draw_state.added_time -= 0.05 events.append(event) else: events.append(event) self.processed_events.raw_data.events.append(event) # translating plot if not self.draw_state.synchronized_with_events: # ignore translating plot for stale events if not self.draw_state.stale_events_displayed: self.draw_state.stale_events_displayed = True else: # translate plot for new events if len(events) != 0: self.draw_state.added_time = events[-1].timestamp - \ 0.3 * self.draw_state.timeline_width self.draw_state.synchronized_with_events = True if not self.draw_state.paused: self.draw_state.timeline_max = time.time() - self.start_time + \ self.draw_state.added_time self.draw_state.ax.set_xlim( self.draw_state.timeline_max - self.draw_state.timeline_width, self.draw_state.timeline_max) # plotting events y = list(map(lambda x: x.type_id, events)) x = list(map(lambda x: x.timestamp, events)) self.draw_state.ax.plot( x, y, marker='o', linestyle=' ', color='r', markersize=self.draw_state.event_submit_markersize) self.draw_state.ax.add_collection(PatchCollection(rects)) plt.gcf().canvas.flush_events() def plot_events_real_time(self, queue, finish_event, selected_events_types=None, one_line=False): self.start_time = time.time() self.queue = queue self.finish_event = finish_event self.processed_events.raw_data.registered_events_types = queue.get() self.processed_events.match_event_processing() if selected_events_types is None: selected_events_types = list( self.processed_events.raw_data.registered_events_types.keys()) self.processed_events.event_processing_start_id = \ self.processed_events.raw_data.get_event_type_id('event_processing_start') self.processed_events.event_processing_end_id = \ self.processed_events.raw_data.get_event_type_id('event_processing_end') if (self.processed_events.event_processing_start_id is None) or ( self.processed_events.event_processing_end_id is None): self.processed_events.tracking_execution = False fig = self._prepare_plot(selected_events_types) self.start_stop_ax = plt.axes([0.8, 0.025, 0.1, 0.04]) self.start_stop_button = Button(self.start_stop_ax, 'Start/Stop') self.start_stop_button.on_clicked(self.on_click_start_stop) plt.sca(self.draw_state.ax) self.ani = animation.FuncAnimation( fig, self.animate_events_real_time, fargs=[selected_events_types, one_line], interval=self.plot_config['refresh_time']) plt.show() def plot_events_from_file(self, selected_events_types=None, one_line=False): self.draw_state.paused = True if len(self.processed_events.raw_data.events) == 0 or \ len(self.processed_events.raw_data.registered_events_types) == 0: self.logger.error("Please read some events data before plotting") if selected_events_types is None: selected_events_types = list( self.processed_events.raw_data.registered_events_types.keys()) self.processed_events.match_event_processing() self._prepare_plot(selected_events_types) x = list( map(lambda x: x.submit.timestamp, self.processed_events.tracked_events)) y = list( map(lambda x: x.submit.type_id, self.processed_events.tracked_events)) self.draw_state.ax.plot( x, y, marker='o', linestyle=' ', color='r', markersize=self.draw_state.event_submit_markersize) if self.processed_events.tracking_execution: rects = [] for ev in self.processed_events.tracked_events: rects.append( matplotlib.patches.Rectangle( (ev.proc_start_time, ev.submit.type_id - self.draw_state.event_processing_rect_height / 2), ev.proc_end_time - ev.proc_start_time, self.draw_state.event_processing_rect_height, edgecolor='black')) self.draw_state.ax.add_collection(PatchCollection(rects)) self.draw_state.timeline_max = max(x) + 1 self.draw_state.timeline_width = max(x) - min(x) + 2 self.draw_state.ax.set_xlim([min(x) - 1, max(x) + 1]) plt.draw() plt.show()
class PlotNordic(): def __init__(self, stream=None, event_close=None, log_lvl=logging.WARNING): plt.rcParams['toolbar'] = 'None' plt.ioff() self.plot_config = PlotNordicConfig self.draw_state = DrawState( self.plot_config['timeline_width_init'], self.plot_config['event_processing_rect_height'], self.plot_config['event_submit_markersize']) self.ani = None self.close_event_flag = False self.processed_events = ProcessedEvents() if stream is not None: timeouts = { 'descriptions': 1, 'events': 0 } self.in_stream = stream self.in_stream.set_timeouts(timeouts) if event_close is not None: self.event_close = event_close self.logger = logging.getLogger('Plot Nordic') self.logger_console = logging.StreamHandler() self.logger.setLevel(log_lvl) self.log_format = logging.Formatter( '[%(levelname)s] %(name)s: %(message)s') self.logger_console.setFormatter(self.log_format) self.logger.addHandler(self.logger_console) def read_data_from_files(self, events_filename, events_types_filename): self.processed_events.read_data_from_files( events_filename, events_types_filename) if not self.processed_events.verify(): self.logger.warning("Missing event descriptions") def on_click_start_stop(self, event): if self.draw_state.paused: if self.draw_state.l_line is not None: self.draw_state.l_line.remove() self.draw_state.l_line = None self.draw_state.l_line_coord = None if self.draw_state.r_line is not None: self.draw_state.r_line.remove() self.draw_state.r_line = None self.draw_state.r_line_coord = None if self.draw_state.duration_marker is not None: self.draw_state.duration_marker.remove() self.draw_state.paused = not self.draw_state.paused def _prepare_plot(self, selected_events_types): self.draw_state.ax = plt.gca() self.draw_state.ax.set_navigate(False) fig = plt.gcf() fig.set_size_inches( self.plot_config['window_width_inch'], self.plot_config['window_height_inch'], forward=True) fig.canvas.draw() plt.xlabel("Time [s]") plt.title("Custom events") plt.grid(True) minimum = min(selected_events_types) maximum = max(selected_events_types) ticks = [] labels = [] for j in selected_events_types: ticks.append(j) labels.append(self.processed_events.registered_events_types[j].name) plt.yticks(ticks, labels) # min and max range of y axis are bigger by one so markers fit nicely # on plot self.draw_state.y_max = maximum + 1 self.draw_state.y_height = maximum - minimum + 2 plt.ylim([minimum - 1, maximum + 1]) self.draw_state.selected_event_textbox = self.draw_state.ax.text( 0.05, 0.95, self.draw_state.selected_event_text, fontsize=10, transform=self.draw_state.ax.transAxes, verticalalignment='top', bbox=dict( boxstyle='round', alpha=0.5, facecolor='linen')) self.draw_state.selected_event_textbox.set_visible(False) fig.canvas.mpl_connect('scroll_event', self.scroll_event) fig.canvas.mpl_connect('button_press_event', self.button_press_event) fig.canvas.mpl_connect('button_release_event', self.button_release_event) fig.canvas.mpl_connect('resize_event', PlotNordic.resize_event) fig.canvas.mpl_connect('close_event', self.close_event) plt.tight_layout() return fig def _get_relative_coords(self, event): # relative position of plot - x0, y0, width, height ax_loc = self.draw_state.ax.get_position().bounds window_size = plt.gcf().get_size_inches() * \ plt.gcf().dpi # window size - width, height x_rel = (event.x - ax_loc[0] * window_size[0]) \ / ax_loc[2] / window_size[0] y_rel = (event.y - ax_loc[1] * window_size[1]) \ / ax_loc[3] / window_size[1] return x_rel, y_rel def scroll_event(self, event): x_rel, _ = self._get_relative_coords(event) if event.button == 'up': if self.draw_state.paused: self.draw_state.timeline_max = self.draw_state.timeline_max - (1 - x_rel) * \ (self.draw_state.timeline_width - self.draw_state.timeline_width * self.plot_config['timeline_scale_factor']) self.draw_state.timeline_width = self.draw_state.timeline_width * \ self.plot_config['timeline_scale_factor'] if event.button == 'down': if self.draw_state.paused: self.draw_state.timeline_max = self.draw_state.timeline_max + (1 - x_rel) * \ (self.draw_state.timeline_width / self.plot_config['timeline_scale_factor'] - self.draw_state.timeline_width) self.draw_state.timeline_width = self.draw_state.timeline_width / \ self.plot_config['timeline_scale_factor'] self.draw_state.ax.set_xlim( self.draw_state.timeline_max - self.draw_state.timeline_width, self.draw_state.timeline_max) plt.draw() def _find_closest_event(self, x_coord, y_coord): filtered_id = list(filter(lambda x: x.submit.type_id == round(y_coord), self.processed_events.tracked_events)) if len(filtered_id) == 0: return None if not self.processed_events.is_event_tracked(round(y_coord)): dists = list(map(lambda x: abs(x.submit.timestamp - x_coord), filtered_id)) return filtered_id[np.argmin(dists)] else: matching_processing = list( filter( lambda x: x.proc_start_time < x_coord < x.proc_end_time, filtered_id)) if matching_processing: return matching_processing[0] dists = list(map(lambda x: min([abs(x.submit.timestamp - x_coord), abs(x.proc_start_time - x_coord), abs(x.proc_end_time - x_coord)]), filtered_id)) return filtered_id[np.argmin(dists)] @staticmethod def _stringify_time(time_seconds): if time_seconds > 0.1: return '%.5f' % (time_seconds) + ' s' return '%.5f' % (1000 * time_seconds) + ' ms' def button_press_event(self, event): x_rel, y_rel = self._get_relative_coords(event) if event.button == MouseButton.LEFT.value: self.draw_state.pan_x_start1 = x_rel if event.button == MouseButton.MIDDLE.value: if self.draw_state.selected_event_submit is not None: for i in self.draw_state.selected_event_submit: i.remove() self.draw_state.selected_event_submit = None if self.draw_state.selected_event_processing is not None: self.draw_state.selected_event_processing.remove() self.draw_state.selected_event_processing = None self.draw_state.selected_event_textbox.set_visible(False) if x_rel > 1 or x_rel < 0 or y_rel > 1 or y_rel < 0: plt.draw() return coord_x = self.draw_state.timeline_max - \ (1 - x_rel) * self.draw_state.timeline_width coord_y = self.draw_state.y_max - \ (1 - y_rel) * self.draw_state.y_height selected_event = self._find_closest_event(coord_x, coord_y) if selected_event is None: return event_submit = selected_event.submit self.draw_state.selected_event_submit = self.draw_state.ax.plot( event_submit.timestamp, event_submit.type_id, markersize=2*self.draw_state.event_submit_markersize, color='g', marker='o', linestyle=' ') if selected_event.proc_start_time is not None: self.draw_state.selected_event_processing = matplotlib.patches.Rectangle( (selected_event.proc_start_time, selected_event.submit.type_id - self.draw_state.event_processing_rect_height), selected_event.proc_end_time - selected_event.proc_start_time, 2*self.draw_state.event_processing_rect_height, color='g') self.draw_state.ax.add_artist( self.draw_state.selected_event_processing) self.draw_state.selected_event_text = \ self.processed_events.registered_events_types[event_submit.type_id].name + '\n' self.draw_state.selected_event_text += 'Submit: ' + \ PlotNordic._stringify_time(event_submit.timestamp) + '\n' if selected_event.proc_start_time is not None: self.draw_state.selected_event_text += 'Processing start: ' + \ PlotNordic._stringify_time( selected_event.proc_start_time) + '\n' self.draw_state.selected_event_text += 'Processing end: ' + \ PlotNordic._stringify_time( selected_event.proc_end_time) + '\n' self.draw_state.selected_event_text += 'Processing time: ' + \ PlotNordic._stringify_time(selected_event.proc_end_time - \ selected_event.proc_start_time) + '\n' ev_type = self.processed_events.registered_events_types[event_submit.type_id] for i in range(0, len(ev_type.data_descriptions)): if ev_type.data_descriptions[i] == EM_MEM_ADDRESS_DATA_DESC: continue self.draw_state.selected_event_text += ev_type.data_descriptions[i] + ' = ' self.draw_state.selected_event_text += str(event_submit.data[i]) + '\n' self.draw_state.selected_event_textbox.set_visible(True) self.draw_state.selected_event_textbox.set_text( self.draw_state.selected_event_text) plt.draw() if event.button == MouseButton.RIGHT.value: self.draw_state.pan_x_start2 = x_rel def button_release_event(self, event): x_rel, y_rel = self._get_relative_coords(event) if event.button == MouseButton.LEFT.value: if self.draw_state.paused: if abs(x_rel - self.draw_state.pan_x_start1) < 0.01: if self.draw_state.l_line is not None: self.draw_state.l_line.remove() self.draw_state.l_line = None self.draw_state.l_line_coord = None if 0 <= x_rel <= 1: if 0 <= y_rel <= 1: self.draw_state.l_line_coord = self.draw_state.timeline_max - \ (1 - x_rel) * self.draw_state.timeline_width self.draw_state.l_line = plt.axvline( self.draw_state.l_line_coord) plt.draw() else: self.draw_state.timeline_max = self.draw_state.timeline_max - \ (x_rel - self.draw_state.pan_x_start1) * \ self.draw_state.timeline_width self.draw_state.ax.set_xlim( self.draw_state.timeline_max - self.draw_state.timeline_width, self.draw_state.timeline_max) plt.draw() if event.button == MouseButton.RIGHT.value: if self.draw_state.paused: if abs(x_rel - self.draw_state.pan_x_start2) < 0.01: if self.draw_state.r_line is not None: self.draw_state.r_line.remove() self.draw_state.r_line = None self.draw_state.r_line_coord = None if 0 <= x_rel <= 1: if 0 <= y_rel <= 1: self.draw_state.r_line_coord = self.draw_state.timeline_max - \ (1 - x_rel) * self.draw_state.timeline_width self.draw_state.r_line = plt.axvline( self.draw_state.r_line_coord, color='r') plt.draw() if self.draw_state.r_line_coord is not None and self.draw_state.l_line_coord is not None: if self.draw_state.duration_marker is not None: self.draw_state.duration_marker.remove() bigger_coord = max( self.draw_state.r_line_coord, self.draw_state.l_line_coord) smaller_coord = min( self.draw_state.r_line_coord, self.draw_state.l_line_coord) self.draw_state.duration_marker = plt.annotate( text=PlotNordic._stringify_time( bigger_coord - smaller_coord), xy=( smaller_coord, 0.5), xytext=( bigger_coord, 0.5), arrowprops=dict( arrowstyle='<->')) else: if self.draw_state.duration_marker is not None: self.draw_state.duration_marker.remove() self.draw_state.duration_marker = None @staticmethod def resize_event(event): plt.tight_layout() def close_event(self, event): self.close_event_flag = True def animate_events_real_time(self, fig): rects = [] events = [] #Receive events while True: try: data = self.in_stream.recv_ev() except StreamError as err: if err.args[1] == StreamError.TIMEOUT_MSG: break self.logger.error("Receiving error: {}. Exiting".format(err)) self.close_event(None) sys.exit() data_str = data.decode() tracked_event = TrackedEvent.deserialize(data_str) events.append(tracked_event.submit) self.processed_events.tracked_events.append(tracked_event) if tracked_event.proc_start_time is not None: assert tracked_event.proc_end_time is not None rects.append( matplotlib.patches.Rectangle( (tracked_event.proc_start_time, tracked_event.submit.type_id - self.draw_state.event_processing_rect_height/2), tracked_event.proc_end_time - tracked_event.proc_start_time, self.draw_state.event_processing_rect_height, edgecolor='black')) # translating plot if not self.draw_state.synchronized_with_events: # ignore translating plot for stale events if not self.draw_state.stale_events_displayed: self.draw_state.stale_events_displayed = True else: # translate plot for new events if len(events) != 0: self.draw_state.added_time = events[-1].timestamp - \ 0.3 * self.draw_state.timeline_width self.draw_state.synchronized_with_events = True if not self.draw_state.paused: self.draw_state.timeline_max = time.time() - self.start_time + \ self.draw_state.added_time self.draw_state.ax.set_xlim( self.draw_state.timeline_max - self.draw_state.timeline_width, self.draw_state.timeline_max) # plotting events y = list(map(lambda x: x.type_id, events)) x = list(map(lambda x: x.timestamp, events)) self.draw_state.ax.plot( x, y, marker='o', linestyle=' ', color='r', markersize=self.draw_state.event_submit_markersize) self.draw_state.ax.add_collection(PatchCollection(rects)) plt.gcf().canvas.flush_events() if self.event_close.is_set(): self.close_event(None) if self.close_event_flag: sys.exit() def plot_events_real_time(self, selected_events_types=None): self.start_time = time.time() #Receive event descriptions while True: try: bytes = self.in_stream.recv_desc() break except StreamError as err: if err.args[1] == StreamError.TIMEOUT_MSG: if self.event_close.is_set(): self.logger.info("Module closed before receiving event descriptions.") sys.exit() continue self.logger.error("Receiving error: {}. Exiting".format(err)) sys.exit() data_str = bytes.decode() event_types_dict = json.loads(data_str) self.processed_events.registered_events_types = dict((int(k), EventType.deserialize(v)) for k, v in event_types_dict.items()) if self.processed_events.registered_events_types is None: self.logger.error("Event descriptors not sent properly") sys.exit() if selected_events_types is None: selected_events_types = list( self.processed_events.registered_events_types.keys()) fig = self._prepare_plot(selected_events_types) self.start_stop_ax = plt.axes([0.8, 0.025, 0.1, 0.04]) self.start_stop_button = Button(self.start_stop_ax, 'Start/Stop') self.start_stop_button.on_clicked(self.on_click_start_stop) plt.sca(self.draw_state.ax) self.ani = animation.FuncAnimation( fig, self.animate_events_real_time, interval=self.plot_config['refresh_time']) plt.show() def plot_events_from_file( self, selected_events_types=None, one_line=False): self.draw_state.paused = True if len(self.processed_events.tracked_events) == 0 or \ len(self.processed_events.registered_events_types) == 0: self.logger.error("Please read some events data before plotting") if selected_events_types is None: selected_events_types = list( self.processed_events.registered_events_types.keys()) self._prepare_plot(selected_events_types) x = list(map(lambda x: x.submit.timestamp, self.processed_events.tracked_events)) y = list(map(lambda x: x.submit.type_id, self.processed_events.tracked_events)) self.draw_state.ax.plot( x, y, marker='o', linestyle=' ', color='r', markersize=self.draw_state.event_submit_markersize) rects = [] for ev in self.processed_events.tracked_events: if ev.proc_start_time is None: continue rects.append( matplotlib.patches.Rectangle( (ev.proc_start_time, ev.submit.type_id - self.draw_state.event_processing_rect_height/2), ev.proc_end_time - ev.proc_start_time, self.draw_state.event_processing_rect_height, edgecolor='black')) self.draw_state.ax.add_collection(PatchCollection(rects)) self.draw_state.timeline_max = max(x) + 1 self.draw_state.timeline_width = max(x) - min(x) + 2 self.draw_state.ax.set_xlim([min(x) - 1, max(x) + 1]) plt.draw() plt.show()