Bug 1595708 - Cargo build timings SVG output Freezes the entire browser with WebRender r=nical,jrmuizel

Differential Revision: https://phabricator.services.mozilla.com/D56244

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Bert Peers 2019-12-09 20:21:41 +00:00
parent 30f2b5474f
commit 8edb97a47a
9 changed files with 77 additions and 14 deletions

1
Cargo.lock generated
View File

@ -4457,6 +4457,7 @@ dependencies = [
"thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender 0.60.0",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]

View File

@ -29,6 +29,7 @@ features = ["capture", "serialize_program"]
[target.'cfg(target_os = "windows")'.dependencies]
dwrote = "0.9"
dirs = "1.0"
winapi = "0.3"
[target.'cfg(target_os = "macos")'.dependencies]
core-foundation = "0.6"

View File

@ -45,6 +45,8 @@ static StaticRefPtr<RenderThread> sRenderThread;
RenderThread::RenderThread(base::Thread* aThread)
: mThread(aThread),
mThreadPool(false),
mThreadPoolLP(true),
mWindowInfos("RenderThread.mWindowInfos"),
mRenderTextureMapLock("RenderThread.mRenderTextureMapLock"),
mHasShutdown(false),
@ -118,6 +120,7 @@ void RenderThread::ShutDownTask(layers::SynchronousTask* aTask) {
// Let go of our handle to the (internally ref-counted) thread pool.
mThreadPool.Release();
mThreadPoolLP.Release();
// Releasing on the render thread will allow us to avoid dispatching to remove
// remaining textures from the texture map.
@ -867,8 +870,8 @@ WebRenderPipelineInfo::~WebRenderPipelineInfo() {
wr_pipeline_info_delete(mPipelineInfo);
}
WebRenderThreadPool::WebRenderThreadPool() {
mThreadPool = wr_thread_pool_new();
WebRenderThreadPool::WebRenderThreadPool(bool low_priority) {
mThreadPool = wr_thread_pool_new(low_priority);
}
WebRenderThreadPool::~WebRenderThreadPool() { Release(); }

View File

@ -44,7 +44,7 @@ class RenderThread;
/// process.
class WebRenderThreadPool {
public:
WebRenderThreadPool();
explicit WebRenderThreadPool(bool low_priority);
~WebRenderThreadPool();
@ -230,6 +230,10 @@ class RenderThread final {
/// Can be called from any thread.
WebRenderThreadPool& ThreadPool() { return mThreadPool; }
/// Thread pool for low priority scene building
/// Can be called from any thread.
WebRenderThreadPool& ThreadPoolLP() { return mThreadPoolLP; }
/// Returns the cache used to serialize shader programs to disk, if enabled.
///
/// Can only be called from the render thread.
@ -288,6 +292,7 @@ class RenderThread final {
base::Thread* const mThread;
WebRenderThreadPool mThreadPool;
WebRenderThreadPool mThreadPoolLP;
UniquePtr<WebRenderProgramCache> mProgramCache;
UniquePtr<WebRenderShaders> mShaders;

View File

@ -73,11 +73,15 @@ class NewRenderer : public RendererEvent {
bool allow_texture_swizzling = gfx::gfxVars::UseGLSwizzle();
bool isMainWindow = true; // TODO!
bool supportLowPriorityTransactions = isMainWindow;
bool supportLowPriorityThreadpool =
supportLowPriorityTransactions &&
StaticPrefs::gfx_webrender_enable_low_priority_pool();
bool supportPictureCaching = isMainWindow;
wr::Renderer* wrRenderer = nullptr;
if (!wr_window_new(
aWindowId, mSize.width, mSize.height,
supportLowPriorityTransactions, allow_texture_swizzling,
supportLowPriorityTransactions, supportLowPriorityThreadpool,
allow_texture_swizzling,
StaticPrefs::gfx_webrender_picture_caching() &&
supportPictureCaching,
#ifdef NIGHTLY_BUILD
@ -92,7 +96,8 @@ class NewRenderer : public RendererEvent {
aRenderThread.GetShaders()
? aRenderThread.GetShaders()->RawShaders()
: nullptr,
aRenderThread.ThreadPool().Raw(), &WebRenderMallocSizeOf,
aRenderThread.ThreadPool().Raw(),
aRenderThread.ThreadPoolLP().Raw(), &WebRenderMallocSizeOf,
&WebRenderMallocEnclosingSizeOf, (uint32_t)wr::RenderRoot::Default,
compositor->ShouldUseNativeCompositor() ? compositor.get()
: nullptr,

View File

@ -7,6 +7,10 @@ use std::ffi::{CStr, CString};
use std::ffi::OsString;
#[cfg(target_os = "windows")]
use std::os::windows::ffi::OsStringExt;
#[cfg(target_os = "windows")]
use winapi::um::processthreadsapi::{SetThreadPriority,GetCurrentThread};
#[cfg(target_os = "windows")]
use winapi::um::winbase::{SetThreadAffinityMask};
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
use std::os::unix::ffi::OsStringExt;
use std::io::Cursor;
@ -38,6 +42,7 @@ use rayon;
use num_cpus;
use euclid::SideOffsets2D;
use nsstring::nsAString;
//linux only//use thread_priority::*;
#[cfg(target_os = "macos")]
use core_foundation::string::CFString;
@ -1053,18 +1058,35 @@ impl ThreadListener for GeckoProfilerThreadListener {
pub struct WrThreadPool(Arc<rayon::ThreadPool>);
#[no_mangle]
pub unsafe extern "C" fn wr_thread_pool_new() -> *mut WrThreadPool {
pub unsafe extern "C" fn wr_thread_pool_new(low_priority: bool) -> *mut WrThreadPool {
// Clamp the number of workers between 1 and 8. We get diminishing returns
// with high worker counts and extra overhead because of rayon and font
// management.
let num_threads = num_cpus::get().max(2).min(8);
let priority_tag = if low_priority { "LP" } else { "" };
let worker = rayon::ThreadPoolBuilder::new()
.thread_name(|idx|{ format!("WRWorker#{}", idx) })
.thread_name(move |idx|{ format!("WRWorker{}#{}", priority_tag, idx) })
.num_threads(num_threads)
.start_handler(|idx| {
.start_handler(move |idx| {
#[cfg(target_os = "windows")]
{
SetThreadPriority(
GetCurrentThread(),
if low_priority {
-1 /* THREAD_PRIORITY_BELOW_NORMAL */
} else {
0 /* THREAD_PRIORITY_NORMAL */
});
SetThreadAffinityMask(GetCurrentThread(), 1usize << idx);
}
/*let thread_id = thread_native_id();
set_thread_priority(thread_id,
if low_priority { ThreadPriority::Min } else { ThreadPriority::Max },
ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Normal));*/
wr_register_thread_local_arena();
let name = format!("WRWorker#{}", idx);
let name = format!("WRWorker{}#{}",priority_tag, idx);
register_thread_with_profiler(name.clone());
gecko_profiler_register_thread(CString::new(name).unwrap().as_ptr());
})
@ -1305,6 +1327,7 @@ pub extern "C" fn wr_window_new(window_id: WrWindowId,
window_width: i32,
window_height: i32,
support_low_priority_transactions: bool,
support_low_priority_threadpool: bool,
allow_texture_swizzling: bool,
enable_picture_caching: bool,
start_debug_server: bool,
@ -1313,6 +1336,7 @@ pub extern "C" fn wr_window_new(window_id: WrWindowId,
program_cache: Option<&mut WrProgramCache>,
shaders: Option<&mut WrShaders>,
thread_pool: *mut WrThreadPool,
thread_pool_low_priority: *mut WrThreadPool,
size_of_op: VoidPtrToSizeFn,
enclosing_size_of_op: VoidPtrToSizeFn,
document_id: u32,
@ -1347,6 +1371,13 @@ pub extern "C" fn wr_window_new(window_id: WrWindowId,
let workers = unsafe {
Arc::clone(&(*thread_pool).0)
};
let workers_low_priority = unsafe {
if support_low_priority_threadpool {
Arc::clone(&(*thread_pool_low_priority).0)
} else {
Arc::clone(&(*thread_pool).0)
}
};
let upload_method = if unsafe { is_glcontext_angle(gl_context) } {
UploadMethod::Immediate
@ -1390,7 +1421,7 @@ pub extern "C" fn wr_window_new(window_id: WrWindowId,
support_low_priority_transactions,
allow_texture_swizzling,
recorder: recorder,
blob_image_handler: Some(Box::new(Moz2dBlobImageHandler::new(workers.clone()))),
blob_image_handler: Some(Box::new(Moz2dBlobImageHandler::new(workers.clone(), workers_low_priority.clone()))),
workers: Some(workers.clone()),
thread_listener: Some(Box::new(GeckoProfilerThreadListener::new())),
size_of_op: Some(size_of_op),

View File

@ -21,6 +21,8 @@ extern crate log;
#[cfg(target_os = "windows")]
extern crate dwrote;
#[cfg(target_os = "windows")]
extern crate winapi;
#[cfg(target_os = "macos")]

View File

@ -77,6 +77,7 @@ fn dump_index(blob: &[u8]) -> () {
/// Handles the interpretation and rasterization of gecko-based (moz2d) WR blob images.
pub struct Moz2dBlobImageHandler {
workers: Arc<ThreadPool>,
workers_low_priority: Arc<ThreadPool>,
blob_commands: HashMap<BlobImageKey, BlobCommand>,
}
@ -502,6 +503,8 @@ struct BlobCommand {
struct Moz2dBlobRasterizer {
/// Pool of rasterizers.
workers: Arc<ThreadPool>,
/// Pool of low priority rasterizers.
workers_low_priority: Arc<ThreadPool>,
/// Blobs to rasterize.
blob_commands: HashMap<BlobImageKey, BlobCommand>,
}
@ -559,9 +562,14 @@ impl AsyncBlobImageRasterizer for Moz2dBlobRasterizer {
// Parallel version synchronously installs a job on the thread pool which will
// try to do the work in parallel.
// This thread is blocked until the thread pool is done doing the work.
self.workers.install(||{
requests.into_par_iter().map(rasterize_blob).collect()
})
let lambda = ||{ requests.into_par_iter().map(rasterize_blob).collect() };
if low_priority {
//TODO --bpe runtime flag to A/B test these two
self.workers_low_priority.install(lambda)
//self.workers.install(lambda)
} else {
self.workers.install(lambda)
}
} else {
requests.into_iter().map(rasterize_blob).collect()
}
@ -653,6 +661,7 @@ impl BlobImageHandler for Moz2dBlobImageHandler {
fn create_blob_rasterizer(&mut self) -> Box<dyn AsyncBlobImageRasterizer> {
Box::new(Moz2dBlobRasterizer {
workers: Arc::clone(&self.workers),
workers_low_priority: Arc::clone(&self.workers_low_priority),
blob_commands: self.blob_commands.clone(),
})
}
@ -705,10 +714,11 @@ extern "C" {
impl Moz2dBlobImageHandler {
/// Create a new BlobImageHandler with the given thread pool.
pub fn new(workers: Arc<ThreadPool>) -> Self {
pub fn new(workers: Arc<ThreadPool>, workers_low_priority: Arc<ThreadPool>) -> Self {
Moz2dBlobImageHandler {
blob_commands: HashMap::new(),
workers: workers,
workers_low_priority: workers_low_priority,
}
}

View File

@ -3749,6 +3749,11 @@
mirror: always
#endif
- name: gfx.webrender.enable-low-priority-pool
type: RelaxedAtomicBool
value: false
mirror: always
# Use vsync events generated by hardware
- name: gfx.work-around-driver-bugs
type: bool