Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion tasks/artyushkina_markirovka/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"mpi": "enabled",
"omp": "enabled",
"seq": "enabled",
"stl": "enabled"
"stl": "enabled",
"tbb": "enabled"
},
"tasks_type": "processes"
}
48 changes: 48 additions & 0 deletions tasks/artyushkina_markirovka/tbb/include/ops_tbb.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#ifndef ARTYUSHKINA_MARKIROVKA_TBB_INCLUDE_OPS_TBB_HPP_
#define ARTYUSHKINA_MARKIROVKA_TBB_INCLUDE_OPS_TBB_HPP_

#include <tbb/spin_mutex.h>

#include <vector>

#include "artyushkina_markirovka/common/include/common.hpp"
#include "task/include/task.hpp"

namespace artyushkina_markirovka {

class MarkingComponentsTBB : public BaseTask {
public:
static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() {
return ppc::task::TypeOfTask::kTBB;
}
explicit MarkingComponentsTBB(const InType &in);

private:
bool ValidationImpl() override;
bool PreProcessingImpl() override;
bool RunImpl() override;
bool PostProcessingImpl() override;

int FindRoot(int label);
void UnionLabels(int label1, int label2);

void InitLabelsTbb();
void MergeHorizontalPairsTbb();
void MergeVerticalPairsTbb();
void MergeDiagonalPairsTbb();
void FinalizeRootsTbb();
void NormalizeLabelsTbb();

int rows_ = 0;
int cols_ = 0;
std::vector<int> labels_;
std::vector<int> parent_;
InType input_;
int current_label_ = 0;

mutable tbb::spin_mutex dsu_mutex_;
};

} // namespace artyushkina_markirovka

#endif // ARTYUSHKINA_MARKIROVKA_TBB_INCLUDE_OPS_TBB_HPP_
188 changes: 188 additions & 0 deletions tasks/artyushkina_markirovka/tbb/src/ops_tbb.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
#include "artyushkina_markirovka/tbb/include/ops_tbb.hpp"

#include <tbb/parallel_for.h>
#include <tbb/parallel_reduce.h>
#include <tbb/spin_mutex.h>

#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <vector>

#include "artyushkina_markirovka/common/include/common.hpp"

