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