26#include <boost/accumulators/accumulators.hpp>
27#include <boost/accumulators/statistics/mean.hpp>
28#include <boost/accumulators/statistics/stats.hpp>
29#include <boost/accumulators/statistics/variance.hpp>
30#include <boost/test/unit_test.hpp>
31#include <boost/timer/timer.hpp>
39BOOST_AUTO_TEST_SUITE(ComputeEnvironmentTest)
41struct ComputeEnvironmentFixture {
42 ComputeEnvironmentFixture() {
43 QuantExt::ComputeFrameworkRegistry::instance().add(
44 "OpenCL", &QuantExt::createComputeFrameworkCreator<QuantExt::OpenClFramework>,
true);
45 QuantExt::ComputeFrameworkRegistry::instance().add(
46 "BasicCpu", &QuantExt::createComputeFrameworkCreator<QuantExt::BasicCpuFramework>,
true);
48 ~ComputeEnvironmentFixture() { ComputeEnvironment::instance().reset(); }
57 <<
" MFLOPS (raw + data copy)");
62 <<
" MFLOPS (raw + data copy + program build)");
67 BOOST_TEST_MESSAGE(
"testing enviroment initialization");
68 ComputeEnvironmentFixture fixture;
70 for (
auto const& d : ComputeEnvironment::instance().getAvailableDevices()) {
71 ComputeEnvironment::instance().selectContext(d);
72 ComputeEnvironment::instance().context().init();
73 BOOST_TEST_MESSAGE(
" device '" << d <<
"' initialized.");
74 for (
auto const& [field, value] : ComputeEnvironment::instance().context().deviceInfo()) {
75 BOOST_TEST_MESSAGE(
" " << std::left << std::setw(30) << field <<
": '" << value <<
"'");
77 BOOST_TEST_MESSAGE(
" " << std::left << std::setw(30) <<
"supportsDoublePrecision"
78 <<
": " << std::boolalpha
79 << ComputeEnvironment::instance().context().supportsDoublePrecision());
82 BOOST_CHECK_NO_THROW(init());
86 ComputeEnvironmentFixture fixture;
87 const std::size_t n = 1024;
88 for (
auto const& d : ComputeEnvironment::instance().getAvailableDevices()) {
89 BOOST_TEST_MESSAGE(
"testing simple calc on device '" << d <<
"'.");
90 ComputeEnvironment::instance().selectContext(d);
91 auto& c = ComputeEnvironment::instance().context();
93 BOOST_TEST_MESSAGE(
" do first calc");
96 std::vector<double> rx(n, 4.0);
102 std::vector<std::vector<double>> output(1, std::vector<double>(n));
104 for (
auto const& v : output.front()) {
105 BOOST_CHECK_CLOSE(v, 49.0, 1.0E-8);
108 BOOST_TEST_MESSAGE(
" do second calc using same kernel");
111 std::vector<double> rx2(n, 5.0);
114 std::vector<std::vector<double>> output2(1, std::vector<double>(n));
116 for (
auto const& v : output2.front()) {
117 BOOST_CHECK_CLOSE(v, 36.0, 1.0E-8);
123 ComputeEnvironmentFixture fixture;
124 const std::size_t n = 1024;
125 for (
auto const& d : ComputeEnvironment::instance().getAvailableDevices()) {
126 BOOST_TEST_MESSAGE(
"testing simple calc (double precision) on device '" << d <<
"'.");
127 ComputeEnvironment::instance().selectContext(d);
128 auto& c = ComputeEnvironment::instance().context();
131 BOOST_TEST_MESSAGE(
"device does not support double precision - skipping the test for this device.");
135 BOOST_TEST_MESSAGE(
" do first calc");
137 double dblPrecNumber = 1.29382757483823819;
142 std::vector<double> rx(n, dblPrecNumber);
148 std::vector<std::vector<double>> output(1, std::vector<double>(n));
150 for (
auto const& v : output.front()) {
151 BOOST_CHECK_CLOSE(v, (dblPrecNumber + dblPrecNumber) * (dblPrecNumber + dblPrecNumber), 1.0E-15);
154 BOOST_TEST_MESSAGE(
" do second calc using same kernel");
157 std::vector<double> rx2(n, dblPrecNumber);
160 std::vector<std::vector<double>> output2(1, std::vector<double>(n));
162 for (
auto const& v : output2.front()) {
163 BOOST_CHECK_CLOSE(v, (dblPrecNumber + dblPrecNumber) * (dblPrecNumber + dblPrecNumber), 1.0E-15);
169 ComputeEnvironmentFixture fixture;
171 const std::size_t n = 65536;
172 const std::size_t m = 1024;
174 std::vector<double> results;
175 for (
auto const& d : ComputeEnvironment::instance().getAvailableDevices()) {
176 BOOST_TEST_MESSAGE(
"testing large calc on device '" << d <<
"'.");
177 ComputeEnvironment::instance().selectContext(d);
178 auto& c = ComputeEnvironment::instance().context();
179 std::vector<std::size_t> values(m);
180 std::vector<double> data(n, 0.9f);
181 std::vector<std::vector<double>> output(1, std::vector<double>(n));
186 settings.
debug =
true;
189 std::size_t val = values[0];
190 for (std::size_t i = 0; i < m; ++i) {
199 BOOST_TEST_MESSAGE(
" first calculation result = " << output.front()[0]);
200 results.push_back(output.front()[0]);
207 BOOST_TEST_MESSAGE(
" second calculation result = " << output.front()[0]);
208 results.push_back(output.front()[0]);
213 std::vector<RandomVariable> values(m);
214 for (std::size_t i = 0; i < m; ++i) {
219 boost::timer::nanosecond_type t1;
220 boost::timer::cpu_timer timer;
221 for (std::size_t i = 0; i < m; ++i) {
225 t1 = timer.elapsed().wall;
226 BOOST_TEST_MESSAGE(
" testing large calc locally (benchmark)");
227 BOOST_TEST_MESSAGE(
" result = " << res.
at(0));
228 BOOST_TEST_MESSAGE(
" " << 2.0 * (
double)m * (
double)n / (
double)(t1) * 1.0E3 <<
" MFlops");
230 for (
auto const& r : results) {
231 BOOST_CHECK_CLOSE(res.
at(0), r, 1E-3);
236void checkRngOutput(
const std::vector<std::vector<double>>& output) {
237 for (
auto const& o : output) {
238 boost::accumulators::accumulator_set<
239 double, boost::accumulators::stats<boost::accumulators::tag::mean, boost::accumulators::tag::variance>>
241 for (
auto const& v : o) {
244 BOOST_TEST_MESSAGE(
" mean = " << boost::accumulators::mean(acc)
245 <<
", variance = " << boost::accumulators::variance(acc));
246 BOOST_CHECK_SMALL(boost::accumulators::mean(acc), 0.05);
247 BOOST_CHECK_CLOSE(boost::accumulators::variance(acc), 1.0, 2.0);
253 ComputeEnvironmentFixture fixture;
254 const std::size_t n = 65536;
255 for (
auto const& d : ComputeEnvironment::instance().getAvailableDevices()) {
256 BOOST_TEST_MESSAGE(
"testing rng generation on device '" << d <<
"'.");
257 ComputeEnvironment::instance().selectContext(d);
258 auto& c = ComputeEnvironment::instance().context();
261 for (
auto const& d :
vs) {
262 for (
auto const& r : d) {
266 std::vector<std::vector<double>> output(6, std::vector<double>(n));
269 checkRngOutput(output);
271 BOOST_TEST_MESSAGE(
"test to replay same calc");
273 BOOST_CHECK(!newCalc2);
274 BOOST_CHECK_EQUAL(
id, id2);
277 checkRngOutput(output);
282 ComputeEnvironmentFixture fixture;
283 const std::size_t n = 42;
284 std::vector<std::vector<double>> output;
285 for (
auto const& d : ComputeEnvironment::instance().getAvailableDevices()) {
286 BOOST_TEST_MESSAGE(
"testing replay flow error on device '" << d <<
"'.");
287 ComputeEnvironment::instance().selectContext(d);
288 auto& c = ComputeEnvironment::instance().context();
290 BOOST_CHECK(newCalc);
296 BOOST_CHECK(!newCalc2);
297 BOOST_CHECK_EQUAL(
id, id2);
309 ComputeEnvironmentFixture fixture;
310 const std::size_t n = 1500;
311 for (
auto const& d : ComputeEnvironment::instance().getAvailableDevices()) {
312 BOOST_TEST_MESSAGE(
"testing rng generation mt19937 against QL on device '" << d <<
"'.");
313 ComputeEnvironment::instance().selectContext(d);
314 auto& c = ComputeEnvironment::instance().context();
318 BOOST_TEST_MESSAGE(
"using double precision = " << std::boolalpha << settings.
useDoublePrecision);
322 for (
auto const& d :
vs) {
323 for (
auto const& r : d) {
327 for (
auto const& d : vs2) {
328 for (
auto const& r : d) {
332 std::vector<std::vector<double>> output(2, std::vector<double>(n));
335 auto sg = GenericPseudoRandom<MersenneTwisterUniformRng, InverseCumulativeNormal>::make_sequence_generator(
337 MersenneTwisterUniformRng mt(settings.
rngSeed);
341 Size noErrors = 0, errorThreshold = 10;
342 for (Size j = 0; j < 2; ++j) {
343 for (Size i = 0; i < n; ++i) {
344 Real ref = sg.nextSequence().value[0];
345 Real err = std::abs(output[j][i] - ref);
346 if (std::abs(ref) > 1E-10)
347 err /= std::abs(ref);
348 if (err > tol && noErrors < errorThreshold) {
349 BOOST_ERROR(
"gpu value (" << output[j][i] <<
") at j=" << j <<
", i=" << i
350 <<
" does not match cpu value (" << ref <<
"), error " << err <<
", tol "
361 ComputeEnvironmentFixture fixture;
362 const std::size_t n = 100;
363 for (
auto const& d : ComputeEnvironment::instance().getAvailableDevices()) {
364 BOOST_TEST_MESSAGE(
"testing conditional expectation on device '" << d <<
"'.");
365 ComputeEnvironment::instance().selectContext(d);
366 auto& c = ComputeEnvironment::instance().context();
369 BOOST_TEST_MESSAGE(
"using double precision = " << std::boolalpha << settings.
useDoublePrecision);
377 for (
auto const& d :
vs) {
378 for (
auto const& r : d) {
384 std::vector<std::vector<double>> output(3, std::vector<double>(n));
393 Size noErrors = 0, errorThreshold = 10;
395 for (Size i = 0; i < n; ++i) {
396 Real err = std::abs(output[2][i] - z[i]);
397 if (std::abs(z[i]) > 1E-10)
398 err /= std::abs(z[i]);
399 if (err > tol && noErrors < errorThreshold) {
400 BOOST_ERROR(
"gpu value (" << output[2][i] <<
") at i=" << i <<
" does not match reference cpu value ("
401 << z[i] <<
"), error " << err <<
", tol " << tol);
409BOOST_AUTO_TEST_SUITE_END()
411BOOST_AUTO_TEST_SUITE_END()
basic compute env implementation using the cpu
virtual bool supportsDoublePrecision() const
virtual void declareOutputVariable(const std::size_t id)=0
virtual std::vector< std::vector< std::size_t > > createInputVariates(const std::size_t dim, const std::size_t steps)=0
virtual void finalizeCalculation(std::vector< double * > &output)=0
virtual std::size_t createInputVariable(double v)=0
virtual std::size_t applyOperation(const std::size_t randomVariableOpCode, const std::vector< std::size_t > &args)=0
virtual std::pair< std::size_t, bool > initiateCalculation(const std::size_t n, const std::size_t id=0, const std::size_t version=0, const Settings settings={})=0
virtual const DebugInfo & debugInfo() const =0
virtual void freeVariable(const std::size_t id)=0
interface to compute envs
std::vector< std::function< RandomVariable(const std::vector< const RandomVariable * > &)> > multiPathBasisSystem(Size dim, Size order, QuantLib::LsmBasisSystem::PolynomialType type, Size basisSystemSizeBound)
RandomVariable conditionalExpectation(const std::vector< const RandomVariable * > ®ressor, const std::vector< std::function< RandomVariable(const std::vector< const RandomVariable * > &)> > &basisFn, const Array &coefficients)
opencl compute env implementation
unsigned long numberOfOperations
unsigned long nanoSecondsProgramBuild
unsigned long nanoSecondsDataCopy
unsigned long nanoSecondsCalculation
QuantExt::SequenceType rngSequenceType
std::size_t regressionOrder
Real at(const Size i) const
static constexpr std::size_t Add
static constexpr std::size_t Mult
static constexpr std::size_t ConditionalExpectation
BOOST_AUTO_TEST_CASE(testEnvironmentInit)
Fixture that can be used at top level.