namespace artyushkina_markirovka {

MarkingComponentsTBB::MarkingComponentsTBB(const InType &in) {
SetTypeOfTask(GetStaticTypeOfTask());
GetInput() = in;
GetOutput() = OutType();
}

bool MarkingComponentsTBB::ValidationImpl() {
return GetInput().size() >= 2;
}

bool MarkingComponentsTBB::PreProcessingImpl() {
const auto &input = GetInput();
rows_ = static_cast<int>(input[0]);
cols_ = static_cast<int>(input[1]);
input_ = input;

int total_pixels = rows_ * cols_;
labels_.assign(total_pixels, 0);
parent_.resize(total_pixels + 1);
for (int i = 0; i <= total_pixels; ++i) {
parent_[i] = i;
}

current_label_ = 0;
return true;
}

int MarkingComponentsTBB::FindRoot(int label) {
int root = label;
while (parent_[root] != root) {
root = parent_[root];
}

int current = label;
while (parent_[current] != current) {
int next = parent_[current];
parent_[current] = root;
current = next;
}
return root;
}

void MarkingComponentsTBB::UnionLabels(int label1, int label2) {
tbb::spin_mutex::scoped_lock lock(dsu_mutex_);
int root1 = FindRoot(label1);
int root2 = FindRoot(label2);
if (root1 != root2) {
if (root1 < root2) {
parent_[root2] = root1;
} else {
parent_[root1] = root2;
}
}
}

void MarkingComponentsTBB::InitLabelsTbb() {
int total_pixels = rows_ * cols_;
tbb::parallel_for(0, total_pixels, [this](int idx) {
size_t input_idx = static_cast<size_t>(idx) + 2;
if (input_[input_idx] == 0) {
labels_[idx] = idx + 1;
}
});
}

void MarkingComponentsTBB::MergeHorizontalPairsTbb() {
tbb::parallel_for(0, rows_, [this](int y_coord) {
for (int x_coord = 0; x_coord < cols_ - 1; ++x_coord) {
int idx = (y_coord * cols_) + x_coord;
if (labels_[idx] != 0 && labels_[idx + 1] != 0) {
UnionLabels(labels_[idx], labels_[idx + 1]);
}
}
});
}

void MarkingComponentsTBB::MergeVerticalPairsTbb() {
tbb::parallel_for(0, cols_, [this](int x_coord) {
for (int y_coord = 0; y_coord < rows_ - 1; ++y_coord) {
int idx = (y_coord * cols_) + x_coord;
if (labels_[idx] != 0 && labels_[idx + cols_] != 0) {
UnionLabels(labels_[idx], labels_[idx + cols_]);
}
}
});
}

void MarkingComponentsTBB::MergeDiagonalPairsTbb() {
tbb::parallel_for(0, rows_, [this](int y_coord) {
for (int x_coord = 0; x_coord < cols_; ++x_coord) {
int idx = (y_coord * cols_) + x_coord;
if (labels_[idx] == 0) {
continue;
}

if (y_coord > 0 && x_coord > 0 && labels_[idx - cols_ - 1] != 0) {
UnionLabels(labels_[idx], labels_[idx - cols_ - 1]);
}
if (y_coord > 0 && x_coord < cols_ - 1 && labels_[idx - cols_ + 1] != 0) {
UnionLabels(labels_[idx], labels_[idx - cols_ + 1]);
}
}
});
}

void MarkingComponentsTBB::FinalizeRootsTbb() {
int total_pixels = rows_ * cols_;
tbb::parallel_for(0, total_pixels, [this](int i) {
if (labels_[i] != 0) {
labels_[i] = FindRoot(labels_[i]);
}
});
}

void MarkingComponentsTBB::NormalizeLabelsTbb() {
int total_pixels = rows_ * cols_;

std::vector<int> unique_roots;
for (int i = 0; i < total_pixels; ++i) {
if (labels_[i] != 0) {
unique_roots.push_back(labels_[i]);
}
}

std::sort(unique_roots.begin(), unique_roots.end());
unique_roots.erase(std::unique(unique_roots.begin(), unique_roots.end()), unique_roots.end());

std::vector<int> mapping(total_pixels + 1, 0);
for (size_t i = 0; i < unique_roots.size(); ++i) {
mapping[unique_roots[i]] = static_cast<int>(i + 1);
}

tbb::parallel_for(0, total_pixels, [this, &mapping](int i) {
if (labels_[i] != 0) {
labels_[i] = mapping[labels_[i]];
}
});

current_label_ = static_cast<int>(unique_roots.size());
}

bool MarkingComponentsTBB::RunImpl() {
int total_pixels = rows_ * cols_;
if (total_pixels <= 0) {
return true;
}

InitLabelsTbb();
MergeHorizontalPairsTbb();
MergeVerticalPairsTbb();
MergeDiagonalPairsTbb();
FinalizeRootsTbb();
NormalizeLabelsTbb();

return true;
}

bool MarkingComponentsTBB::PostProcessingImpl() {
OutType &output = GetOutput();
output.clear();

output.push_back(static_cast<uint8_t>(rows_));
output.push_back(static_cast<uint8_t>(cols_));

for (int label : labels_) {
output.push_back(static_cast<uint8_t>(label));
}

return true;
}

} // namespace artyushkina_markirovka
106 changes: 106 additions & 0 deletions tasks/artyushkina_markirovka/tests/functional/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "artyushkina_markirovka/omp/include/ops_omp.hpp"
#include "artyushkina_markirovka/seq/include/ops_seq.hpp"
#include "artyushkina_markirovka/stl/include/ops_stl.hpp"
#include "artyushkina_markirovka/tbb/include/ops_tbb.hpp"
#include "util/include/func_test_util.hpp"
#include "util/include/util.hpp"

Expand Down Expand Up @@ -289,6 +290,88 @@ class ArtyushkinaMarkirovkaFuncTestsSTL : public ppc::util::BaseRunFuncTests<InT
OutType expected_;
};

class ArtyushkinaMarkirovkaFuncTestsTBB : public ppc::util::BaseRunFuncTests<InType, OutType, TestType> {
public:
static std::string PrintTestParam(const TestType &test_param) {
return std::to_string(std::get<0>(test_param)) + "_" + std::get<1>(test_param);
}

protected:
void SetUp() override {
TestType params = std::get<static_cast<std::size_t>(ppc::util::GTestParamIndex::kTestParams)>(GetParam());
int test_id = std::get<0>(params);

switch (test_id) {
case 0: {
input_data_ = {3, 3, 0, 0, 255, 0, 255, 255, 255, 255, 0};
expected_ = {3, 3, 1, 1, 0, 1, 0, 0, 0, 0, 2};
break;
}
case 1: {
input_data_ = {3, 3, 0, 0, 0, 0, 255, 0, 0, 0, 255};
expected_ = {3, 3, 1, 1, 1, 1, 0, 1, 1, 1, 0};
break;
}
case 2: {
input_data_ = {2, 3, 255, 255, 255, 255, 255, 255};
expected_ = {2, 3, 0, 0, 0, 0, 0, 0};
break;
}
case 3: {
input_data_ = {2, 2, 0, 0, 0, 0};
expected_ = {2, 2, 1, 1, 1, 1};
break;
}
case 4: {
input_data_ = {3, 4, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0};
expected_ = {3, 4, 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2};
break;
}
case 6: {
input_data_ = {2, 2, 0, 255, 255, 0};
expected_ = {2, 2, 1, 0, 0, 1};
break;
}
default:
break;
}
}

bool CheckTestOutputData(OutType &output_data) final {
int test_id = std::get<0>(std::get<static_cast<std::size_t>(ppc::util::GTestParamIndex::kTestParams)>(GetParam()));

if (test_id == 6) {
std::cout << "\n=== INPUT MATRIX (test " << test_id << ") ===\n";
PrintInputMatrix(input_data_);
std::cout << "========================\n\n";
PrintMatrix(output_data, "=== OUTPUT LABELS ===\n");
}

if (output_data != expected_) {
std::cout << "Expected: ";
for (auto val : expected_) {
std::cout << static_cast<int>(val) << ' ';
}
std::cout << '\n';
std::cout << "Actual : ";
for (auto val : output_data) {
std::cout << val << ' ';
}
std::cout << '\n';
}

return output_data == expected_;
}

InType GetTestInputData() final {
return input_data_;
}

private:
InType input_data_;
OutType expected_;
};

namespace {

TEST_P(ArtyushkinaMarkirovkaFuncTestsSEQ, MarkingComponentsSEQ) {
Expand Down Expand Up @@ -350,6 +433,29 @@ const auto kPerfTestNameSTL = ArtyushkinaMarkirovkaFuncTestsSTL::PrintFuncTestNa

INSTANTIATE_TEST_SUITE_P(ComponentLabelingSTL, ArtyushkinaMarkirovkaFuncTestsSTL, kGtestValuesSTL, kPerfTestNameSTL);

TEST_P(ArtyushkinaMarkirovkaFuncTestsTBB, MarkingComponentsTBB) {
ExecuteTest(GetParam());
}

const std::array<TestType, 6> kTestParamTBB = {
std::make_tuple(0, "L_shaped_component_8connectivity"),
std::make_tuple(1, "diagonal_connected_components"),
std::make_tuple(2, "all_background"),
std::make_tuple(3, "all_objects"),
std::make_tuple(4, "two_horizontal_bars"),
std::make_tuple(6, "diagonal_connectivity_check")
// тест 5 удален
};

const auto kTestTasksListTBB =
ppc::util::AddFuncTask<MarkingComponentsTBB, InType>(kTestParamTBB, PPC_SETTINGS_artyushkina_markirovka);

const auto kGtestValuesTBB = ppc::util::ExpandToValues(kTestTasksListTBB);

const auto kPerfTestNameTBB = ArtyushkinaMarkirovkaFuncTestsTBB::PrintFuncTestName<ArtyushkinaMarkirovkaFuncTestsTBB>;

INSTANTIATE_TEST_SUITE_P(ComponentLabelingTBB, ArtyushkinaMarkirovkaFuncTestsTBB, kGtestValuesTBB, kPerfTestNameTBB);

} // namespace

} // namespace artyushkina_markirovka
11 changes: 11 additions & 0 deletions tasks/artyushkina_markirovka/tests/performance/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "artyushkina_markirovka/omp/include/ops_omp.hpp"
#include "artyushkina_markirovka/seq/include/ops_seq.hpp"
#include "artyushkina_markirovka/stl/include/ops_stl.hpp"
#include "artyushkina_markirovka/tbb/include/ops_tbb.hpp"
#include "util/include/perf_test_util.hpp"

namespace artyushkina_markirovka {
Expand Down Expand Up @@ -101,6 +102,16 @@ const auto kPerfTestNameSTL = ArtyushkinaMarkirovkaPerfTests::CustomPerfTestName

INSTANTIATE_TEST_SUITE_P(RunModeTestsSTL, ArtyushkinaMarkirovkaPerfTests, kGtestValuesSTL, kPerfTestNameSTL);

// TBB тесты
const auto kAllPerfTasksTBB =
ppc::util::MakeAllPerfTasks<InType, MarkingComponentsTBB>(PPC_SETTINGS_artyushkina_markirovka);

const auto kGtestValuesTBB = ppc::util::TupleToGTestValues(kAllPerfTasksTBB);

const auto kPerfTestNameTBB = ArtyushkinaMarkirovkaPerfTests::CustomPerfTestName;

INSTANTIATE_TEST_SUITE_P(RunModeTestsTBB, ArtyushkinaMarkirovkaPerfTests, kGtestValuesTBB, kPerfTestNameTBB);

} // namespace

} // namespace artyushkina_markirovka
Loading