Author: eilemann@gmail.com
State:
- Implemented in 0.9
Overview
Cross-segment load balancing allocates resources (GPUs) dynamically to a set of destination channels. Normally all destination channels managed by a view equalizer belong to multiple segments (displays) of a single view.
A configuration with cross-segment load balancing is hierarchical. The top-level compound has a view equalizer. Each child of this root compound has one destination channel and a load equalizer. Each destination channel compound has the potential leaf nodes executing the rendering. One resource is normally used in multiple leaf nodes of different destination compounds.
For each frame, the view equalizer sets the usage of each leaf compound to activate or deactivate it for rendering. The load equalizer assigns work to each leaf compound according to its allowed usage.
The Figure on the right depicts a snapshot of a simple cross-segment load balancing setup. Two destination channel, each connected to a projector, create the final output. Each projector is driven be a distinct GPU. Each GPU can potentially contribute to the rendering of the other segment (and GPU) through the channels Source 1 and 2.
The left segment has a lower load than the right segment. Consequently, the view equalizer assigns 80% of the 'left' GPU to the left segment, and 20% to the right segment. The 'right' GPU is fully assigned to the right segment, assigning 0.8 resources to the right segment and 1.2 to the left. The load balancing within a segment is performed by the load equalizer assigned to each segment and not described here.
Cross-segment load balancing allows for optimal resource usage of multiple GPUs used for display output and additional source GPUs. It combines multi-display parallel rendering with scalable rendering for optimal performance.
Algorithm
- Initialization:
- Set up statistic load listeners on all leaf channels
- Calculate total number of GPUs available
- For each frame:
- Find newest frame with complete load data
- Compute time needed to redraw each destination channel:
t_dest = sum( max( t_source_render, t_source_transmit ))
- Time to update a source is maximum of render or transmit, since these two operations run concurrently in two different threads
- Actually used is:
t_dest = t_source_average * sqrt( n_sources )
.
This is a heuristical calculation accounting for the non-linear relationship between number of resources and performance. t_total = sum( t_dest )
t_GPU = t_total / n_GPU
- For each destination compound:
n_dest_GPU = t_dest / t_GPU
- Assign usage 'self' GPU:
min( 1.0, n_dest_GPU )
if GPU is used for segment n_dest_remaining = n_dest_GPU - n_self_usage
- For each destination compound:
- Assign GPUs used in last frame (up to n_dest_remaining)
- Update n_dest_remaining
- For each destination compound:
- Assign unused GPUs (up to n_dest_remaining)
File Format
compound { view_equalizer {} compound { channel "destination1" load_equalizer{} compound {} # self compound { channel "source1" outputframe {} } inputframe{} ... } compound { channel "destination2" load_equalizer{} ... } ... }