diff --git a/tasks/perepelkin_i_convex_hull_graham_scan/omp/include/ops_omp.hpp b/tasks/perepelkin_i_convex_hull_graham_scan/omp/include/ops_omp.hpp index 6cd10b047..3933b434c 100644 --- a/tasks/perepelkin_i_convex_hull_graham_scan/omp/include/ops_omp.hpp +++ b/tasks/perepelkin_i_convex_hull_graham_scan/omp/include/ops_omp.hpp @@ -24,6 +24,11 @@ class PerepelkinIConvexHullGrahamScanOMP : public BaseTask { static size_t FindPivotParallel(const std::vector> &pts); static void ParallelSort(std::vector> &data, const std::pair &pivot); + + static void DataPartitioning(size_t total_size, const int &threads, std::vector &start); + static void HullConstruction(std::vector> &hull, + const std::vector> &pts, + const std::pair &pivot); static bool AngleCmp(const std::pair &a, const std::pair &b, const std::pair &pivot); static double Orientation(const std::pair &p, const std::pair &q, diff --git a/tasks/perepelkin_i_convex_hull_graham_scan/omp/src/ops_omp.cpp b/tasks/perepelkin_i_convex_hull_graham_scan/omp/src/ops_omp.cpp index e2a52998b..46ac7d7bf 100644 --- a/tasks/perepelkin_i_convex_hull_graham_scan/omp/src/ops_omp.cpp +++ b/tasks/perepelkin_i_convex_hull_graham_scan/omp/src/ops_omp.cpp @@ -47,44 +47,41 @@ bool PerepelkinIConvexHullGrahamScanOMP::RunImpl() { // Sequential hull construction std::vector> hull; - hull.reserve(pts.size() + 1); - - hull.push_back(pivot); - hull.push_back(pts[0]); - - for (size_t i = 1; i < pts.size(); i++) { - while (hull.size() >= 2 && Orientation(hull[hull.size() - 2], hull[hull.size() - 1], pts[i]) <= 0) { - hull.pop_back(); - } - - hull.push_back(pts[i]); - } + HullConstruction(hull, pts, pivot); GetOutput() = std::move(hull); return true; } size_t PerepelkinIConvexHullGrahamScanOMP::FindPivotParallel(const std::vector> &pts) { - size_t pivot_idx = 0; + const int threads = std::min(ppc::util::GetNumThreads(), static_cast(pts.size())); + std::vector local_idx(threads, 0); -#pragma omp parallel default(none) shared(pts, pivot_idx) num_threads(ppc::util::GetNumThreads()) +#pragma omp parallel default(none) shared(pts, local_idx) num_threads(threads) { - size_t local_idx = pivot_idx; + int tid = omp_get_thread_num(); + size_t local = 0; #pragma omp for nowait for (size_t i = 1; i < pts.size(); i++) { - if (pts[i].second < pts[local_idx].second || - (pts[i].second == pts[local_idx].second && pts[i].first < pts[local_idx].first)) { - local_idx = i; + if (pts[i].second < pts[local].second || + (pts[i].second == pts[local].second && pts[i].first < pts[local].first)) { + local = i; } } -#pragma omp critical - { - if (pts[local_idx].second < pts[pivot_idx].second || - (pts[local_idx].second == pts[pivot_idx].second && pts[local_idx].first < pts[pivot_idx].first)) { - pivot_idx = local_idx; - } + local_idx[tid] = local; + } + + // Sequential reduction + size_t pivot_idx = 0; + + for (int tid = 0; tid < threads; tid++) { + size_t i = local_idx[tid]; + + if (pts[i].second < pts[pivot_idx].second || + (pts[i].second == pts[pivot_idx].second && pts[i].first < pts[pivot_idx].first)) { + pivot_idx = i; } } @@ -93,20 +90,14 @@ size_t PerepelkinIConvexHullGrahamScanOMP::FindPivotParallel(const std::vector> &data, const std::pair &pivot) { - size_t n = data.size(); - int threads = ppc::util::GetNumThreads(); - - if (n < 10000) { - std::ranges::sort(data, [&](const auto &a, const auto &b) { return AngleCmp(a, b, pivot); }); - return; - } + const int threads = std::min(ppc::util::GetNumThreads(), static_cast(data.size())); + // Partitioning std::vector start(threads + 1); - for (int i = 0; i <= threads; i++) { - start[i] = static_cast(i * n / threads); - } + DataPartitioning(data.size(), threads, start); -#pragma omp parallel default(none) shared(data, start, pivot) num_threads(ppc::util::GetNumThreads()) + // Parallel local sorting +#pragma omp parallel default(none) shared(data, start, pivot) num_threads(threads) { int tid = omp_get_thread_num(); std::sort(data.begin() + start[tid], data.begin() + start[tid + 1], @@ -115,7 +106,7 @@ void PerepelkinIConvexHullGrahamScanOMP::ParallelSort(std::vector= threads) { continue; @@ -131,6 +122,40 @@ void PerepelkinIConvexHullGrahamScanOMP::ParallelSort(std::vector &start) { + size_t base = total_size / threads; + size_t rem = total_size % threads; + + size_t offset = 0; + + for (int i = 0; i < threads; i++) { + start[i] = static_cast(offset); + + size_t extra = std::cmp_less(i, rem) ? 1 : 0; + offset += base + extra; + } + + start[threads] = static_cast(total_size); +} + +void PerepelkinIConvexHullGrahamScanOMP::HullConstruction(std::vector> &hull, + const std::vector> &pts, + const std::pair &pivot) { + hull.reserve(pts.size() + 1); + + hull.push_back(pivot); + hull.push_back(pts[0]); + + for (size_t i = 1; i < pts.size(); i++) { + while (hull.size() >= 2 && Orientation(hull[hull.size() - 2], hull[hull.size() - 1], pts[i]) <= 0) { + hull.pop_back(); + } + + hull.push_back(pts[i]); + } +} + double PerepelkinIConvexHullGrahamScanOMP::Orientation(const std::pair &p, const std::pair &q, const std::pair &r) {