Refactor GPU performance measurement
This commit is contained in:
parent
61833168e5
commit
661da5e12b
|
@ -0,0 +1,227 @@
|
||||||
|
// pathfinder/renderer/src/gpu/perf.rs
|
||||||
|
//
|
||||||
|
// Copyright © 2020 The Pathfinder Project Developers.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! Performance monitoring infrastructure.
|
||||||
|
|
||||||
|
use pathfinder_gpu::Device;
|
||||||
|
use std::mem;
|
||||||
|
use std::ops::{Add, Div};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
pub struct RenderStats {
|
||||||
|
pub path_count: usize,
|
||||||
|
pub fill_count: usize,
|
||||||
|
pub alpha_tile_count: usize,
|
||||||
|
pub total_tile_count: usize,
|
||||||
|
pub cpu_build_time: Duration,
|
||||||
|
pub drawcall_count: u32,
|
||||||
|
pub gpu_bytes_allocated: u64,
|
||||||
|
pub gpu_bytes_committed: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<RenderStats> for RenderStats {
|
||||||
|
type Output = RenderStats;
|
||||||
|
fn add(self, other: RenderStats) -> RenderStats {
|
||||||
|
RenderStats {
|
||||||
|
path_count: self.path_count + other.path_count,
|
||||||
|
alpha_tile_count: self.alpha_tile_count + other.alpha_tile_count,
|
||||||
|
total_tile_count: self.total_tile_count + other.total_tile_count,
|
||||||
|
fill_count: self.fill_count + other.fill_count,
|
||||||
|
cpu_build_time: self.cpu_build_time + other.cpu_build_time,
|
||||||
|
drawcall_count: self.drawcall_count + other.drawcall_count,
|
||||||
|
gpu_bytes_allocated: self.gpu_bytes_allocated + other.gpu_bytes_allocated,
|
||||||
|
gpu_bytes_committed: self.gpu_bytes_committed + other.gpu_bytes_committed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div<usize> for RenderStats {
|
||||||
|
type Output = RenderStats;
|
||||||
|
fn div(self, divisor: usize) -> RenderStats {
|
||||||
|
RenderStats {
|
||||||
|
path_count: self.path_count / divisor,
|
||||||
|
alpha_tile_count: self.alpha_tile_count / divisor,
|
||||||
|
total_tile_count: self.total_tile_count / divisor,
|
||||||
|
fill_count: self.fill_count / divisor,
|
||||||
|
cpu_build_time: self.cpu_build_time / divisor as u32,
|
||||||
|
drawcall_count: self.drawcall_count / divisor as u32,
|
||||||
|
gpu_bytes_allocated: self.gpu_bytes_allocated / divisor as u64,
|
||||||
|
gpu_bytes_committed: self.gpu_bytes_committed / divisor as u64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct TimerQueryCache<D> where D: Device {
|
||||||
|
free_queries: Vec<D::TimerQuery>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct PendingTimer<D> where D: Device {
|
||||||
|
pub(crate) dice_times: Vec<TimerFuture<D>>,
|
||||||
|
pub(crate) bin_times: Vec<TimerFuture<D>>,
|
||||||
|
pub(crate) fill_times: Vec<TimerFuture<D>>,
|
||||||
|
pub(crate) composite_times: Vec<TimerFuture<D>>,
|
||||||
|
pub(crate) other_times: Vec<TimerFuture<D>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) enum TimerFuture<D> where D: Device {
|
||||||
|
Pending(D::TimerQuery),
|
||||||
|
Resolved(Duration),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> TimerQueryCache<D> where D: Device {
|
||||||
|
pub(crate) fn new() -> TimerQueryCache<D> {
|
||||||
|
TimerQueryCache { free_queries: vec![] }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn alloc(&mut self, device: &D) -> D::TimerQuery {
|
||||||
|
self.free_queries.pop().unwrap_or_else(|| device.create_timer_query())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn free(&mut self, old_query: D::TimerQuery) {
|
||||||
|
self.free_queries.push(old_query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> PendingTimer<D> where D: Device {
|
||||||
|
pub(crate) fn new() -> PendingTimer<D> {
|
||||||
|
PendingTimer {
|
||||||
|
dice_times: vec![],
|
||||||
|
bin_times: vec![],
|
||||||
|
fill_times: vec![],
|
||||||
|
composite_times: vec![],
|
||||||
|
other_times: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn poll(&mut self, device: &D) -> Vec<D::TimerQuery> {
|
||||||
|
let mut old_queries = vec![];
|
||||||
|
for future in self.dice_times.iter_mut().chain(self.bin_times.iter_mut())
|
||||||
|
.chain(self.fill_times.iter_mut())
|
||||||
|
.chain(self.composite_times.iter_mut())
|
||||||
|
.chain(self.other_times.iter_mut()) {
|
||||||
|
if let Some(old_query) = future.poll(device) {
|
||||||
|
old_queries.push(old_query)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
old_queries
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn total_time(&self) -> Option<RenderTime> {
|
||||||
|
let dice_time = total_time_of_timer_futures(&self.dice_times);
|
||||||
|
let bin_time = total_time_of_timer_futures(&self.bin_times);
|
||||||
|
let fill_time = total_time_of_timer_futures(&self.fill_times);
|
||||||
|
let composite_time = total_time_of_timer_futures(&self.composite_times);
|
||||||
|
let other_time = total_time_of_timer_futures(&self.other_times);
|
||||||
|
match (dice_time, bin_time, fill_time, composite_time, other_time) {
|
||||||
|
(Some(dice_time),
|
||||||
|
Some(bin_time),
|
||||||
|
Some(fill_time),
|
||||||
|
Some(composite_time),
|
||||||
|
Some(other_time)) => {
|
||||||
|
Some(RenderTime { dice_time, bin_time, fill_time, composite_time, other_time })
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> TimerFuture<D> where D: Device {
|
||||||
|
pub(crate) fn new(query: D::TimerQuery) -> TimerFuture<D> {
|
||||||
|
TimerFuture::Pending(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll(&mut self, device: &D) -> Option<D::TimerQuery> {
|
||||||
|
let duration = match *self {
|
||||||
|
TimerFuture::Pending(ref query) => device.try_recv_timer_query(query),
|
||||||
|
TimerFuture::Resolved(_) => None,
|
||||||
|
};
|
||||||
|
match duration {
|
||||||
|
None => None,
|
||||||
|
Some(duration) => {
|
||||||
|
match mem::replace(self, TimerFuture::Resolved(duration)) {
|
||||||
|
TimerFuture::Resolved(_) => unreachable!(),
|
||||||
|
TimerFuture::Pending(old_query) => Some(old_query),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn total_time_of_timer_futures<D>(futures: &[TimerFuture<D>]) -> Option<Duration> where D: Device {
|
||||||
|
let mut total = Duration::default();
|
||||||
|
for future in futures {
|
||||||
|
match *future {
|
||||||
|
TimerFuture::Pending(_) => return None,
|
||||||
|
TimerFuture::Resolved(time) => total += time,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(total)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct RenderTime {
|
||||||
|
pub dice_time: Duration,
|
||||||
|
pub bin_time: Duration,
|
||||||
|
pub fill_time: Duration,
|
||||||
|
pub composite_time: Duration,
|
||||||
|
pub other_time: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderTime {
|
||||||
|
#[inline]
|
||||||
|
pub fn total_time(&self) -> Duration {
|
||||||
|
self.dice_time + self.bin_time + self.fill_time + self.composite_time + self.other_time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for RenderTime {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> RenderTime {
|
||||||
|
RenderTime {
|
||||||
|
dice_time: Duration::new(0, 0),
|
||||||
|
bin_time: Duration::new(0, 0),
|
||||||
|
fill_time: Duration::new(0, 0),
|
||||||
|
composite_time: Duration::new(0, 0),
|
||||||
|
other_time: Duration::new(0, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<RenderTime> for RenderTime {
|
||||||
|
type Output = RenderTime;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(self, other: RenderTime) -> RenderTime {
|
||||||
|
RenderTime {
|
||||||
|
dice_time: self.dice_time + other.dice_time,
|
||||||
|
bin_time: self.bin_time + other.bin_time,
|
||||||
|
fill_time: self.fill_time + other.fill_time,
|
||||||
|
composite_time: self.composite_time + other.composite_time,
|
||||||
|
other_time: self.other_time + other.other_time,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div<usize> for RenderTime {
|
||||||
|
type Output = RenderTime;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn div(self, divisor: usize) -> RenderTime {
|
||||||
|
let divisor = divisor as u32;
|
||||||
|
RenderTime {
|
||||||
|
dice_time: self.dice_time / divisor,
|
||||||
|
bin_time: self.bin_time / divisor,
|
||||||
|
fill_time: self.fill_time / divisor,
|
||||||
|
composite_time: self.composite_time / divisor,
|
||||||
|
other_time: self.other_time / divisor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue