thesis version
This commit is contained in:
231
benchmarks/basic.cpp
Normal file
231
benchmarks/basic.cpp
Normal file
@ -0,0 +1,231 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
constexpr std::size_t K = 1'000;
|
||||
|
||||
std::size_t pfor::ParallelForParameters::nThreads{1};
|
||||
|
||||
struct Arguments {
|
||||
std::size_t arraySize;
|
||||
std::string method;
|
||||
std::size_t sample;
|
||||
};
|
||||
|
||||
Arguments processCLA(int argc, char** argv) {
|
||||
if(argc < 4) {
|
||||
std::cerr << "Usage: " << *argv << " N method #sample [nThreads]" << std::endl;
|
||||
std::cerr << " N: array size (1..1000000)" << std::endl;
|
||||
std::cerr << " method: {seq, omp, gen_omp, gen_thread}" << std::endl;
|
||||
std::cerr << " #sample: {0: full sequential, 1: full parallel, 2: mixed sequential/parallel}" << std::endl;
|
||||
std::cerr << " nThreads: defaults to 1" << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
Arguments args;
|
||||
|
||||
{
|
||||
std::istringstream iss{argv[1]};
|
||||
iss >> args.arraySize;
|
||||
}
|
||||
args.method = std::string{argv[2]};
|
||||
{
|
||||
std::istringstream iss{argv[3]};
|
||||
iss >> args.sample;
|
||||
}
|
||||
|
||||
if(argc >= 5) {
|
||||
std::istringstream iss{argv[4]};
|
||||
iss >> pfor::ParallelForParameters::nThreads;
|
||||
}
|
||||
|
||||
|
||||
if(args.arraySize < 1 || args.arraySize > 10000000) {
|
||||
std::cerr << "N out of bounds" << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
if(args.method != "seq" && args.method != "omp" && args.method != "gen_omp" && args.method != "gen_thread") {
|
||||
std::cerr << "method out of bounds" << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
if(args.sample > 2) {
|
||||
std::cerr << "#sample out of bounds" << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
if(args.method == "omp" && args.sample == 0) {
|
||||
std::cerr << "incoherent method/#sample" << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
using T = int;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
Arguments args = processCLA(argc, argv);
|
||||
long const N = args.arraySize;
|
||||
|
||||
OPERAND(T, a0, N, i++);
|
||||
OPERAND(T, a1, N, i++);
|
||||
OPERAND(T, a2, N, i++);
|
||||
OPERAND(T, a3, N, i++);
|
||||
OPERAND(T, a4, N, i++);
|
||||
OPERAND(T, a5, N, i++);
|
||||
OPERAND(T, a6, N, i++);
|
||||
OPERAND(T, a7, N, i++);
|
||||
|
||||
if(args.sample == 0) {
|
||||
/*
|
||||
* Sample 0: sequential
|
||||
*/
|
||||
// arraysPrinter(K, N, a0, a1, a2, a5);
|
||||
|
||||
if(args.method == "seq") {
|
||||
BENCH(K)
|
||||
for(long i = 0; i < N-1; ++i) {
|
||||
a0_[i] = a0_[i+1] + a1_[i] * a2_[i];
|
||||
a1_[i] = a1_[i+1] + a2_[i] * a3_[i];
|
||||
a2_[i] = a2_[i+1] + a3_[i] * a4_[i];
|
||||
a5_[i] = a5_[i+1] + a6_[i] * a7_[i];
|
||||
}
|
||||
END_BENCH();
|
||||
} else if(args.method == "gen_omp") {
|
||||
BENCH(K)
|
||||
pfor::parallelFor<pfor::ForLoopOMP>(pfor::Range{0, N-1}, [&](pfor::Index i) {
|
||||
return
|
||||
a0[i] = a0[i+_<1>] + a1[i] * a2[i],
|
||||
a1[i] = a1[i+_<1>] + a2[i] * a3[i],
|
||||
a2[i] = a2[i+_<1>] + a3[i] * a4[i],
|
||||
a5[i] = a5[i+_<1>] + a6[i] * a7[i];
|
||||
});
|
||||
END_BENCH();
|
||||
} else if(args.method == "gen_thread") {
|
||||
BENCH(K)
|
||||
pfor::parallelFor<pfor::ForLoopThread>(pfor::Range{0, N-1}, [&](pfor::Index i) {
|
||||
return
|
||||
a0[i] = a0[i+_<1>] + a1[i] * a2[i],
|
||||
a1[i] = a1[i+_<1>] + a2[i] * a3[i],
|
||||
a2[i] = a2[i+_<1>] + a3[i] * a4[i],
|
||||
a5[i] = a5[i+_<1>] + a6[i] * a7[i];
|
||||
});
|
||||
END_BENCH();
|
||||
}
|
||||
|
||||
// arraysPrinter(K, N, a0, a1, a2, a5);
|
||||
} else if(args.sample == 1) {
|
||||
/*
|
||||
* Sample 1: parallel
|
||||
*/
|
||||
if(args.method == "seq") {
|
||||
BENCH(K)
|
||||
for(long i = 0; i < N; ++i) {
|
||||
a0_[i] = a0_[i] + a1_[i] * a2_[i];
|
||||
a1_[i] = a1_[i] + a2_[i] * a3_[i];
|
||||
a2_[i] = a2_[i] + a3_[i] * a4_[i];
|
||||
a5_[i] = a5_[i] + a6_[i] * a7_[i];
|
||||
}
|
||||
END_BENCH();
|
||||
} else if(args.method == "omp") {
|
||||
BENCH(K)
|
||||
#pragma omp parallel for num_threads(pfor::ParallelForParameters::nThreads)
|
||||
for(long i = 0; i < N; ++i) {
|
||||
a0_[i] = a0_[i] + a1_[i] * a2_[i];
|
||||
a1_[i] = a1_[i] + a2_[i] * a3_[i];
|
||||
a2_[i] = a2_[i] + a3_[i] * a4_[i];
|
||||
a5_[i] = a5_[i] + a6_[i] * a7_[i];
|
||||
}
|
||||
END_BENCH();
|
||||
} else if(args.method == "gen_omp") {
|
||||
BENCH(K)
|
||||
pfor::parallelFor<pfor::ForLoopOMP>(pfor::Range{0, N}, [&](pfor::Index i) {
|
||||
return
|
||||
a0[i] = a0[i] + a1[i] * a2[i],
|
||||
a1[i] = a1[i] + a2[i] * a3[i],
|
||||
a2[i] = a2[i] + a3[i] * a4[i],
|
||||
a5[i] = a5[i] + a6[i] * a7[i];
|
||||
});
|
||||
END_BENCH();
|
||||
} else if(args.method == "gen_thread") {
|
||||
BENCH(K)
|
||||
pfor::parallelFor<pfor::ForLoopThread>(pfor::Range{0, N}, [&](pfor::Index i) {
|
||||
return
|
||||
a0[i] = a0[i] + a1[i] * a2[i],
|
||||
a1[i] = a1[i] + a2[i] * a3[i],
|
||||
a2[i] = a2[i] + a3[i] * a4[i],
|
||||
a5[i] = a5[i] + a6[i] * a7[i];
|
||||
});
|
||||
END_BENCH();
|
||||
}
|
||||
} else if(args.sample == 2) {
|
||||
/*
|
||||
* Sample 2: mixed sequential and parallel
|
||||
*/
|
||||
// arraysPrinter(K, N, a0, a1, a2, a3, a4, a5, a6, a7);
|
||||
|
||||
if(args.method == "seq") {
|
||||
BENCH(K)
|
||||
for(long i = 0; i < N-1; ++i) {
|
||||
a0_[i] = a0_[i] + a1_[i] * a2_[i];
|
||||
a1_[i] = a1_[i] + a2_[i] * a3_[i];
|
||||
}
|
||||
for(long i = 0; i < N-1; ++i) {
|
||||
a4_[i] = a4_[i+1] + a5_[i] * a7_[i];
|
||||
a5_[i] = a5_[i+1] + a6_[i] * a7_[i];
|
||||
}
|
||||
END_BENCH();
|
||||
} else if(args.method == "omp") {
|
||||
BENCH(K)
|
||||
#pragma omp parallel for num_threads(pfor::ParallelForParameters::nThreads)
|
||||
for(long i = 0; i < N-1; ++i) {
|
||||
a0_[i] = a0_[i] + a1_[i] * a2_[i];
|
||||
a1_[i] = a1_[i] + a2_[i] * a3_[i];
|
||||
}
|
||||
// Sequential
|
||||
for(long i = 0; i < N-1; ++i) {
|
||||
a4_[i] = a4_[i+1] + a5_[i] * a7_[i];
|
||||
a5_[i] = a5_[i+1] + a6_[i] * a7_[i];
|
||||
}
|
||||
END_BENCH();
|
||||
} else if(args.method == "gen_omp") {
|
||||
BENCH(K)
|
||||
pfor::parallelFor<pfor::ForLoopOMP>(pfor::Range{0, N-1}, [&](pfor::Index i) {
|
||||
return
|
||||
a0[i] = a0[i] + a1[i] * a2[i],
|
||||
a1[i] = a1[i] + a2[i] * a3[i],
|
||||
a4[i] = a4[i+_<1>] + a5[i] * a7[i],
|
||||
a5[i] = a5[i+_<1>] + a6[i] * a7[i];
|
||||
});
|
||||
END_BENCH();
|
||||
} else if(args.method == "gen_thread") {
|
||||
BENCH(K)
|
||||
pfor::parallelFor<pfor::ForLoopThread>(pfor::Range{0, N-1}, [&](pfor::Index i) {
|
||||
return
|
||||
a0[i] = a0[i] + a1[i] * a2[i],
|
||||
a1[i] = a1[i] + a2[i] * a3[i],
|
||||
a4[i] = a4[i+_<1>] + a5[i] * a7[i],
|
||||
a5[i] = a5[i+_<1>] + a6[i] * a7[i];
|
||||
});
|
||||
END_BENCH();
|
||||
}
|
||||
|
||||
// arraysPrinter(K, N, a0, a1, a2, a3, a4, a5, a6, a7);
|
||||
}
|
||||
|
||||
if(rand()==rand()) arraysPrinter(1ul, N, a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_);
|
||||
|
||||
END_OPERAND(a0);
|
||||
END_OPERAND(a1);
|
||||
END_OPERAND(a2);
|
||||
END_OPERAND(a3);
|
||||
END_OPERAND(a4);
|
||||
END_OPERAND(a5);
|
||||
END_OPERAND(a6);
|
||||
END_OPERAND(a7);
|
||||
}
|
65
benchmarks/common.h
Normal file
65
benchmarks/common.h
Normal file
@ -0,0 +1,65 @@
|
||||
#ifndef PFOR_BENCHMARKS_COMMON_H
|
||||
#define PFOR_BENCHMARKS_COMMON_H
|
||||
|
||||
#include <iostream>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <pfor/pfor.h>
|
||||
|
||||
template<std::size_t n>
|
||||
constexpr auto _ = pfor::ctv<n>;
|
||||
|
||||
using TimePoint = std::tuple<long, long>;
|
||||
|
||||
TimePoint timepoint() {
|
||||
struct rusage usage;
|
||||
getrusage(RUSAGE_SELF, &usage);
|
||||
|
||||
long realSec = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
|
||||
long realUsec = usage.ru_utime.tv_usec + usage.ru_stime.tv_usec;
|
||||
|
||||
return {realSec, realUsec};
|
||||
}
|
||||
|
||||
double timediff(TimePoint const& from, TimePoint const& to) {
|
||||
return std::get<0>(to)-std::get<0>(from) + (std::get<1>(to)-std::get<1>(from))/1'000'000.;
|
||||
}
|
||||
|
||||
// Operand utility
|
||||
#define OPERAND(Type, name, size, filler) \
|
||||
Type * name##_ = new Type[size]; \
|
||||
{ \
|
||||
std::size_t i = 0; \
|
||||
std::generate_n(name##_, size, [&i]{ return filler; }); \
|
||||
} \
|
||||
auto name = pfor::Operand<Type*, class ID##name>(name##_);
|
||||
|
||||
#define END_OPERAND(name) delete[] name##_
|
||||
|
||||
// Bench utility
|
||||
#define BENCH(K) { \
|
||||
TimePoint tp0 = timepoint(); \
|
||||
for(std::size_t k_ = 0; k_ < K; ++k_) {
|
||||
|
||||
#define END_BENCH() } \
|
||||
TimePoint tp1 = timepoint(); \
|
||||
std::cout << "time: " << timediff(tp0, tp1) << std::endl; \
|
||||
}
|
||||
|
||||
template<typename K, typename S>
|
||||
void arraysPrinter(K, S) {}
|
||||
|
||||
template<typename K, typename S, typename T, typename... Ts>
|
||||
void arraysPrinter(K k, S n, T&& array, Ts&&... arrays) {
|
||||
if(k != 1) {
|
||||
std::cerr << "warning: displays may be false, must set K to 1" << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
for(S i = 0; i < n; ++i)
|
||||
std::cout << std::forward<T>(array)[i] << ", ";
|
||||
std::cout << std::endl;
|
||||
arraysPrinter(k, n, std::forward<Ts>(arrays)...);
|
||||
}
|
||||
|
||||
#endif
|
101
benchmarks/imgpro.cpp
Normal file
101
benchmarks/imgpro.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <cmath>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
constexpr std::size_t K = 1;
|
||||
|
||||
constexpr long W = 100'001;
|
||||
constexpr long H = 100'000;
|
||||
|
||||
std::size_t pfor::ParallelForParameters::nThreads{1};
|
||||
|
||||
struct Arguments {
|
||||
std::string method;
|
||||
};
|
||||
|
||||
Arguments processCLA(int argc, char** argv) {
|
||||
if(argc < 2) {
|
||||
std::cerr << "Usage: " << *argv << " method [nThreads]" << std::endl;
|
||||
std::cerr << " method: {seq, omp, gen_omp, gen_thread}" << std::endl;
|
||||
std::cerr << " nThreads: defaults to 1" << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
Arguments args;
|
||||
|
||||
args.method = std::string{argv[1]};
|
||||
|
||||
if(argc >= 3) {
|
||||
std::istringstream iss{argv[2]};
|
||||
iss >> pfor::ParallelForParameters::nThreads;
|
||||
}
|
||||
|
||||
|
||||
if(args.method != "seq" && args.method != "omp" && args.method != "gen_omp" && args.method != "gen_thread") {
|
||||
std::cerr << "method out of bounds" << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
char r(int c) { return (c>>24&0xff); }
|
||||
char g(int c) { return (c>>16&0xff); }
|
||||
char b(int c) { return (c>>8&0xff); }
|
||||
char a(int c) { return (c>>0&0xff); }
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Arguments args = processCLA(argc, argv);
|
||||
|
||||
auto img_ = new int[W*H]; // 4 channels (rgba); W*H image
|
||||
auto img = pfor::Operand<decltype(img_), class Img>{img_};
|
||||
|
||||
auto calc_ = [](int n, int w, int s, int e) {
|
||||
auto volatile c = 0;
|
||||
for(int i = 0; i < 10; ++i) ++c;
|
||||
return (n+w+s+e)/4;
|
||||
};
|
||||
auto calc = pfor::makeOperator(calc_);
|
||||
|
||||
if(args.method == "seq") {
|
||||
BENCH(K)
|
||||
for(long i = W+1; i < (H-1)*W; i += 2) {
|
||||
img_[i] = calc_(img_[i-W], img_[i-1], img_[i+W], img_[i+1]);
|
||||
}
|
||||
END_BENCH();
|
||||
} else if(args.method == "omp") {
|
||||
BENCH(K)
|
||||
#pragma omp parallel for num_threads(pfor::ParallelForParameters::nThreads)
|
||||
for(long i = W+1; i < (H-1)*W; i += 2) {
|
||||
img_[i] = calc_(img_[i-W], img_[i-1], img_[i+W], img_[i+1]);
|
||||
}
|
||||
END_BENCH();
|
||||
} else if(args.method == "gen_omp") {
|
||||
BENCH(K)
|
||||
pfor::Index i;
|
||||
pfor::parallelFor<pfor::ForLoopOMP>(pfor::RangeCT<W+1, 2>{(H-1)*W},
|
||||
// pfor::parallelFor<pfor::ForLoopOMP>(pfor::Range{W+1, (H-1)*W, 1},
|
||||
img[i] = calc(img[i-_<W>], img[i-_<1>], img[i+_<W>], img[i+_<1>])
|
||||
);
|
||||
END_BENCH();
|
||||
} else if(args.method == "gen_thread") {
|
||||
BENCH(K)
|
||||
pfor::Index i;
|
||||
pfor::parallelFor<pfor::ForLoopThread>(pfor::RangeCT<W+1, 2>{(H-1)*W},
|
||||
img[i] = calc(img[i-_<W>], img[i-_<1>], img[i+_<W>], img[i+_<1>])
|
||||
);
|
||||
END_BENCH();
|
||||
}
|
||||
|
||||
if(rand()==rand()) {
|
||||
for(long i = 0; i<W*H; ++i)
|
||||
std::printf("%d,", img_[i]);
|
||||
std::puts("");
|
||||
}
|
||||
|
||||
delete[] img_;
|
||||
}
|
97
benchmarks/seq.cpp
Normal file
97
benchmarks/seq.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
constexpr std::size_t K = 1'000;
|
||||
|
||||
std::size_t pfor::ParallelForParameters::nThreads{1};
|
||||
|
||||
struct Arguments {
|
||||
std::size_t arraySize;
|
||||
std::string method;
|
||||
};
|
||||
|
||||
Arguments processCLA(int argc, char **argv) {
|
||||
if(argc < 2) {
|
||||
std::cerr << "Usage: " << *argv << " N method" << std::endl;
|
||||
std::cerr << " N: array size (1..1000000)" << std::endl;
|
||||
std::cerr << " method: {seq, gen}" << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
Arguments args;
|
||||
|
||||
{
|
||||
std::istringstream iss{argv[1]};
|
||||
iss >> args.arraySize;
|
||||
}
|
||||
args.method = std::string{argv[2]};
|
||||
|
||||
if(args.arraySize < 1 || args.arraySize > 1000000) {
|
||||
std::cerr << "N out of bounds" << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
if(args.method != "seq" && args.method != "gen") {
|
||||
std::cerr << "method out of bounds" << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
using T = int;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
Arguments args = processCLA(argc, argv);
|
||||
std::size_t const N = args.arraySize;
|
||||
|
||||
OPERAND(T, a0, N, i++);
|
||||
OPERAND(T, a1, N, i++);
|
||||
OPERAND(T, a2, N, i++);
|
||||
OPERAND(T, a3, N, i++);
|
||||
OPERAND(T, a4, N, i++);
|
||||
OPERAND(T, a5, N, i++);
|
||||
OPERAND(T, a6, N, i++);
|
||||
OPERAND(T, a7, N, i++);
|
||||
|
||||
/*
|
||||
* Sample 0: sequential
|
||||
*/
|
||||
// arraysPrinter(K, N, a0, a1, a2, a5);
|
||||
|
||||
if(args.method == "seq") {
|
||||
BENCH(K)
|
||||
for(std::size_t i = 0; i < N-1; ++i) {
|
||||
a0_[i] = a0_[i+1] + a1_[i] * a2_[i];
|
||||
a1_[i] = a1_[i+1] + a2_[i] * a3_[i];
|
||||
a2_[i] = a2_[i+1] + a3_[i] * a4_[i];
|
||||
a5_[i] = a5_[i+1] + a6_[i] * a7_[i];
|
||||
}
|
||||
END_BENCH();
|
||||
} else if(args.method == "gen") {
|
||||
BENCH(K)
|
||||
pfor::parallelFor(pfor::Range{0, static_cast<long>(N-1)}, [&](pfor::Index i) {
|
||||
return
|
||||
a0[i] = a0[i+_<1>] + a1[i] * a2[i],
|
||||
a1[i] = a1[i+_<1>] + a2[i] * a3[i],
|
||||
a2[i] = a2[i+_<1>] + a3[i] * a4[i],
|
||||
a5[i] = a5[i+_<1>] + a6[i] * a7[i];
|
||||
});
|
||||
END_BENCH();
|
||||
}
|
||||
|
||||
if(rand() == rand()) arraysPrinter(1, N, a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_);
|
||||
|
||||
END_OPERAND(a0);
|
||||
END_OPERAND(a1);
|
||||
END_OPERAND(a2);
|
||||
END_OPERAND(a3);
|
||||
END_OPERAND(a4);
|
||||
END_OPERAND(a5);
|
||||
END_OPERAND(a6);
|
||||
END_OPERAND(a7);
|
||||
}
|
Reference in New Issue
Block a user