CUTLASS v1.0 release

This commit is contained in:
akerr
2018-05-16 11:44:56 -07:00
parent 901287175f
commit 2028ebe120
1830 changed files with 308993 additions and 11173 deletions
+194
View File
@@ -0,0 +1,194 @@
/***************************************************************************************************
* Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
* * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************************************/
#include <cutlass_unit_test.h>
#include <algorithm>
#include <tools/test/unit/core/layout_verification.h>
namespace test {
Layout::Layout() {
}
Layout::Layout(Layout::SpanVector const &_layout) {
reset(_layout);
}
struct SpanCompareDim {
bool operator()(Layout::Span const &a, Layout::Span const &b) const {
return a.dim < b.dim;
}
};
/// Updates the layout
void Layout::reset(Layout::SpanVector const &_layout) {
layout_ = _layout;
extent_.clear();
extent_.resize(layout_.size(), 1);
int _rank = std::max_element(layout_.begin(), layout_.end(), SpanCompareDim())->dim + 1;
dim_extent_.clear();
dim_extent_.resize(_rank, extent_);
// initialize extent vector
for (size_t i = layout_.size(); i > 0; --i) {
extent_.at(i - 1) = layout_.at(i - 1).size * (i < layout_.size() ? extent_.at(i) : 1);
}
// initialize the dim_extent vector
for (size_t rank_idx = 0; rank_idx < dim_extent_.size(); ++rank_idx) {
ExtentVector &_extent = dim_extent_.at(rank_idx);
for (size_t i = layout_.size(); i > 0; --i) {
int _size = (rank_idx == layout_.at(i - 1).dim ? layout_.at(i - 1).size : 1);
_extent.at(i - 1) = _size * (i < layout_.size() ? _extent.at(i) : 1);
}
}
}
/// Computes the rank of the layout
int Layout::rank() const {
return int(dim_extent_.size());
}
/// Prints a layout
std::ostream & Layout::write(std::ostream &out) const {
std::cout << "Layout: [";
for (size_t i = 0; i < layout_.size(); ++i) {
std::cout << "(" << layout_.at(i).dim << ": " << layout_.at(i).size << ") ";
}
std::cout << "] - rank: " << rank() << "\n";
std::cout << "Extent: [";
for (size_t i = 0; i < layout_.size(); ++i) {
std::cout << (i ? ", " : "") << extent_.at(i);
}
std::cout << "]\n";
for (size_t r = 0; r < dim_extent_.size(); ++r) {
std::cout << " Dim " << r << ": [";
for (int i = 0; i < dim_extent_.at(r).size(); ++i) {
std::cout << (i ? ", " : "") << dim_extent_.at(r).at(i);
}
std::cout << "]\n";
}
return out;
}
/// Maps an index to a given coordinate
Layout::Coordinate Layout::operator()(int index) const {
Coordinate coord(rank(), 0);
for (size_t i = 0; i < layout_.size() - 1; ++i) {
int quotient = (index / extent_.at(i + 1));
index = (index % extent_.at(i + 1));
coord.at(layout_.at(i).dim) += quotient * dim_extent_.at(layout_.at(i).dim).at(i + 1);
}
coord.at(layout_.back().dim) += index;
return coord;
}
/// Maps a coordinate to an index
int Layout::operator()(Layout::Coordinate const &_coord) const {
Coordinate coord(_coord);
int index = 0;
for (size_t i = layout_.size(); i > 0; --i) {
size_t idx = i - 1;
int dim = layout_.at(idx).dim;
int size = layout_.at(idx).size;
int items = coord.at(dim);
int quotient = items / size;
int remainder = items % size;
index += remainder * (i < layout_.size() ? extent_.at(idx + 1) : 1);
coord.at(dim) = quotient;
}
return index;
}
}
std::ostream & operator<<(std::ostream &out, test::Layout::Coordinate const &coord) {
for (int i = 0; i < coord.size(); ++i) {
out << (i ? ", " : "") << coord.at(i);
}
return out;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
TEST(Layout, igemm) {
test::Layout::SpanVector layout_def;
typedef test::Layout::Span Span;
layout_def.push_back(Span(0, 8));
layout_def.push_back(Span(1, 4));
layout_def.push_back(Span(0, 4));
test::Layout layout(layout_def);
for (int i = 0; i < 33; ++i) {
test::Layout::Coordinate coord = layout(i);
int index = layout(coord);
EXPECT_EQ(i, index)
<< "[" << i << "] - (" << layout(i) << ") => " << layout(layout(i)) << std::endl;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
TEST(Layout, sgemm_accum) {
test::Layout::SpanVector layout_def;
typedef test::Layout::Span Span;
layout_def.push_back(Span(0, 2));
layout_def.push_back(Span(1, 8));
layout_def.push_back(Span(0, 2));
test::Layout layout(layout_def);
for (int i = 0; i < 32; ++i) {
test::Layout::Coordinate coord = layout(i);
int index = layout(coord);
EXPECT_EQ(i, index)
<< "[" << i << "] - (" << layout(i) << ") => " << layout(layout(i)) << std::endl;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
+314
View File
@@ -0,0 +1,314 @@
/***************************************************************************************************
* Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
* * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************************************/
#pragma once
#include <functional>
#include <iosfwd>
#include <iostream>
#include <vector>
#include <cutlass/tensor_view.h>
#include <tools/util/half.h>
#include <tools/util/host_tensor_view.h>
#include <tools/util/tensor_view_io.h>
#include <tools/util/type_traits.h>
namespace test {
/// Defines an arrangement
class Layout {
public:
/// Analogous to cutlass::Span
struct Span {
int dim;
int size;
Span(int _dim = 0, int _size = 0) : dim(_dim), size(_size) {}
};
/// Vector of span definitions
typedef std::vector<Span> SpanVector;
/// Coordinate in an arbitrary-dimensional space
typedef std::vector<int> Coordinate;
/// Defines a vector describing the extent of some dimension
typedef std::vector<int> ExtentVector;
private:
/// Defines a mapping from a 1D sequence to an n-dimensional space
SpanVector layout_;
/// Computes the extent of each node in the layout description
ExtentVector extent_;
/// For each dimension, computes extent
std::vector<ExtentVector> dim_extent_;
public:
//
// Methods
//
Layout();
Layout(SpanVector const& _layout);
/// Updates the layout
void reset(SpanVector const& _layout = SpanVector());
/// Computes the rank of the layout
int rank() const;
/// Prints Layout data structure
std::ostream& write(std::ostream& out) const;
/// Maps an index to a given coordinate
Coordinate operator()(int index) const;
/// Maps a coordinate to an index
int operator()(Coordinate const& coord) const;
};
}
/// Implemented in layout_verification.cu
std::ostream& operator<<(std::ostream& out, test::Layout::Coordinate const& coord);
namespace test {
/// Packs the elements of a coordinate into the bits available
template <typename T, int Rank = 2>
struct CoordinatePack {
typedef T value_type;
typedef typename cutlass::TypeTraits<T>::unsigned_type Bits;
static int const ElementBits = sizeof(Bits) * 8 / Rank;
static Bits const Mask = (Bits(1) << ElementBits) - 1;
Bits operator()(Layout::Coordinate const& coord) const {
Bits result = 0;
for (size_t i = 0; i < coord.size(); ++i) {
result |= (((coord.at(i) & Mask) << (i * ElementBits)));
}
return result;
}
};
/// Unpacks a coordinate from the bits available
template <typename T, int Rank = 2>
struct CoordinateUnpack {
typedef T value_type;
typedef typename cutlass::TypeTraits<T>::unsigned_type Bits;
static int const ElementBits = sizeof(Bits) * 8 / Rank;
static Bits const Mask = (Bits(1) << ElementBits) - 1;
Layout::Coordinate operator()(Bits index) const {
Layout::Coordinate coord(Rank, 0);
for (size_t i = 0; i < Rank; ++i) {
coord.at(i) = (index & Mask);
index = (index >> ElementBits);
}
return coord;
}
};
/// Hashing function
struct HashUint64 {
// PJW Elf Hash - https://en.wikipedia.org/wiki/PJW_hash_function
uint64_t operator()(uint64_t value) const {
uint64_t h = 0;
uint64_t high;
uint8_t const* s = reinterpret_cast<uint8_t const*>(&value);
for (int byte = 0; byte < sizeof(value); ++byte) {
h = (h << 4) + *s++;
if (high = (h & 0xF0000000)) {
h ^= high >> 24;
}
h &= ~high;
}
return h;
}
};
/// Packs the coordinate into 64 bits then hashes the result and stores the least significant bits
template <typename T, typename Hasher = HashUint64>
struct CoordinateHash {
typedef T value_type;
typedef typename cutlass::TypeTraits<T>::unsigned_type Bits;
typedef CoordinatePack<uint64_t, 4> Pack;
/// Bit mask to cast from uint64_t to whatever Bits is
static uint64_t const mask = ((uint64_t(1) << (sizeof(Bits) * 8)) - 1);
static_assert(sizeof(Bits) <= sizeof(uint64_t), "T must be smaller than or equal to uint64_t");
//
// Data members
//
/// Packs coordinate into uint64_t
Pack pack;
/// Hashes the resulting coordinate
Hasher hasher;
/// One additional xor to salt things
uint64_t salt;
//
//
//
CoordinateHash(uint64_t _salt = 0x0ac7d0190) : salt(_salt) {}
/// Returns a hashed coordinate
Bits operator()(Layout::Coordinate const& coord) const {
uint64_t result = hasher(pack(coord) ^ salt);
return Bits(result & mask);
}
};
/// Environment to initialize and verify a template
template <typename DestType_,
typename DestCoordinateHash_,
typename SourceType_,
typename SourceCoordinateHash_>
class VerifyLayout {
public:
typedef DestType_ DestType;
typedef typename cutlass::TypeTraits<DestType>::unsigned_type DestBits;
typedef DestCoordinateHash_ DestCoordinateHash;
typedef SourceType_ SourceType;
typedef typename cutlass::TypeTraits<SourceType>::unsigned_type SourceBits;
typedef SourceCoordinateHash_ SourceCoordinateHash;
public:
/// Basic visitor to terminate verification on error
struct VisitorNop {
/// Returns true to keep checking in spite of errors, false if to stop
bool operator()(DestBits got, // hashed/packed coordinate encountered
DestBits expected, // hashed/packed coordinate expected
Layout::Coordinate coord, // computed coordinate
int index) { // location
// false to terminate checking
return false;
}
};
/// Basic visitor to terminate verification on error
struct VisitorVerbose {
CoordinateUnpack<DestBits> unpack;
std::ostream* out;
VisitorVerbose() : out(&std::cout) {}
VisitorVerbose(std::ostream& _out) : out(&_out) {}
/// Returns true to keep checking in spite of errors, false if to stop
bool operator()(DestBits got, // hashed/packed coordinate encountered
DestBits expected, // hashed/packed coordinate expected
Layout::Coordinate coord, // computed coordinate
int index) { // location
int const width = sizeof(DestBits) * 2;
(*out) << "[" << index << "] - (" << coord << ") - expected: 0x" << std::hex
<< std::setw(width) << std::setfill('0') << expected << ", got: 0x" << std::setw(width)
<< std::setfill('0') << got << std::dec << " - unpacked: (" << unpack(got) << ")"
<< std::endl;
// true to print out complete error report
return true;
}
};
public:
VerifyLayout() {}
/// Initializes memory according to a layout and hash function
void initialize(cutlass::HostTensorView<SourceType> const& source, Layout const& layout) {
SourceCoordinateHash hash;
int const count = source.size().count();
SourceBits* data = reinterpret_cast<SourceBits*>(source.ref().data());
for (int index = 0; index < count; ++index) {
SourceBits element = hash(layout(index));
data[index] = element;
}
}
/// Verifies the resulting layout
template <typename Visitor>
bool verify(cutlass::HostTensorView<DestType> const& dest,
Layout const& layout,
Visitor visitor) {
DestCoordinateHash hash;
int const count = dest.size().count();
DestBits* data = reinterpret_cast<DestBits*>(dest.ref().data());
int errors = 0;
for (int index = 0; index < count; ++index) {
Layout::Coordinate coord = layout(index);
DestBits element = hash(coord);
if (element != data[index]) {
++errors;
if (!visitor(data[index], element, coord, index)) {
break;
}
}
}
return !errors;
}
/// Verifies the resulting layout
bool verify(cutlass::HostTensorView<DestType> const& dest, Layout const& layout) {
return verify(layout, VisitorNop());
}
};
} // namespace test
+120
View File
@@ -0,0 +1,120 @@
/***************************************************************************************************
* Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
* * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************************************/
#include <cublas_v2.h>
#include <cstring>
#include <cutlass_unit_test.h>
#include <cutlass/predicate_vector.h>
#include <tools/util/host_tensor.h>
namespace test {
template <typename PredicateVector>
__global__ void load_predicates(unsigned *output, unsigned const *input) {
PredicateVector predicates;
int const word_count = (PredicateVector::kPredicates + 31) / 32;
int i = 0;
for (int word_idx = 0; word_idx < word_count; ++word_idx) {
unsigned word = input[word_idx];
CUTLASS_PRAGMA_UNROLL
for (int bit = 0; bit < sizeof(unsigned) * 8; ++bit) {
bool pred = ((word >> bit) & 1);
predicates.set(i, pred);
if (predicates.at(i) != pred) {
printf("ERROR - cannot read back predicate\n");
}
++i;
}
}
__syncthreads();
i = 0;
for (int word_idx = 0; word_idx < word_count; ++word_idx) {
unsigned result = 0;
for (int bit = 0; bit < sizeof(unsigned) * 8; ++bit) {
bool pred = predicates.at(i ++);
result |= (unsigned(pred) << bit);
}
output[word_idx] = result;
}
}
}
TEST(PredicateVector, Basic) {
static int const Bits = 32;
static int const Words = (Bits + 31) / 32;
typedef cutlass::PredicateVector<Bits> PredicateVector;
cutlass::HostTensor<unsigned> output;
cutlass::HostTensor<unsigned> input;
output.resize(Words);
input.resize(Words);
// some arbitrary test bits
unsigned values[] = {
0xdeadbeef,
0xa0070032,
0x9076d001,
0x00000000,
0xabdfc0ad
};
for (int test = 0; test < 5; ++test) {
input[0] = values[test];
output[0] = 0;
input.sync_device();
output.sync_device();
test::load_predicates<PredicateVector><<<
dim3(1,1,1), dim3(1,1,1)
>>>(
output.device_data(),
input.device_data()
);
output.sync_host();
for (int word = 0; word < Words; ++word) {
EXPECT_EQ(input[word], output[word])
<< "Expected: 0x" << std::hex << input.host_data()[word]
<< ", got: 0x" << output.host_data()[word]
<< std::dec;
}
}
}
+153
View File
@@ -0,0 +1,153 @@
/***************************************************************************************************
* Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
* * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************************************/
#include <cutlass_unit_test.h>
#include <tools/util/host_tensor.h>
#include <tools/util/tensor_view_io.h>
#include <cutlass/shape.h>
#include <cutlass/predicate_vector.h>
#include <cutlass/tile_iterator.h>
#include <cutlass/tile_traits_standard.h>
#include <cutlass/iterator_access.h>
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace test {
template <typename Traits, typename Scalar>
__global__ void load_store_global(
typename cutlass::TileLoadIterator<Traits, Scalar, cutlass::IteratorAdvance::kH,
cutlass::MemorySpace::kGlobal>::Scalar const *input,
typename cutlass::TileStoreIterator<Traits, Scalar, cutlass::IteratorAdvance::kH,
cutlass::MemorySpace::kGlobal>::Scalar *output
) {
typedef cutlass::TileLoadIterator<Traits, Scalar, cutlass::IteratorAdvance::kH, cutlass::MemorySpace::kGlobal> LoadIterator;
typedef cutlass::TileStoreIterator<Traits, Scalar, cutlass::IteratorAdvance::kH, cutlass::MemorySpace::kGlobal> StoreIterator;
typename LoadIterator::Params load_params;
typename StoreIterator::Params store_params;
typedef typename Traits::Tile Tile;
load_params.initialize(input, Tile::kH*Tile::kW, Tile::kW, 1);
store_params.initialize(output, Tile::kH*Tile::kW, Tile::kW, 1);
LoadIterator load_iterator(load_params);
StoreIterator store_iterator(store_params);
typename LoadIterator::Fragment fragment;
load_iterator.load(fragment);
store_iterator.store(fragment);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
TEST(TileIterator, tile_128x8_contiguous) {
static int const M = 128;
static int const N = 1;
static int const K = 8;
static int const kThreads = M;
typedef cutlass::Shape<K, N, M> ThreadBlockTile;
typedef cutlass::TileTraitsStandard<cutlass::Shape<N, K, M>, kThreads> Traits;
cutlass::HostTensor<float> input;
cutlass::HostTensor<float> output;
input.resize_matrix(ThreadBlockTile::kW, ThreadBlockTile::kD,
cutlass::MatrixLayout::kColumnMajor);
output.resize_matrix(ThreadBlockTile::kW, ThreadBlockTile::kD,
cutlass::MatrixLayout::kColumnMajor);
input.fill_linear(cutlass::make_Coord(1, 1, ThreadBlockTile::kW, 1));
output.fill(0);
test::load_store_global< Traits, float ><<<
dim3(1,1,1),
dim3(kThreads, 1)
>>>(
input.device_data(),
output.device_data()
);
cudaError_t result = cudaDeviceSynchronize();
ASSERT_EQ(result, cudaSuccess) << "\nCUDA kernel launch error: " << cudaGetErrorString(result)
<< "\n";
output.sync_host();
EXPECT_TRUE(input.bit_equals(output));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
TEST(TileIterator, tile_128x8_rake) {
static int const M = 128;
static int const N = 1;
static int const K = 8;
static int const kThreads = 32;
typedef cutlass::Shape<K, N, M> ThreadBlockTile;
typedef cutlass::TileTraitsStandard<cutlass::Shape<N, K, M>, kThreads> Traits;
cutlass::HostTensor<float> input;
cutlass::HostTensor<float> output;
input.resize_matrix(ThreadBlockTile::kW, ThreadBlockTile::kD,
cutlass::MatrixLayout::kColumnMajor);
output.resize_matrix(ThreadBlockTile::kW, ThreadBlockTile::kD,
cutlass::MatrixLayout::kColumnMajor);
input.fill_linear(cutlass::make_Coord(1, 1, ThreadBlockTile::kW, 1));
output.fill(0);
test::load_store_global< Traits, float ><<<
dim3(1,1,1),
dim3(kThreads, 1)
>>>(
input.device_data(),
output.device_data()
);
cudaError_t result = cudaDeviceSynchronize();
ASSERT_EQ(result, cudaSuccess) << "\nCUDA kernel launch error: " << cudaGetErrorString(result)
<< "\n";
output.sync_host();
EXPECT_TRUE(input.bit_equals(output));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}