CUTLASS v1.0 release
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user