Implement parallel version of mergesort
This commit is contained in:
parent
304af488ce
commit
c560bfe4cc
@ -44,23 +44,54 @@ auto main(int argc, char *argv[]) -> int {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt::print("Opened file {} sucessfully!\n", "dummy");
|
fmt::print("Opened file {} sucessfully\n", "dummy");
|
||||||
std::vector<int32_t> dataset;
|
std::vector<int32_t> dataset;
|
||||||
|
|
||||||
parse_file(file, dataset);
|
parse_file(file, dataset);
|
||||||
fmt::print("Read {} values from {}\n", dataset.size(), "dummy");
|
fmt::print("Read {} values from {}\n", dataset.size(), "dummy");
|
||||||
|
|
||||||
auto t1 = std::chrono::high_resolution_clock::now();
|
auto dataset_par = dataset;
|
||||||
|
auto dataset_seq = dataset;
|
||||||
|
|
||||||
algo::MergeSort_v1::sort(dataset.begin(), dataset.end(), [](int32_t a, int32_t b) {
|
auto t1 = std::chrono::high_resolution_clock::now();
|
||||||
|
algo::MergeSort_v1::sort(dataset_seq.begin(), dataset_seq.end(), [](int32_t a, int32_t b) {
|
||||||
return (a > b);
|
return (a > b);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto t2 = std::chrono::high_resolution_clock::now();
|
auto t2 = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
|
||||||
auto delay_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);
|
auto delay_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);
|
||||||
fmt::print("Sorted {} entries within {} ms.", dataset.size(), delay_ms.count());
|
fmt::print("Sorted {} entries within {} ms in sequential\n", dataset_seq.size(), delay_ms.count());
|
||||||
|
|
||||||
|
t1 = std::chrono::high_resolution_clock::now();
|
||||||
|
algo::MergeSort_v2::sort(dataset_par.begin(), dataset_par.end(), [](int32_t a, int32_t b) {
|
||||||
|
return (a > b);
|
||||||
|
}, 16);
|
||||||
|
t2 = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
delay_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);
|
||||||
|
fmt::print("Sorted {} entries within {} ms in parallel using {} threads\n", dataset_seq.size(), delay_ms.count(), 16);
|
||||||
|
|
||||||
|
auto eq = (dataset_seq == dataset_par);
|
||||||
|
fmt::print("Equality: {}\n", eq);
|
||||||
|
fmt::print("Parallel dataset: {}; Sequential dataset: {}\n", dataset_par.size(), dataset_seq.size());
|
||||||
|
|
||||||
|
//fmt::print("Created {} recurstions", algo::MergeSort_v1::get_recursions());
|
||||||
|
|
||||||
|
std::ofstream ofile("dataset.out.dat", std::ios_base::out);
|
||||||
|
if(!ofile.is_open()) {
|
||||||
|
fmt::print("Error writing to file");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto &element : dataset_seq) {
|
||||||
|
ofile << std::to_string(element) << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
ofile.flush();
|
||||||
|
ofile.close();
|
||||||
|
|
||||||
|
fmt::print("Written to output file\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -2,13 +2,16 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
namespace algo {
|
namespace algo {
|
||||||
|
|
||||||
class MergeSort_v1 {
|
class MergeSort_v1 {
|
||||||
private:
|
private:
|
||||||
template<typename Iterator, typename Comparator>
|
template<typename Iterator, typename Comparator>
|
||||||
static auto merge(Iterator start, Iterator middle, Iterator end, Comparator cmp, Iterator output_start) -> void {
|
static auto
|
||||||
|
merge(Iterator start, Iterator middle, Iterator end, Comparator cmp, Iterator output_start) -> void {
|
||||||
Iterator start_m = start;
|
Iterator start_m = start;
|
||||||
Iterator begin = output_start;
|
Iterator begin = output_start;
|
||||||
Iterator start2 = middle + 1;
|
Iterator start2 = middle + 1;
|
||||||
@ -46,7 +49,8 @@ namespace algo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename Container, typename Iterator, typename Comparator>
|
template<typename Container, typename Iterator, typename Comparator>
|
||||||
static auto ms_split(Container &output_vec, Iterator start, Iterator end, Comparator cmp, Iterator output_start) -> void {
|
static auto
|
||||||
|
ms_split(Container &output_vec, Iterator start, Iterator end, Comparator cmp, Iterator output_start) -> void {
|
||||||
Iterator mid = start;
|
Iterator mid = start;
|
||||||
Iterator begin = output_start;
|
Iterator begin = output_start;
|
||||||
|
|
||||||
@ -77,4 +81,106 @@ namespace algo {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MergeSort_v2 {
|
||||||
|
private:
|
||||||
|
//Caution: non thread-safe, must be executed with additional protection (e.g. lock_guard)
|
||||||
|
template<typename Iterator, typename Comparator>
|
||||||
|
static auto
|
||||||
|
merge(Iterator start, Iterator middle, Iterator end, Comparator cmp, Iterator output_start) -> void {
|
||||||
|
Iterator start_m = start;
|
||||||
|
Iterator begin = output_start;
|
||||||
|
Iterator start2 = middle + 1;
|
||||||
|
|
||||||
|
//merge from input until one half completes
|
||||||
|
while (start <= middle && start2 <= end) {
|
||||||
|
if (cmp(*start, *start2)) {
|
||||||
|
*output_start = *start;
|
||||||
|
start++;
|
||||||
|
} else {
|
||||||
|
*output_start = *start2;
|
||||||
|
start2++;
|
||||||
|
}
|
||||||
|
output_start++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//try to finish first half
|
||||||
|
while (start <= middle) {
|
||||||
|
*output_start = *start;
|
||||||
|
start++;
|
||||||
|
output_start++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (start2 <= end) {
|
||||||
|
*output_start = *start2;
|
||||||
|
start2++;
|
||||||
|
output_start++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto size = std::distance(start_m, end);
|
||||||
|
for (auto i = 0; i <= size; i++, start_m++, begin++) {
|
||||||
|
*start_m = *begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Container, typename Iterator, typename Comparator>
|
||||||
|
static auto ms_split(Container &output_vec, Iterator start, Iterator end, Comparator cmp, Iterator output_start,
|
||||||
|
int &nthreads, std::mutex &dataset_guard, std::mutex &depth_guard) -> void {
|
||||||
|
Iterator mid = start;
|
||||||
|
Iterator begin = output_start;
|
||||||
|
|
||||||
|
if (std::distance(start, end) < 1) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (nthreads > 1) {
|
||||||
|
depth_guard.lock();
|
||||||
|
nthreads -= 2;
|
||||||
|
depth_guard.unlock();
|
||||||
|
//move mid iterator litterally to the mid
|
||||||
|
std::advance(mid, std::distance(start, end) / 2);
|
||||||
|
//sort the first half within an recursion
|
||||||
|
|
||||||
|
std::thread t1([&]() { ms_split(output_vec, start, mid, cmp, output_start, nthreads, dataset_guard, depth_guard); });
|
||||||
|
|
||||||
|
//move output iteratoroutput_vec, start, mid, cmp, output_start
|
||||||
|
std::advance(output_start, std::distance(start, mid + 1));
|
||||||
|
//sort the second half within a recursion
|
||||||
|
std::thread t2([&]() { ms_split(output_vec, mid + 1, end, cmp, output_start, nthreads, dataset_guard, depth_guard); });
|
||||||
|
|
||||||
|
|
||||||
|
//merge everything together starting from the complete beginning
|
||||||
|
t1.join();
|
||||||
|
t2.join();
|
||||||
|
const std::lock_guard<std::mutex> lock(dataset_guard);
|
||||||
|
merge(start, mid, end, cmp, begin);
|
||||||
|
} else {
|
||||||
|
//move mid iterator litterally to the mid
|
||||||
|
std::advance(mid, std::distance(start, end) / 2);
|
||||||
|
//sort the first half within an recursion
|
||||||
|
ms_split(output_vec, start, mid, cmp, output_start, nthreads, dataset_guard, depth_guard);
|
||||||
|
|
||||||
|
//move output iterator
|
||||||
|
std::advance(output_start, std::distance(start, mid + 1));
|
||||||
|
//sort the second half within a recursion
|
||||||
|
ms_split(output_vec, mid + 1, end, cmp, output_start, nthreads, dataset_guard, depth_guard);
|
||||||
|
|
||||||
|
//merge everything together starting from the complete beginning
|
||||||
|
const std::lock_guard<std::mutex> lock(dataset_guard);
|
||||||
|
merge(start, mid, end, cmp, begin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<typename Iterator, typename Comparator>
|
||||||
|
static auto sort(Iterator start, Iterator end, Comparator cmp, int nthreads) -> void {
|
||||||
|
using valtype = typename std::iterator_traits<Iterator>::value_type;
|
||||||
|
std::vector<valtype> temporary_dataset(std::distance(start, end));
|
||||||
|
std::mutex dataset_guard;
|
||||||
|
std::mutex depth_guard;
|
||||||
|
|
||||||
|
ms_split(temporary_dataset, start, end - 1, cmp, temporary_dataset.begin(), nthreads, dataset_guard, depth_guard);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user