mirror of
https://github.com/matrix-construct/construct
synced 2025-02-18 09:40:12 +01:00
ircd:🆑 Add options for exec; improve dependency related.
This commit is contained in:
parent
b1bfa7640d
commit
699d15e8c9
2 changed files with 127 additions and 41 deletions
|
@ -116,12 +116,50 @@ struct ircd::cl::kern::range
|
|||
local { 0, 0, 0, 0, 0 };
|
||||
};
|
||||
|
||||
/// Construction enqueues the task; destruction waits for completion.
|
||||
///
|
||||
/// clEnqueue* construction with resulting cl_event wrapping. Instances
|
||||
/// represent the full lifecycle of work creation, submission and completion.
|
||||
///
|
||||
/// Our interface is tied directly to ircd::ctx for intuitive control flow and
|
||||
/// interaction with the device. By default, all constructions are dependent
|
||||
/// on the last construction made on the same ircd::ctx, providing sequential
|
||||
/// consistency for each ircd::ctx, and independence between different ctxs.
|
||||
/// Each instance destructs only when complete, otherwise the ircd::ctx will
|
||||
/// block in the destructor.
|
||||
struct ircd::cl::exec
|
||||
:work
|
||||
{
|
||||
exec(data &, const mutable_buffer &, const bool blocking = false);
|
||||
exec(data &, const const_buffer &, const bool blocking = false);
|
||||
exec(kern &, const kern::range &);
|
||||
struct opts;
|
||||
|
||||
static const opts opts_default;
|
||||
|
||||
// Read data from the device into buffer.
|
||||
exec(data &, const mutable_buffer &, const opts & = opts_default);
|
||||
|
||||
// Write data to the device from buffer.
|
||||
exec(data &, const const_buffer &, const opts & = opts_default);
|
||||
|
||||
// Execute a kernel on a range.
|
||||
exec(kern &, const kern::range &, const opts & = opts_default);
|
||||
|
||||
// Execute a barrier.
|
||||
exec(const opts &);
|
||||
};
|
||||
|
||||
/// Options for an exec.
|
||||
struct ircd::cl::exec::opts
|
||||
{
|
||||
/// Specify a list of dependencies. When provided, this list overrides the
|
||||
/// default sequential behavior; thus can be used to start new dependency
|
||||
/// chains for some task concurrency on the same ircd::ctx. Providing a
|
||||
/// single reference to the last exec on the same stack is equivalent to
|
||||
/// the default.
|
||||
vector_view<cl::exec> deps;
|
||||
|
||||
/// For operations that have an optional blocking behavior;
|
||||
/// otherwise ignored.
|
||||
bool blocking {false};
|
||||
};
|
||||
|
||||
struct ircd::cl::init
|
||||
|
|
124
ircd/cl.cc
124
ircd/cl.cc
|
@ -266,7 +266,11 @@ ircd::cl::flush()
|
|||
|
||||
namespace ircd::cl
|
||||
{
|
||||
size_t depend_ctx_last(const vector_view<cl_event> &, cl::work *const &);
|
||||
static const size_t _deps_list_max {256};
|
||||
static thread_local cl_event _deps_list[_deps_list_max];
|
||||
|
||||
static vector_view<cl_event> make_deps_default(cl::work *const &, const exec::opts &);
|
||||
static vector_view<cl_event> make_deps(cl::work *const &, const exec::opts &);
|
||||
}
|
||||
|
||||
template<>
|
||||
|
@ -281,8 +285,45 @@ ircd::util::instance_list<ircd::cl::work>::list
|
|||
allocator
|
||||
};
|
||||
|
||||
decltype(ircd::cl::exec::opts_default)
|
||||
ircd::cl::exec::opts_default;
|
||||
|
||||
ircd::cl::exec::exec(const opts &opts)
|
||||
try
|
||||
{
|
||||
auto &q
|
||||
{
|
||||
queue[0][0]
|
||||
};
|
||||
|
||||
const auto deps
|
||||
{
|
||||
make_deps(this, opts)
|
||||
};
|
||||
|
||||
call
|
||||
(
|
||||
clEnqueueBarrierWithWaitList,
|
||||
q,
|
||||
deps.size(),
|
||||
deps.size()? deps.data(): nullptr,
|
||||
reinterpret_cast<cl_event *>(&this->handle)
|
||||
);
|
||||
}
|
||||
catch(const std::exception &e)
|
||||
{
|
||||
log::error
|
||||
{
|
||||
log, "Exec Barrier :%s",
|
||||
e.what(),
|
||||
};
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
ircd::cl::exec::exec(kern &kern,
|
||||
const kern::range &work)
|
||||
const kern::range &work,
|
||||
const opts &opts)
|
||||
try
|
||||
{
|
||||
size_t dim(0);
|
||||
|
@ -294,14 +335,9 @@ try
|
|||
queue[0][0]
|
||||
};
|
||||
|
||||
cl_event dependency[1]
|
||||
const auto deps
|
||||
{
|
||||
nullptr
|
||||
};
|
||||
|
||||
const auto dependencies
|
||||
{
|
||||
depend_ctx_last(dependency, this)
|
||||
make_deps(this, opts)
|
||||
};
|
||||
|
||||
call
|
||||
|
@ -313,8 +349,8 @@ try
|
|||
work.offset.data(),
|
||||
work.global.data(),
|
||||
work.local.data(),
|
||||
dependencies,
|
||||
dependencies? dependency: nullptr,
|
||||
deps.size(),
|
||||
deps.size()? deps.data(): nullptr,
|
||||
reinterpret_cast<cl_event *>(&this->handle)
|
||||
);
|
||||
}
|
||||
|
@ -331,7 +367,7 @@ catch(const std::exception &e)
|
|||
|
||||
ircd::cl::exec::exec(data &data,
|
||||
const mutable_buffer &buf,
|
||||
const bool blocking)
|
||||
const opts &opts)
|
||||
try
|
||||
{
|
||||
auto &q
|
||||
|
@ -339,14 +375,9 @@ try
|
|||
queue[0][0]
|
||||
};
|
||||
|
||||
cl_event dependency[1]
|
||||
const auto deps
|
||||
{
|
||||
nullptr
|
||||
};
|
||||
|
||||
const auto dependencies
|
||||
{
|
||||
depend_ctx_last(dependency, this)
|
||||
make_deps(this, opts)
|
||||
};
|
||||
|
||||
call
|
||||
|
@ -354,12 +385,12 @@ try
|
|||
clEnqueueReadBuffer,
|
||||
q,
|
||||
cl_mem(data.handle),
|
||||
blocking,
|
||||
opts.blocking,
|
||||
0UL, //offset,
|
||||
ircd::size(buf),
|
||||
ircd::data(buf),
|
||||
dependencies,
|
||||
dependencies? dependency: nullptr,
|
||||
deps.size(),
|
||||
deps.size()? deps.data(): nullptr,
|
||||
reinterpret_cast<cl_event *>(&this->handle)
|
||||
);
|
||||
}
|
||||
|
@ -376,7 +407,7 @@ catch(const std::exception &e)
|
|||
|
||||
ircd::cl::exec::exec(data &data,
|
||||
const const_buffer &buf,
|
||||
const bool blocking)
|
||||
const opts &opts)
|
||||
try
|
||||
{
|
||||
auto &q
|
||||
|
@ -384,14 +415,9 @@ try
|
|||
queue[0][0]
|
||||
};
|
||||
|
||||
cl_event dependency[1]
|
||||
const auto deps
|
||||
{
|
||||
nullptr
|
||||
};
|
||||
|
||||
const auto dependencies
|
||||
{
|
||||
depend_ctx_last(dependency, this)
|
||||
make_deps(this, opts)
|
||||
};
|
||||
|
||||
call
|
||||
|
@ -399,12 +425,12 @@ try
|
|||
clEnqueueWriteBuffer,
|
||||
q,
|
||||
cl_mem(data.handle),
|
||||
blocking,
|
||||
opts.blocking,
|
||||
0UL, //offset,
|
||||
ircd::size(buf),
|
||||
mutable_cast(ircd::data(buf)),
|
||||
dependencies,
|
||||
dependencies? dependency: nullptr,
|
||||
deps.size(),
|
||||
deps.size()? deps.data(): nullptr,
|
||||
reinterpret_cast<cl_event *>(&this->handle)
|
||||
);
|
||||
}
|
||||
|
@ -419,11 +445,30 @@ catch(const std::exception &e)
|
|||
throw;
|
||||
}
|
||||
|
||||
size_t
|
||||
ircd::cl::depend_ctx_last(const vector_view<cl_event> &deps,
|
||||
cl::work *const &work)
|
||||
ircd::vector_view<cl_event>
|
||||
ircd::cl::make_deps(cl::work *const &work,
|
||||
const exec::opts &opts)
|
||||
{
|
||||
if(empty(opts.deps))
|
||||
return make_deps_default(work, opts);
|
||||
|
||||
size_t ret(0);
|
||||
vector_view<cl_event> out(_deps_list);
|
||||
for(auto &exec : opts.deps)
|
||||
out.at(ret++) = cl_event(exec.handle);
|
||||
|
||||
return vector_view<cl_event>
|
||||
{
|
||||
out, ret
|
||||
};
|
||||
}
|
||||
|
||||
ircd::vector_view<cl_event>
|
||||
ircd::cl::make_deps_default(cl::work *const &work,
|
||||
const exec::opts &opts)
|
||||
{
|
||||
size_t ret(0);
|
||||
vector_view<cl_event> out(_deps_list);
|
||||
for(auto it(rbegin(cl::work::list)); it != rend(cl::work::list); ++it)
|
||||
{
|
||||
cl::work *const &other{*it};
|
||||
|
@ -433,11 +478,14 @@ ircd::cl::depend_ctx_last(const vector_view<cl_event> &deps,
|
|||
if(other->context != ctx::current)
|
||||
continue;
|
||||
|
||||
deps.at(ret++) = cl_event(other->handle);
|
||||
out.at(ret++) = cl_event(other->handle);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return vector_view<cl_event>
|
||||
{
|
||||
out, ret
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
|
|
Loading…
Add table
Reference in a new issue