Skip to content
Merged
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
1 change: 1 addition & 0 deletions benchmarks/bench-all.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
#include "bench-qselect.hpp"
#include "bench-qsort.hpp"
#include "bench-keyvalue.hpp"
#include "bench-objsort.hpp"
108 changes: 108 additions & 0 deletions benchmarks/bench-objsort.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#include <cmath>

static constexpr char x[] = "x";
static constexpr char euclidean[] = "euclidean";
static constexpr char taxicab[] = "taxicab";
static constexpr char chebyshev[] = "chebyshev";

template <const char* val>
struct Point3D {
double x;
double y;
double z;
static constexpr std::string_view name {val};
Point3D()
{
x = (double)rand() / RAND_MAX;
y = (double)rand() / RAND_MAX;
z = (double)rand() / RAND_MAX;
}
double distance()
{
if constexpr (name == "x") {
return x;
}
else if constexpr (name == "euclidean") {
return std::sqrt(x * x + y * y + z * z);
}
else if constexpr (name == "taxicab") {
return abs(x) + abs(y) + abs(z);
}
else if constexpr (name == "chebyshev") {
return std::max(std::max(x, y), z);
}
}
};

template <typename T>
std::vector<T> init_data(const int size)
{
srand(42);
std::vector<T> arr;
for (auto ii = 0; ii < size; ++ii) {
T temp;
arr.push_back(temp);
}
return arr;
}

template <typename T>
struct less_than_key {
inline bool operator()(T &p1, T &p2)
{
return (p1.distance() < p2.distance());
}
};

template <typename T>
static void scalarobjsort(benchmark::State &state)
{
// set up array
std::vector<T> arr = init_data<T>(state.range(0));
std::vector<T> arr_bkp = arr;
// benchmark
for (auto _ : state) {
std::sort(arr.begin(), arr.end(), less_than_key<T>());
state.PauseTiming();
arr = arr_bkp;
state.ResumeTiming();
}
}

template <typename T>
static void simdobjsort(benchmark::State &state)
{
// set up array
std::vector<T> arr = init_data<T>(state.range(0));
std::vector<T> arr_bkp = arr;
// benchmark
for (auto _ : state) {
x86simdsort::object_qsort(arr.data(), arr.size(), [](T p) -> double {
return p.distance();
});
state.PauseTiming();
if (!std::is_sorted(arr.begin(), arr.end(), less_than_key<T>())) {
std::cout << "sorting failed \n";
}
arr = arr_bkp;
state.ResumeTiming();
}
}

#define BENCHMARK_OBJSORT(func, T) \
BENCHMARK_TEMPLATE(func, T) \
->Arg(10e1) \
->Arg(10e2) \
->Arg(10e3) \
->Arg(10e4) \
->Arg(10e5) \
->Arg(10e6);

BENCHMARK_OBJSORT(simdobjsort, Point3D<x>)
BENCHMARK_OBJSORT(scalarobjsort, Point3D<x>)
BENCHMARK_OBJSORT(simdobjsort, Point3D<taxicab>)
BENCHMARK_OBJSORT(scalarobjsort, Point3D<taxicab>)
BENCHMARK_OBJSORT(simdobjsort, Point3D<euclidean>)
BENCHMARK_OBJSORT(scalarobjsort, Point3D<euclidean>)
BENCHMARK_OBJSORT(simdobjsort, Point3D<chebyshev>)
BENCHMARK_OBJSORT(scalarobjsort, Point3D<chebyshev>)
43 changes: 42 additions & 1 deletion lib/x86simdsort.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <stdint.h>
#include <vector>
#include <cstddef>
#include <functional>
#include <numeric>

#define XSS_EXPORT_SYMBOL __attribute__((visibility("default")))
#define XSS_HIDE_SYMBOL __attribute__((visibility("hidden")))
Expand Down Expand Up @@ -34,10 +36,49 @@ template <typename T>
XSS_EXPORT_SYMBOL std::vector<size_t>
argselect(T *arr, size_t k, size_t arrsize, bool hasnan = false);

// argselect
// keyvalue sort
template <typename T1, typename T2>
XSS_EXPORT_SYMBOL void
keyvalue_qsort(T1 *key, T2* val, size_t arrsize, bool hasnan = false);

// sort an object
template <typename T, typename Func>
XSS_EXPORT_SYMBOL void object_qsort(T *arr, size_t arrsize, Func key_func)
{
/* (1) Create a vector a keys */
using return_type_of =
typename decltype(std::function {key_func})::result_type;
Comment on lines +49 to +50

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably a C++17 technique (CTAD). If you need to support pre-C++17, you may need to rewrite it.

std::vector<return_type_of> keys;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add: keys.reserve(arrsize).

keys.reserve(arrsize);
for (size_t ii = 0; ii < arrsize; ++ii) {
keys[ii] = key_func(arr[ii]);
}

/* (2) Call arg based on keys using the keyvalue sort */
std::vector<size_t> arg(arrsize);
std::iota(arg.begin(), arg.end(), 0);
keyvalue_qsort(keys.data(), arg.data(), arrsize);

/* (3) Permute obj array in-place */
std::vector<bool> done(arrsize);
for (size_t i = 0; i < arrsize; ++i)
{
if (done[i])
{
continue;
}
done[i] = true;
size_t prev_j = i;
size_t j = arg[i];
while (i != j)
{
std::swap(arr[prev_j], arr[j]);
done[j] = true;
prev_j = j;
j = arg[j];
}
}
}

} // namespace x86simdsort
#endif
3 changes: 3 additions & 0 deletions run-bench.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
elif "keyvalue" in args.benchcompare:
baseline = "scalarkvsort.*" + filterb
contender = "simdkvsort.*" + filterb
elif "objsort" in args.benchcompare:
baseline = "scalarobjsort.*" + filterb
contender = "simdobjsort.*" + filterb
else:
parser.print_help(sys.stderr)
parser.error("ERROR: Unknown argument '%s'" % args.benchcompare)
Expand Down