Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tasking module #5436

Merged
merged 28 commits into from
Apr 27, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e105140
Initial code dump.
mzient Apr 17, 2024
905752f
Code ported from the prototype.
mzient Apr 17, 2024
8adbeeb
Code moved. Initial sanity tests added. Multi-output capability added.
mzient Apr 18, 2024
36dd609
Add documentation.
mzient Apr 18, 2024
51609b7
Add a torture test.
mzient Apr 18, 2024
0fa1e5f
Review issues.
mzient Apr 19, 2024
3c214c8
Clarification.
mzient Apr 19, 2024
669183e
Bugfix in parallelism test.
mzient Apr 19, 2024
0ceb326
Improve test description.
mzient Apr 19, 2024
f35094f
Review issues - renaming, more documentation.
mzient Apr 22, 2024
c2be520
More documentation, some more renaming.
mzient Apr 22, 2024
dc497a0
Review issues.
mzient Apr 22, 2024
814745b
Further improvements in docs.
mzient Apr 22, 2024
b0c62b8
Add tests for error cases.
mzient Apr 22, 2024
2b72aa6
Bugfix in the tests. Reduce lock scope in Scheduler::AddTaskImpl.
mzient Apr 22, 2024
00f4ab3
Remove extraneous newline in an error message.
mzient Apr 22, 2024
565dbfb
Remove the need to pass a Scheduler to TaskFuture.
mzient Apr 22, 2024
1d8ac66
Add atomic fences in Wait and Run.
mzient Apr 22, 2024
319adc5
Move Submit to private section.
mzient Apr 22, 2024
f91312f
Improve wording in ReleaseImpl documentation.
mzient Apr 22, 2024
23f6b32
Improve atomicity semantics.
mzient Apr 23, 2024
2aa3da6
Restore fences for clarity; improved comments.
mzient Apr 23, 2024
3c833d1
Improved constness.
mzient Apr 23, 2024
0c5838c
Ensure proper handling of (runtime) non-copyable functors.
mzient Apr 24, 2024
803b2cd
Fix input check test.
mzient Apr 24, 2024
bb84b2e
Fix waiting for releasables. Add more tests with semaphores.
mzient Apr 24, 2024
1850e94
Add comment explaining why we need to call IsAcquirable in a loop.
mzient Apr 24, 2024
1d84af3
Use [[nodiscard(reason)]] only if the compiler supports it.
mzient Apr 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ SHORT_NAMES = NO
# description.)
# The default value is: NO.

JAVADOC_AUTOBRIEF = NO
JAVADOC_AUTOBRIEF = YES

# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
# line (until the first dot) of a Qt-style comment as the brief description. If
Expand Down
3 changes: 2 additions & 1 deletion dali/core/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2017-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -16,6 +16,7 @@ project(dali_core CUDA CXX C)

add_subdirectory(mm)
add_subdirectory(os)
add_subdirectory(exec)

# Get all the source files
collect_headers(DALI_INST_HDRS PARENT_SCOPE)
Expand Down
20 changes: 20 additions & 0 deletions dali/core/exec/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

add_subdirectory(tasking)

# Get all the source files
collect_headers(DALI_INST_HDRS PARENT_SCOPE)
collect_sources(DALI_CORE_SRCS PARENT_SCOPE)
collect_test_sources(DALI_CORE_TEST_SRCS PARENT_SCOPE)
18 changes: 18 additions & 0 deletions dali/core/exec/tasking/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Get all the source files
collect_headers(DALI_INST_HDRS PARENT_SCOPE)
collect_sources(DALI_CORE_SRCS PARENT_SCOPE)
collect_test_sources(DALI_CORE_TEST_SRCS PARENT_SCOPE)
104 changes: 104 additions & 0 deletions dali/core/exec/tasking/scheduler.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <cassert>
#include <mutex>
#include <iostream>
#include "dali/core/exec/tasking/scheduler.h"

namespace dali::tasking {

bool Scheduler::AcquireAllAndMoveToReady(SharedTask &task) noexcept {
assert(task->state_ <= TaskState::Pending);

// All or nothing - first we check that all preconditions are met
for (auto &w : task->preconditions_)
JanuszL marked this conversation as resolved.
Show resolved Hide resolved
if (!w->IsAcquirable())
return false; // at least one unmet
// If they are, we acquire them - this must succeed
for (auto &w : task->preconditions_)
if (!w->TryAcquire(task)) {
std::cerr
<< "Internal error - resource acquisition failed for a resource known to be available"
<< std::endl;
std::abort();
}

task->preconditions_.clear();
task->state_ = TaskState::Ready;
pending_.Remove(task);
ready_.push(std::move(task));
return true;
}

void Scheduler::Notify(Waitable *w) {
bool is_completion_event = dynamic_cast<CompletionEvent *>(w) != nullptr;
bool is_task = is_completion_event && dynamic_cast<Task *>(w);
JanuszL marked this conversation as resolved.
Show resolved Hide resolved

int new_ready = 0;
{
std::lock_guard g(mtx_);
if (is_task)
task_done_.notify_all();

SmallVector<SharedTask, 8> waiting;
int n = w->waiting_.size();
waiting.reserve(n);
for (int i = 0; i < n; i++)
waiting.emplace_back(w->waiting_[i]);

for (auto &task : waiting) {
if (task->Ready())
continue;

// If the task has only one precondition or the waitable is a completion event,
// then we can just try to acquire that waitable on behalf of the task.
// A completion event, once complete, is never un-completed and all waiting threads
// will be able to acquire it. This menas that we can eagerly acquire it without risking
// deadlocks. This imposes less overhead than re-checking all preconditions each time.
if (is_completion_event ||
(task->preconditions_.size() == 1 && task->preconditions_.begin()->get() == w)) {
// try acquire - the only way this can fail is that the task was
// re-checked in another thread and marked as ready...
if (!w->TryAcquire(task)) {
assert(task->preconditions_.size() != 1 || task->preconditions_.begin()->get() != w);
continue; // ... if so, nothing to do
}
auto it = std::find_if(task->preconditions_.begin(), task->preconditions_.end(),
[w](auto &pre) { return pre.get() == w; });
assert(it != task->preconditions_.end());
task->preconditions_.erase(it);
if (task->Ready()) {
pending_.Remove(task);
task->state_ = TaskState::Ready;
ready_.push(std::move(task));
new_ready++;
// OK, the task is ready, we're done with it
continue;
}
}

if (AcquireAllAndMoveToReady(task))
new_ready++;
}
}


if (new_ready == 1)
this->task_ready_.notify_one();
else if (new_ready > 1)
this->task_ready_.notify_all();
}

} // namespace dali::tasking
Loading
Loading