Skip to content

Parallel sort algorithm performance on Threadripper #1238

Description

@ohhmm

Hi,

I tried to use std::sort(std::execution::par parallel implementation using custom predicate on gigabytes of data.
Unfortunately its result gave no much benefit comparably to single-thread std::sort.
Simple custom implementation of merge-sort gave much better benefit:

		auto TotalThreads = std::thread::hardware_concurrency();

		template<class Iter, class Pred>
		void quick_merge_sort(Iter first, Iter last, Pred pred)
		{
			auto length = last - first;
			auto chunkSize = length / TotalThreads;
			auto chunks = length / chunkSize;
			if (chunkSize > 1)
			{
				auto tail = length - (chunkSize * chunks);
				auto hasTail = tail > 0;
				auto tailStart = first + chunks * chunkSize;
				{
					std::deque<std::future<void>> tasks;

					for (auto thread = 0; thread < chunks; ++thread) {
						auto chunkStart = first + thread * chunkSize;
						auto chunkEnd = chunkStart + chunkSize;
						tasks.emplace_back(std::async(std::launch::async, &std::sort<Iter, Pred>, chunkStart, chunkEnd, pred));
					}

					if (hasTail)
						std::sort(tailStart, last, pred);

					while (chunkSize < length)
					{
						auto bigChunkStart = first;
						auto bigChunkMiddle = bigChunkStart;
						auto bigChunkEnd = bigChunkStart;
						for (auto thread = 0; thread < chunks; ++thread) {
							tasks.pop_front();
							bigChunkEnd = bigChunkMiddle + chunkSize;
							if (thread % 2) {
								tasks.emplace_back(std::async(std::launch::async, &std::inplace_merge<Iter, Pred>, bigChunkStart, bigChunkMiddle, bigChunkEnd, pred));
								bigChunkStart = bigChunkEnd;
							}
							bigChunkMiddle += chunkSize;
						}

						chunkSize *= 2;
						chunks = length / chunkSize;
					}
				} // ensure tasks completion

				if (hasTail) {
					std::inplace_merge(first, tailStart, last, pred);
				}
			}
			else if (length > 1) {
				std::sort(first, last, pred);
			}

			assert(std::is_sorted(first, last, pred));
		}
	}

This code still has range-way to improve CPU threads utilization, but it gave much more benefit of parallelization.
How much threads are used to sort with parallel executor?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    performanceMust go fasterwontfixThis will not be worked on

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions