Skip to content
This repository has been archived by the owner on Mar 21, 2024. It is now read-only.

Commit

Permalink
WIP Adding async scan algorithms, iterate on async testing.
Browse files Browse the repository at this point in the history
  • Loading branch information
alliepiper committed Oct 2, 2020
1 parent 2f6ac6f commit c236ed8
Show file tree
Hide file tree
Showing 32 changed files with 3,711 additions and 10 deletions.
1 change: 1 addition & 0 deletions testing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ foreach(thrust_target IN LISTS THRUST_TARGETS)
endforeach()

# Add specialized tests:
add_subdirectory(async)
add_subdirectory(cpp)
add_subdirectory(cuda)
add_subdirectory(omp)
Expand Down
80 changes: 80 additions & 0 deletions testing/async/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# The async tests perform a large amount of codegen, making them expensive to
# build and test. To keep compilation and runtimes manageable, the tests are
# broken up into many files per algorithm to enable parallelism during
# compilation and testing. The structure of these test directories are:
#
# thrust/testing/async/<algorithm_name>/<unit_test>.cu
#
# These generate executables and CTest tests named
# ${config_prefix}.test.async.<algorithm_name>.<unit_test>.

# The async tests only support CUDA enabled configs. Create a list of valid
# thrust targets:
set(cuda_configs)
foreach(thrust_target IN LISTS THRUST_TARGETS)
thrust_get_target_property(config_device ${thrust_target} DEVICE)
if (config_device STREQUAL CUDA)
list(APPEND cuda_configs ${thrust_target})
endif()
endforeach()

list(LENGTH cuda_configs num_cuda_configs)
if (num_cuda_configs EQUAL 0)
return() # No valid configs found, nothing to do.
endif()

# Process a single algorithm directory, adding all .cu/cpp files as tests for
# each valid backend. algo_name is the name of the subdir (<algorithm_name>
# above) and is used for naming the executable/targets.
function(thrust_add_async_test_dir algo_name)
file(GLOB test_srcs
RELATIVE "${CMAKE_CURRENT_LIST_DIR}"
CONFIGURE_DEPENDS
"${algo_name}/*.cu"
"${algo_name}/*.cpp"
)

# Per-algorithm, all-config metatarget: thrust.all.test.async.[algo].all
set(algo_meta_target thrust.all.test.async.${algo_name}.all)
add_custom_target(${algo_meta_target})

foreach(thrust_target IN LISTS cuda_configs)
thrust_get_target_property(config_prefix ${thrust_target} PREFIX)

# Per-algorithm, per-config metatarget: thrust.[config].test.async.[algo].all
set(algo_config_meta_target ${config_prefix}.test.async.${algo_name}.all)
add_custom_target(${algo_config_meta_target})
add_dependencies(${algo_meta_target} ${algo_config_meta_target})

foreach(test_src IN LISTS test_srcs)
get_filename_component(test_name "${test_src}" NAME_WLE)
string(PREPEND test_name async.${algo_name}.)

thrust_add_test(test_target ${test_name} "${test_src}" ${thrust_target})
if(THRUST_ENABLE_TESTS_WITH_RDC)
thrust_enable_rdc_for_cuda_target(${test_target})
endif()

add_dependencies(${algo_config_meta_target} ${test_target})
endforeach()
endforeach()
endfunction()

# Grab all algorithm subdirectories:
set(test_dirs)
file(GLOB contents
CONFIGURE_DEPENDS
"${CMAKE_CURRENT_LIST_DIR}/*"
)

foreach(test_dir IN LISTS contents)
if(IS_DIRECTORY "${test_dir}")
list(APPEND test_dirs "${test_dir}")
endif()
endforeach()

# Process all test dirs:
foreach(test_dir IN LISTS test_dirs)
get_filename_component(algo_name "${test_dir}" NAME_WLE)
thrust_add_async_test_dir(${algo_name})
endforeach()
72 changes: 72 additions & 0 deletions testing/async/exclusive_scan/basic.cu
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include <thrust/detail/config.h>

#if THRUST_CPP_DIALECT >= 2014

#include <async/test_policy_overloads.h>

#include <async/exclusive_scan/mixin.h>

template <typename input_value_type,
typename output_value_type = input_value_type,
typename initial_value_type = input_value_type,
typename alternate_binary_op = thrust::maximum<>>
struct basic_invoker
: testing::async::mixin::input::device_vector<input_value_type>
, testing::async::mixin::output::device_vector<output_value_type>
, testing::async::exclusive_scan::mixin::postfix_args::
all_overloads<initial_value_type, alternate_binary_op>
, testing::async::exclusive_scan::mixin::invoke_reference::
host_synchronous<input_value_type, output_value_type>
, testing::async::exclusive_scan::mixin::invoke_async::basic
, testing::async::mixin::compare_outputs::assert_maybe_fuzzy_equal_quiet
{
static std::string description()
{
return "basic invocation with device vectors";
}
};

template <typename T>
struct TestBasic
{
void operator()(std::size_t num_values) const
{
testing::async::test_policy_overloads<basic_invoker<T>>::run(num_values);
}
};
DECLARE_GENERIC_SIZED_UNITTEST_WITH_TYPES(TestBasic, NumericTypes);

// Testing the in-place algorithm uses the exact same instantiations of the
// underlying scan implementation as above. Test them here to avoid compiling
// them twice.
template <typename input_value_type,
typename initial_value_type = input_value_type,
typename alternate_binary_op = thrust::maximum<>>
struct basic_inplace_invoker
: testing::async::mixin::input::device_vector<input_value_type>
, testing::async::mixin::output::device_vector_reuse_input<input_value_type>
, testing::async::exclusive_scan::mixin::postfix_args::
all_overloads<initial_value_type, alternate_binary_op>
, testing::async::exclusive_scan::mixin::invoke_reference::host_synchronous<
input_value_type>
, testing::async::exclusive_scan::mixin::invoke_async::basic
, testing::async::mixin::compare_outputs::assert_maybe_fuzzy_equal_quiet
{
static std::string description()
{
return "basic in-place invocation with device vectors";
}
};

template <typename T>
struct TestBasicInPlace
{
void operator()(std::size_t num_values) const
{
using invoker = basic_inplace_invoker<T>;
testing::async::test_policy_overloads<invoker>::run(num_values);
}
};
DECLARE_GENERIC_SIZED_UNITTEST_WITH_TYPES(TestBasicInPlace, NumericTypes);

#endif // C++14
46 changes: 46 additions & 0 deletions testing/async/exclusive_scan/counting_iterator.cu
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include <thrust/detail/config.h>

#if THRUST_CPP_DIALECT >= 2014

#include <async/test_policy_overloads.h>

#include <async/exclusive_scan/mixin.h>

#include <algorithm>
#include <limits>

template <typename input_value_type,
typename output_value_type = input_value_type,
typename initial_value_type = input_value_type,
typename alternate_binary_op = thrust::maximum<>>
struct invoker
: testing::async::mixin::input::counting_iterator_0<input_value_type>
, testing::async::mixin::output::device_vector<output_value_type>
, testing::async::exclusive_scan::mixin::postfix_args::
all_overloads<initial_value_type, alternate_binary_op>
, testing::async::exclusive_scan::mixin::invoke_reference::
host_synchronous<input_value_type, output_value_type>
, testing::async::exclusive_scan::mixin::invoke_async::basic
, testing::async::mixin::compare_outputs::assert_maybe_fuzzy_equal_quiet
{
static std::string description()
{
return "fancy input iterator (counting_iterator)";
}
};

template <typename T>
struct TestCountingIterator
{
void operator()(std::size_t num_values) const
{
num_values = unittest::truncate_to_max_representable<T>(num_values);
testing::async::test_policy_overloads<invoker<T>>::run(num_values);
}
};
// Use built-in types only, counting_iterator doesn't seem to be compatible with
// the custom_numeric.
DECLARE_GENERIC_SIZED_UNITTEST_WITH_TYPES(TestCountingIterator,
BuiltinNumericTypes);

#endif // C++14
38 changes: 38 additions & 0 deletions testing/async/exclusive_scan/discard_output.cu
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include <thrust/detail/config.h>

#if THRUST_CPP_DIALECT >= 2014

#include <async/test_policy_overloads.h>

#include <async/exclusive_scan/mixin.h>

// Compilation test with discard iterators. No runtime validation is actually
// performed, other than testing whether the algorithm completes without
// exception.

template <typename input_value_type,
typename initial_value_type = input_value_type,
typename alternate_binary_op = thrust::maximum<>>
struct discard_invoker
: testing::async::mixin::input::device_vector<input_value_type>
, testing::async::mixin::output::discard_iterator
, testing::async::exclusive_scan::mixin::postfix_args::
all_overloads<initial_value_type, alternate_binary_op>
, testing::async::mixin::invoke_reference::noop
, testing::async::exclusive_scan::mixin::invoke_async::basic
, testing::async::mixin::compare_outputs::noop
{
static std::string description() { return "discard output"; }
};

template <typename T>
struct TestDiscard
{
void operator()(std::size_t num_values) const
{
testing::async::test_policy_overloads<discard_invoker<T>>::run(num_values);
}
};
DECLARE_GENERIC_SIZED_UNITTEST_WITH_TYPES(TestDiscard, NumericTypes);

#endif // C++14
Loading

0 comments on commit c236ed8

Please sign in to comment.