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 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.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 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.get_event_type_id(event_name) if event_type_id is None: self.logger.error("Event name not found: " + event_name) return None if not self.processed_data.is_event_tracked(event_type_id) and event_state != EventState.SUBMIT: self.logger.error("This event is not tracked: " + event_name) return None trackings = list(filter(lambda x: x.submit.type_id == event_type_id, self.processed_data.tracked_events)) if not isinstance(event_state, 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 @staticmethod def calculate_times_between(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 @staticmethod def prepare_stats_txt(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)) 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: " + end_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() 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) if end_meas == float('inf'): end_meas_string = 'inf' else: end_meas_string = int(end_meas) dir_name = "{}{}_{}_{}/".format(OUTPUT_FOLDER, self.data_name, int(start_meas), end_meas_string) if not os.path.exists(dir_name): os.makedirs(dir_name) plt.savefig(dir_name + title.lower().replace(' ', '_').replace('\n', '_') +'.png')