def _process_without_pandas(self, measurements_csv): per_frame_fps = [] start_vsync, end_vsync = None, None frame_count = 0 for frame_data in measurements_csv.iter_values(): if frame_data.Flags_flags != 0: continue frame_count += 1 if start_vsync is None: start_vsync = frame_data.Vsync_time_us end_vsync = frame_data.Vsync_time_us frame_time = frame_data.FrameCompleted_time_us - frame_data.IntendedVsync_time_us pff = 1e9 / frame_time if pff > self.drop_threshold: per_frame_fps.append([pff]) if frame_count: duration = end_vsync - start_vsync fps = (1e6 * frame_count) / float(duration) else: duration = 0 fps = 0 csv_file = self._get_csv_file_name(measurements_csv.path) with csvwriter(csv_file) as writer: writer.writerow(['fps']) writer.writerows(per_frame_fps) return [DerivedMetric('fps', fps, 'fps'), DerivedMetric('total_frames', frame_count, 'frames'), MeasurementsCsv(csv_file)]
def get_data(self, outfile): if os.stat(self.raw_data_file).st_size == 0: self.logger.warning('"{}" appears to be empty'.format( self.raw_data_file)) return all_channels = [c.label for c in self.list_channels()] active_channels = [c.label for c in self.active_channels] active_indexes = [all_channels.index(ac) for ac in active_channels] with csvreader(self.raw_data_file, skipinitialspace=True) as reader: with csvwriter(outfile) as writer: writer.writerow(active_channels) header = next(reader) ts_index = header.index('timestamp ms') for row in reader: output_row = [] for i in active_indexes: if i == ts_index: # Leave time in ms output_row.append(float(row[i])) else: # Convert rest into standard units. output_row.append(float(row[i]) / 1000) writer.writerow(output_row) return MeasurementsCsv(outfile, self.active_channels, self.sample_rate_hz)
def _process_with_pandas(self, measurements_csv): data = pd.read_csv(measurements_csv.path) data = data[data.Flags_flags == 0] frame_time = data.FrameCompleted_time_us - data.IntendedVsync_time_us per_frame_fps = (1e6 / frame_time) keep_filter = per_frame_fps > self.drop_threshold per_frame_fps = per_frame_fps[keep_filter] per_frame_fps.name = 'fps' frame_count = data.index.size if frame_count > 1: duration = data.Vsync_time_us.iloc[-1] - data.Vsync_time_us.iloc[0] fps = (1e9 * frame_count) / float(duration) else: duration = 0 fps = 0 csv_file = self._get_csv_file_name(measurements_csv.path) per_frame_fps.to_csv(csv_file, index=False, header=True) return [ DerivedMetric('fps', fps, 'fps'), DerivedMetric('total_frames', frame_count, 'frames'), MeasurementsCsv(csv_file) ]
def _process_with_pandas(self, measurements_csv): data = pd.read_csv(measurements_csv.path) # fiter out bogus frames. bogus_frames_filter = data.actual_present_time_us != 0x7fffffffffffffff actual_present_times = data.actual_present_time_us[bogus_frames_filter] actual_present_time_deltas = actual_present_times.diff().dropna() vsyncs_to_compose = actual_present_time_deltas.div(VSYNC_INTERVAL) vsyncs_to_compose.apply(lambda x: int(round(x, 0))) # drop values lower than drop_threshold FPS as real in-game frame # rate is unlikely to drop below that (except on loading screens # etc, which should not be factored in frame rate calculation). per_frame_fps = (1.0 / (vsyncs_to_compose.multiply(VSYNC_INTERVAL / 1e9))) keep_filter = per_frame_fps > self.drop_threshold filtered_vsyncs_to_compose = vsyncs_to_compose[keep_filter] per_frame_fps.name = 'fps' csv_file = self._get_csv_file_name(measurements_csv.path) per_frame_fps.to_csv(csv_file, index=False, header=True) if not filtered_vsyncs_to_compose.empty: fps = 0 total_vsyncs = filtered_vsyncs_to_compose.sum() frame_count = filtered_vsyncs_to_compose.size if total_vsyncs: fps = 1e9 * frame_count / (VSYNC_INTERVAL * total_vsyncs) janks = self._calc_janks(filtered_vsyncs_to_compose) not_at_vsync = self._calc_not_at_vsync(vsyncs_to_compose) else: fps = 0 frame_count = 0 janks = 0 not_at_vsync = 0 janks_pc = 0 if frame_count == 0 else janks * 100 / frame_count return [ DerivedMetric('fps', fps, 'fps'), DerivedMetric('total_frames', frame_count, 'frames'), MeasurementsCsv(csv_file), DerivedMetric('janks', janks, 'count'), DerivedMetric('janks_pc', janks_pc, 'percent'), DerivedMetric('missed_vsync', not_at_vsync, 'count') ]
def process(self, measurements_csv): if isinstance(measurements_csv, basestring): measurements_csv = MeasurementsCsv(measurements_csv) if pd is not None: return self._process_with_pandas(measurements_csv) return self._process_without_pandas(measurements_csv)
def get_data(self, outfile=None, **to_csv_kwargs): if outfile is None: return self.data self.data.to_csv(outfile, **to_csv_kwargs) return MeasurementsCsv(outfile, self.active_channels)