mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-06 09:28:07 +02:00
rusticl: restructure program build to prepare for parallelization
v2: include restructuring of link and compile, break out more functions v3: split out naming changes to later commit Reviewed-by: Karol Herbst <kherbst@redhat.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36497>
This commit is contained in:
parent
833481b6ab
commit
56cc1b1c96
2 changed files with 88 additions and 74 deletions
|
|
@ -309,7 +309,7 @@ fn build_program(
|
|||
pfn_notify: Option<FuncProgramCB>,
|
||||
user_data: *mut ::std::os::raw::c_void,
|
||||
) -> CLResult<()> {
|
||||
let p = Program::ref_from_raw(program)?;
|
||||
let p = Program::arc_from_raw(program)?;
|
||||
let devs = validate_devices(device_list, num_devices, &p.devs)?;
|
||||
|
||||
// SAFETY: The requirements on `ProgramCB::try_new` match the requirements
|
||||
|
|
@ -321,25 +321,15 @@ fn build_program(
|
|||
return Err(CL_INVALID_OPERATION);
|
||||
}
|
||||
|
||||
// CL_BUILD_PROGRAM_FAILURE if there is a failure to build the program executable. This error
|
||||
// will be returned if clBuildProgram does not return until the build has completed.
|
||||
let options = c_string_to_string(options);
|
||||
let res = p.build(&devs, &options);
|
||||
|
||||
if let Some(cb) = cb_opt {
|
||||
cb.call(p);
|
||||
}
|
||||
let res = p.build(devs, options, cb_opt);
|
||||
|
||||
//• CL_INVALID_BINARY if program is created with clCreateProgramWithBinary and devices listed in device_list do not have a valid program binary loaded.
|
||||
//• CL_INVALID_BUILD_OPTIONS if the build options specified by options are invalid.
|
||||
//• CL_INVALID_OPERATION if the build of a program executable for any of the devices listed in device_list by a previous call to clBuildProgram for program has not completed.
|
||||
//• CL_INVALID_OPERATION if program was not created with clCreateProgramWithSource, clCreateProgramWithIL or clCreateProgramWithBinary.
|
||||
|
||||
if res {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(CL_BUILD_PROGRAM_FAILURE)
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
#[cl_entrypoint(clCompileProgram)]
|
||||
|
|
@ -354,7 +344,7 @@ fn compile_program(
|
|||
pfn_notify: Option<FuncProgramCB>,
|
||||
user_data: *mut ::std::os::raw::c_void,
|
||||
) -> CLResult<()> {
|
||||
let p = Program::ref_from_raw(program)?;
|
||||
let p = Program::arc_from_raw(program)?;
|
||||
let devs = validate_devices(device_list, num_devices, &p.devs)?;
|
||||
|
||||
// SAFETY: The requirements on `ProgramCB::try_new` match the requirements
|
||||
|
|
@ -408,23 +398,13 @@ fn compile_program(
|
|||
return Err(CL_INVALID_OPERATION);
|
||||
}
|
||||
|
||||
// CL_COMPILE_PROGRAM_FAILURE if there is a failure to compile the program source. This error
|
||||
// will be returned if clCompileProgram does not return until the compile has completed.
|
||||
let options = c_string_to_string(options);
|
||||
let res = p.compile(&devs, &options, &headers);
|
||||
|
||||
if let Some(cb) = cb_opt {
|
||||
cb.call(p);
|
||||
}
|
||||
let res = p.compile(devs, options, headers, cb_opt);
|
||||
|
||||
// • CL_INVALID_COMPILER_OPTIONS if the compiler options specified by options are invalid.
|
||||
// • CL_INVALID_OPERATION if the compilation or build of a program executable for any of the devices listed in device_list by a previous call to clCompileProgram or clBuildProgram for program has not completed.
|
||||
|
||||
if res {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(CL_COMPILE_PROGRAM_FAILURE)
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
pub fn link_program(
|
||||
|
|
@ -459,31 +439,11 @@ pub fn link_program(
|
|||
// CL_INVALID_OPERATION if the compilation or build of a program executable for any of the
|
||||
// devices listed in device_list by a previous call to clCompileProgram or clBuildProgram for
|
||||
// program has not completed.
|
||||
for d in &devs {
|
||||
if progs
|
||||
.iter()
|
||||
.map(|p| p.status(d))
|
||||
.any(|s| s != CL_BUILD_SUCCESS as cl_build_status)
|
||||
{
|
||||
return Err(CL_INVALID_OPERATION);
|
||||
}
|
||||
if progs.iter().any(|p| !p.all_devices_succeeded(&devs)) {
|
||||
return Err(CL_INVALID_OPERATION);
|
||||
}
|
||||
|
||||
// CL_LINK_PROGRAM_FAILURE if there is a failure to link the compiled binaries and/or libraries.
|
||||
let res = Program::link(c, &devs, &progs, c_string_to_string(options));
|
||||
let code = if devs
|
||||
.iter()
|
||||
.map(|d| res.status(d))
|
||||
.all(|s| s == CL_BUILD_SUCCESS as cl_build_status)
|
||||
{
|
||||
CL_SUCCESS as cl_int
|
||||
} else {
|
||||
CL_LINK_PROGRAM_FAILURE
|
||||
};
|
||||
|
||||
if let Some(cb) = cb_opt {
|
||||
cb.call(&res);
|
||||
}
|
||||
let (res, code) = Program::link(c, devs, progs, c_string_to_string(options), cb_opt)?;
|
||||
|
||||
Ok((res.into_cl(), code))
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::api::icd::*;
|
||||
use crate::api::types::ProgramCB;
|
||||
use crate::core::context::*;
|
||||
use crate::core::device::*;
|
||||
use crate::core::kernel::*;
|
||||
|
|
@ -567,14 +568,17 @@ impl Program {
|
|||
.any(|k| Arc::strong_count(k) > 1)
|
||||
}
|
||||
|
||||
pub fn build(&self, devs: &[&'static Device], options: &str) -> bool {
|
||||
pub fn build(
|
||||
self: Arc<Self>,
|
||||
devs: Vec<&'static Device>,
|
||||
options: String,
|
||||
callback: Option<ProgramCB>,
|
||||
) -> CLResult<()> {
|
||||
let lib = options.contains("-create-library");
|
||||
let mut info = self.build_info();
|
||||
|
||||
let mut res = true;
|
||||
for dev in devs {
|
||||
if !self.do_compile(dev, options, &[], &mut info) {
|
||||
res = false;
|
||||
for &dev in &devs {
|
||||
if !self.do_compile(dev, &options, &[], &mut info) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -594,17 +598,29 @@ impl Program {
|
|||
// Don't request validation of the SPIR-V, as we've just done that
|
||||
// as part of compilation.
|
||||
Self::do_link(d, &spirvs, lib, None);
|
||||
|
||||
if d.status == CL_BUILD_ERROR {
|
||||
res = false
|
||||
}
|
||||
}
|
||||
|
||||
info.rebuild_kernels(devs, self.is_src());
|
||||
info.rebuild_kernels(&devs, self.is_src());
|
||||
|
||||
debug_logging(self, devs);
|
||||
// The callback must be called after we've dropped any mutex locks we're
|
||||
// holding.
|
||||
drop(info);
|
||||
|
||||
res
|
||||
if let Some(callback) = callback {
|
||||
callback.call(&self);
|
||||
}
|
||||
|
||||
debug_logging(&self, &devs);
|
||||
|
||||
if !self.all_devices_succeeded(&devs) {
|
||||
// clBuildProgram returns CL_BUILD_PROGRAM_FAILURE if there is a
|
||||
// failure to build the program executable. This error will be
|
||||
// returned if clBuildProgram does not return until the build
|
||||
// has completed.
|
||||
return Err(CL_BUILD_PROGRAM_FAILURE);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn do_compile(
|
||||
|
|
@ -694,28 +710,46 @@ impl Program {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn compile(&self, devs: &[&Device], options: &str, headers: &[HeaderProgram]) -> bool {
|
||||
let mut res = true;
|
||||
for dev in devs {
|
||||
res &= self.do_compile(dev, options, headers, &mut self.build_info());
|
||||
pub fn compile(
|
||||
self: Arc<Self>,
|
||||
devs: Vec<&Device>,
|
||||
options: String,
|
||||
headers: Vec<HeaderProgram>,
|
||||
callback: Option<ProgramCB>,
|
||||
) -> CLResult<()> {
|
||||
for &dev in &devs {
|
||||
self.do_compile(dev, &options, &headers, &mut self.build_info());
|
||||
}
|
||||
|
||||
debug_logging(self, devs);
|
||||
if let Some(callback) = callback {
|
||||
callback.call(&self);
|
||||
}
|
||||
|
||||
res
|
||||
debug_logging(&self, &devs);
|
||||
|
||||
if !self.all_devices_succeeded(&devs) {
|
||||
// clCompileProgram returns CL_COMPILE_PROGRAM_FAILURE if there is a
|
||||
// failure to compile the program source. This error will be
|
||||
// returned if clCompileProgram does not return until the compile
|
||||
// has completed.
|
||||
return Err(CL_COMPILE_PROGRAM_FAILURE);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn link(
|
||||
context: Arc<Context>,
|
||||
devs: &[&'static Device],
|
||||
progs: &[Arc<Program>],
|
||||
devs: Vec<&'static Device>,
|
||||
progs: Vec<Arc<Program>>,
|
||||
options: String,
|
||||
) -> Arc<Program> {
|
||||
callback: Option<ProgramCB>,
|
||||
) -> CLResult<(Arc<Program>, cl_int)> {
|
||||
let mut builds = HashMap::new();
|
||||
let mut locks: Vec<_> = progs.iter().map(|p| p.build_info()).collect();
|
||||
let lib = options.contains("-create-library");
|
||||
|
||||
for &d in devs {
|
||||
for &d in &devs {
|
||||
let bins: Vec<_> = locks
|
||||
.iter_mut()
|
||||
.map(|l| l.dev_build(d).spirv.as_ref().unwrap())
|
||||
|
|
@ -741,19 +775,31 @@ impl Program {
|
|||
};
|
||||
|
||||
// Pre build nir kernels
|
||||
build.rebuild_kernels(devs, false);
|
||||
build.rebuild_kernels(&devs, false);
|
||||
|
||||
let res = Arc::new(Self {
|
||||
base: CLObjectBase::new(RusticlTypes::Program),
|
||||
context: context,
|
||||
devs: devs.to_owned(),
|
||||
devs: devs.clone(),
|
||||
src: ProgramSourceType::Linked,
|
||||
build: Mutex::new(build),
|
||||
});
|
||||
|
||||
if let Some(callback) = callback {
|
||||
callback.call(&res);
|
||||
}
|
||||
|
||||
debug_logging(&res, &devs);
|
||||
|
||||
res
|
||||
let status = if res.all_devices_succeeded(&devs) {
|
||||
CL_SUCCESS as cl_int
|
||||
} else {
|
||||
// clLinkProgram returns CL_LINK_PROGRAM_FAILURE if there is a
|
||||
// failure to link the compiled binaries and/or libraries.
|
||||
CL_LINK_PROGRAM_FAILURE
|
||||
};
|
||||
|
||||
Ok((res, status))
|
||||
}
|
||||
|
||||
/// Performs linking of the provided SPIR-V binaries.
|
||||
|
|
@ -795,6 +841,14 @@ impl Program {
|
|||
};
|
||||
}
|
||||
|
||||
/// Returns `true` if build succeeded for each of the provided devices,
|
||||
/// false otherwise.
|
||||
pub fn all_devices_succeeded(&self, devices: &[&Device]) -> bool {
|
||||
devices
|
||||
.iter()
|
||||
.all(|&device| self.status(device) == CL_BUILD_SUCCESS as cl_build_status)
|
||||
}
|
||||
|
||||
pub fn is_bin(&self) -> bool {
|
||||
matches!(self.src, ProgramSourceType::Binary)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue