From d380c23b2cc0b02e10819e779c73cde2c62603b2 Mon Sep 17 00:00:00 2001 From: Eugene Zhulenev Date: Mon, 14 Oct 2019 14:31:59 -0700 Subject: Block evaluation for TensorGenerator/TensorReverse/TensorShuffling --- unsupported/test/cxx11_tensor_block_eval.cpp | 246 +++++++++++++++++++++------ 1 file changed, 196 insertions(+), 50 deletions(-) (limited to 'unsupported/test/cxx11_tensor_block_eval.cpp') diff --git a/unsupported/test/cxx11_tensor_block_eval.cpp b/unsupported/test/cxx11_tensor_block_eval.cpp index aac75014c..eb93c5c53 100644 --- a/unsupported/test/cxx11_tensor_block_eval.cpp +++ b/unsupported/test/cxx11_tensor_block_eval.cpp @@ -139,23 +139,50 @@ static void VerifyBlockEvaluator(Expression expr, GenBlockParams gen_block) { // Evaluate TensorBlock expression into a tensor. Tensor block(block_params.desc.dimensions()); + // Dimensions for the potential destination buffer. + DSizes dst_dims; + if (internal::random()) { + dst_dims = block_params.desc.dimensions(); + } else { + for (int i = 0; i < NumDims; ++i) { + Index extent = internal::random(0, 5); + dst_dims[i] = block_params.desc.dimension(i) + extent; + } + } + // Maybe use this tensor as a block desc destination. - Tensor dst(block_params.desc.dimensions()); + Tensor dst(dst_dims); + dst.setZero(); if (internal::random()) { block_params.desc.template AddDestinationBuffer( dst.data(), internal::strides(dst.dimensions()), dst.dimensions().TotalSize() * sizeof(T)); } - auto tensor_block = eval.blockV2(block_params.desc, scratch); - auto b_expr = tensor_block.expr(); + const bool root_of_expr = internal::random(); + auto tensor_block = eval.blockV2(block_params.desc, scratch, root_of_expr); + + if (tensor_block.kind() == internal::TensorBlockKind::kMaterializedInOutput) { + // Copy data from destination buffer. + if (dimensions_match(dst.dimensions(), block.dimensions())) { + block = dst; + } else { + DSizes offsets; + for (int i = 0; i < NumDims; ++i) offsets[i] = 0; + block = dst.slice(offsets, block.dimensions()); + } - // We explicitly disable vectorization and tiling, to run a simple coefficient - // wise assignment loop, because it's very simple and should be correct. - using BlockAssign = TensorAssignOp; - using BlockExecutor = TensorExecutor; - BlockExecutor::run(BlockAssign(block, b_expr), d); + } else { + // Assign to block from expression. + auto b_expr = tensor_block.expr(); + + // We explicitly disable vectorization and tiling, to run a simple coefficient + // wise assignment loop, because it's very simple and should be correct. + using BlockAssign = TensorAssignOp; + using BlockExecutor = TensorExecutor; + BlockExecutor::run(BlockAssign(block, b_expr), d); + } // Cleanup temporary buffers owned by a tensor block. tensor_block.cleanup(); @@ -375,17 +402,16 @@ static void test_eval_tensor_generator() { Tensor input(dims); input.setRandom(); - auto generator = [](const array& dims) -> T { + auto generator = [](const array& coords) -> T { T result = static_cast(0); for (int i = 0; i < NumDims; ++i) { - result += static_cast((i + 1) * dims[i]); + result += static_cast((i + 1) * coords[i]); } return result; }; VerifyBlockEvaluator( - input.generate(generator), - [&dims]() { return FixedSizeBlock(dims); }); + input.generate(generator), [&dims]() { return FixedSizeBlock(dims); }); VerifyBlockEvaluator( input.generate(generator), @@ -403,12 +429,63 @@ static void test_eval_tensor_reverse() { for (int i = 0; i < NumDims; ++i) reverse[i] = internal::random(); VerifyBlockEvaluator( - input.reverse(reverse), - [&dims]() { return FixedSizeBlock(dims); }); + input.reverse(reverse), [&dims]() { return FixedSizeBlock(dims); }); + + VerifyBlockEvaluator(input.reverse(reverse), [&dims]() { + return RandomBlock(dims, 1, 10); + }); +} + +template +static void test_eval_tensor_slice() { + DSizes dims = RandomDims(10, 20); + Tensor input(dims); + input.setRandom(); + + // Pick a random slice of an input tensor. + DSizes slice_start = RandomDims(5, 10); + DSizes slice_size = RandomDims(5, 10); + + // Make sure that slice start + size do not overflow tensor dims. + for (int i = 0; i < NumDims; ++i) { + slice_start[i] = numext::mini(dims[i] - 1, slice_start[i]); + slice_size[i] = numext::mini(slice_size[i], dims[i] - slice_start[i]); + } + + VerifyBlockEvaluator( + input.slice(slice_start, slice_size), + [&slice_size]() { return FixedSizeBlock(slice_size); }); VerifyBlockEvaluator( - input.reverse(reverse), - [&dims]() { return RandomBlock(dims, 1, 10); }); + input.slice(slice_start, slice_size), + [&slice_size]() { return RandomBlock(slice_size, 1, 10); }); +} + +template +static void test_eval_tensor_shuffle() { + DSizes dims = RandomDims(5, 15); + Tensor input(dims); + input.setRandom(); + + DSizes shuffle; + for (int i = 0; i < NumDims; ++i) shuffle[i] = i; + + do { + DSizes shuffled_dims; + for (int i = 0; i < NumDims; ++i) shuffled_dims[i] = dims[shuffle[i]]; + + VerifyBlockEvaluator( + input.shuffle(shuffle), + [&shuffled_dims]() { return FixedSizeBlock(shuffled_dims); }); + + VerifyBlockEvaluator( + input.shuffle(shuffle), [&shuffled_dims]() { + return RandomBlock(shuffled_dims, 1, 5); + }); + + break; + + } while (std::next_permutation(&shuffle[0], &shuffle[0] + NumDims)); } template @@ -564,7 +641,7 @@ static void test_assign_to_tensor_chipping() { Index chip_dim = internal::random(0, NumDims - 1); Index chip_offset = internal::random(0, dims[chip_dim] - 2); - DSizes < Index, NumDims - 1 > chipped_dims; + DSizes chipped_dims; for (Index i = 0; i < chip_dim; ++i) { chipped_dims[i] = dims[i]; } @@ -587,42 +664,111 @@ static void test_assign_to_tensor_chipping() { [&chipped_dims]() { return FixedSizeBlock(chipped_dims); }); } -// -------------------------------------------------------------------------- // +template +static void test_assign_to_tensor_slice() { + DSizes dims = RandomDims(10, 20); + Tensor tensor(dims); + + // Pick a random slice of tensor. + DSizes slice_start = RandomDims(5, 10); + DSizes slice_size = RandomDims(5, 10); + + // Make sure that slice start + size do not overflow tensor dims. + for (int i = 0; i < NumDims; ++i) { + slice_start[i] = numext::mini(dims[i] - 1, slice_start[i]); + slice_size[i] = numext::mini(slice_size[i], dims[i] - slice_start[i]); + } + + TensorMap> map(tensor.data(), dims); + + VerifyBlockAssignment( + tensor, map.slice(slice_start, slice_size), + [&slice_size]() { return RandomBlock(slice_size, 1, 10); }); + + VerifyBlockAssignment( + tensor, map.slice(slice_start, slice_size), + [&slice_size]() { return SkewedInnerBlock(slice_size); }); -#define CALL_SUBTESTS_DIMS_LAYOUTS(NAME) \ - CALL_SUBTEST((NAME())); \ - CALL_SUBTEST((NAME())); \ - CALL_SUBTEST((NAME())); \ - CALL_SUBTEST((NAME())); \ - CALL_SUBTEST((NAME())); \ - CALL_SUBTEST((NAME())); \ - CALL_SUBTEST((NAME())); \ - CALL_SUBTEST((NAME())) + VerifyBlockAssignment( + tensor, map.slice(slice_start, slice_size), + [&slice_size]() { return FixedSizeBlock(slice_size); }); +} + +template +static void test_assign_to_tensor_shuffle() { + DSizes dims = RandomDims(5, 15); + Tensor tensor(dims); + + DSizes shuffle; + for (int i = 0; i < NumDims; ++i) shuffle[i] = i; + + TensorMap> map(tensor.data(), dims); -#define CALL_SUBTESTS_LAYOUTS(NAME) \ - CALL_SUBTEST((NAME())); \ - CALL_SUBTEST((NAME())) + do { + DSizes shuffled_dims; + for (int i = 0; i < NumDims; ++i) shuffled_dims[i] = dims[shuffle[i]]; + + VerifyBlockAssignment( + tensor, map.shuffle(shuffle), + [&shuffled_dims]() { return FixedSizeBlock(shuffled_dims); }); + + VerifyBlockAssignment( + tensor, map.shuffle(shuffle), [&shuffled_dims]() { + return RandomBlock(shuffled_dims, 1, 5); + }); + + } while (std::next_permutation(&shuffle[0], &shuffle[0] + NumDims)); +} + +// -------------------------------------------------------------------------- // + +#define CALL_SUBTEST_PART(PART) \ + CALL_SUBTEST_##PART + +#define CALL_SUBTESTS_DIMS_LAYOUTS(PART, NAME) \ + CALL_SUBTEST_PART(PART)((NAME())); \ + CALL_SUBTEST_PART(PART)((NAME())); \ + CALL_SUBTEST_PART(PART)((NAME())); \ + CALL_SUBTEST_PART(PART)((NAME())); \ + CALL_SUBTEST_PART(PART)((NAME())); \ + CALL_SUBTEST_PART(PART)((NAME())); \ + CALL_SUBTEST_PART(PART)((NAME())); \ + CALL_SUBTEST_PART(PART)((NAME())); \ + CALL_SUBTEST_PART(PART)((NAME())); \ + CALL_SUBTEST_PART(PART)((NAME())) + +#define CALL_SUBTESTS_LAYOUTS(PART, NAME) \ + CALL_SUBTEST_PART(PART)((NAME())); \ + CALL_SUBTEST_PART(PART)((NAME())) EIGEN_DECLARE_TEST(cxx11_tensor_block_eval) { // clang-format off - CALL_SUBTESTS_DIMS_LAYOUTS(test_eval_tensor_block); - CALL_SUBTESTS_DIMS_LAYOUTS(test_eval_tensor_unary_expr_block); - CALL_SUBTESTS_DIMS_LAYOUTS(test_eval_tensor_binary_expr_block); - CALL_SUBTESTS_DIMS_LAYOUTS(test_eval_tensor_binary_with_unary_expr_block); - CALL_SUBTESTS_DIMS_LAYOUTS(test_eval_tensor_broadcast); - CALL_SUBTESTS_DIMS_LAYOUTS(test_eval_tensor_reshape); - CALL_SUBTESTS_DIMS_LAYOUTS(test_eval_tensor_cast); - CALL_SUBTESTS_DIMS_LAYOUTS(test_eval_tensor_select); - CALL_SUBTESTS_DIMS_LAYOUTS(test_eval_tensor_padding); - CALL_SUBTESTS_DIMS_LAYOUTS(test_eval_tensor_chipping); - CALL_SUBTESTS_DIMS_LAYOUTS(test_eval_tensor_generator); - CALL_SUBTESTS_DIMS_LAYOUTS(test_eval_tensor_reverse); - - CALL_SUBTESTS_LAYOUTS(test_eval_tensor_reshape_with_bcast); - CALL_SUBTESTS_LAYOUTS(test_eval_tensor_forced_eval); - - CALL_SUBTESTS_DIMS_LAYOUTS(test_assign_to_tensor); - CALL_SUBTESTS_DIMS_LAYOUTS(test_assign_to_tensor_reshape); - CALL_SUBTESTS_DIMS_LAYOUTS(test_assign_to_tensor_chipping); + CALL_SUBTESTS_DIMS_LAYOUTS(1, test_eval_tensor_block); + CALL_SUBTESTS_DIMS_LAYOUTS(1, test_eval_tensor_unary_expr_block); + CALL_SUBTESTS_DIMS_LAYOUTS(1, test_eval_tensor_binary_expr_block); + CALL_SUBTESTS_DIMS_LAYOUTS(2, test_eval_tensor_binary_with_unary_expr_block); + CALL_SUBTESTS_DIMS_LAYOUTS(2, test_eval_tensor_broadcast); + CALL_SUBTESTS_DIMS_LAYOUTS(2, test_eval_tensor_reshape); + CALL_SUBTESTS_DIMS_LAYOUTS(3, test_eval_tensor_cast); + CALL_SUBTESTS_DIMS_LAYOUTS(3, test_eval_tensor_select); + CALL_SUBTESTS_DIMS_LAYOUTS(3, test_eval_tensor_padding); + CALL_SUBTESTS_DIMS_LAYOUTS(4, test_eval_tensor_chipping); + CALL_SUBTESTS_DIMS_LAYOUTS(4, test_eval_tensor_generator); + CALL_SUBTESTS_DIMS_LAYOUTS(4, test_eval_tensor_reverse); + CALL_SUBTESTS_DIMS_LAYOUTS(5, test_eval_tensor_slice); + CALL_SUBTESTS_DIMS_LAYOUTS(5, test_eval_tensor_shuffle); + + CALL_SUBTESTS_LAYOUTS(6, test_eval_tensor_reshape_with_bcast); + CALL_SUBTESTS_LAYOUTS(6, test_eval_tensor_forced_eval); + + CALL_SUBTESTS_DIMS_LAYOUTS(7, test_assign_to_tensor); + CALL_SUBTESTS_DIMS_LAYOUTS(7, test_assign_to_tensor_reshape); + CALL_SUBTESTS_DIMS_LAYOUTS(7, test_assign_to_tensor_chipping); + CALL_SUBTESTS_DIMS_LAYOUTS(8, test_assign_to_tensor_slice); + CALL_SUBTESTS_DIMS_LAYOUTS(8, test_assign_to_tensor_shuffle); + + // Force CMake to split this test. + // EIGEN_SUFFIXES;1;2;3;4;5;6;7;8 + // clang-format on } -- cgit v1.2.3