cutlass/tools/test/unit/core/layout_verification.cu
Artem Belevich e18292db46 Make CUTLASS compileable with Clang.
Requires a recent clang build (r359248 or newer).

Enable compilation with clang with these options:
cmake -DCUDA_COMPILER=clang -DCMAKE_CXX_COMPILER=/path/to/clang++
2019-05-02 11:00:22 -07:00

200 lines
6.5 KiB
Plaintext

/***************************************************************************************************
* Copyright (c) 2017-2019, 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;
}
}
// test::Layout::Coordinate is actually a std::vector<>, so for ADL lookup to
// work, the operator<< must be in std::. GCC does look it up in global
// namespace, but that's a bug.
namespace std {
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;
}
} // namespace std
///////////////////////////////////////////////////////////////////////////////////////////////////
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;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////