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_ns end_vsync = frame_data.Vsync_time_ns frame_time = frame_data.FrameCompleted_time_ns - frame_data.IntendedVsync_time_ns pff = 1e9 / frame_time if pff > self.drop_threshold: per_frame_fps.append([pff]) if frame_count: duration = end_vsync - start_vsync fps = (1e9 * 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 process_raw(filepath, *args): metrics = [] dump = gfxinfo_get_last_dump(filepath) seen_stats = False for line in dump.split('\n'): if seen_stats and not line.strip(): break elif line.startswith('Janky frames:'): text = line.split(': ')[-1] val_text, pc_text = text.split('(') metrics.append(DerivedMetric('janks', numeric(val_text.strip()), 'count')) metrics.append(DerivedMetric('janks_pc', numeric(pc_text[:-3]), 'percent')) elif ' percentile: ' in line: ptile, val_text = line.split(' percentile: ') name = 'render_time_{}_ptile'.format(ptile) value = numeric(val_text.strip()[:-2]) metrics.append(DerivedMetric(name, value, 'time_ms')) elif line.startswith('Number '): name_text, val_text = line.strip().split(': ') name = name_text[7:].lower().replace(' ', '_') value = numeric(val_text) metrics.append(DerivedMetric(name, value, 'count')) else: continue seen_stats = True return metrics
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_with_pandas(self, measurements_csv): data = pd.read_csv(measurements_csv.path) data = data[data.Flags_flags == 0] frame_time = data.FrameCompleted_time_ns - data.IntendedVsync_time_ns per_frame_fps = (1e9 / 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_ns.iloc[-1] - data.Vsync_time_ns.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(measurements_csv): should_calculate_energy = [] use_timestamp = False # Determine sites to calculate energy for channel_map = defaultdict(list) for channel in measurements_csv.channels: channel_map[channel.site].append(channel.kind) if channel.site == 'timestamp': use_timestamp = True time_measurment = channel.measurement_type for site, kinds in channel_map.items(): if 'power' in kinds and not 'energy' in kinds: should_calculate_energy.append(site) if measurements_csv.sample_rate_hz is None and not use_timestamp: msg = 'Timestamp data is unavailable, please provide a sample rate' raise ValueError(msg) if use_timestamp: # Find index of timestamp column ts_index = [ i for i, chan in enumerate(measurements_csv.channels) if chan.site == 'timestamp' ] if len(ts_index) > 1: raise ValueError('Multiple timestamps detected') ts_index = ts_index[0] row_ts = 0 last_ts = 0 energy_results = defaultdict(dict) power_results = defaultdict(float) # Process data for count, row in enumerate(measurements_csv.iter_measurements()): if use_timestamp: last_ts = row_ts row_ts = time_measurment.convert(float(row[ts_index].value), 'time') for entry in row: channel = entry.channel site = channel.site if channel.kind == 'energy': if count == 0: energy_results[site]['start'] = entry.value else: energy_results[site]['end'] = entry.value if channel.kind == 'power': power_results[site] += entry.value if site in should_calculate_energy: if count == 0: energy_results[site]['start'] = 0 energy_results[site]['end'] = 0 elif use_timestamp: energy_results[site]['end'] += entry.value * ( row_ts - last_ts) else: energy_results[site]['end'] += entry.value * ( 1 / measurements_csv.sample_rate_hz) # Calculate final measurements derived_measurements = [] for site in energy_results: total_energy = energy_results[site]['end'] - energy_results[site][ 'start'] name = '{}_total_energy'.format(site) derived_measurements.append( DerivedMetric(name, total_energy, MEASUREMENT_TYPES['energy'])) for site in power_results: power = power_results[site] / (count + 1) #pylint: disable=undefined-loop-variable name = '{}_average_power'.format(site) derived_measurements.append( DerivedMetric(name, power, MEASUREMENT_TYPES['power'])) return derived_measurements