CUTLASS 2.2 (#96)
Adds support for NVIDIA Ampere Architecture features. CUDA 11 Toolkit recommended.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
# Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
# Copyright (c) 2017-2020, 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:
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
find_package(Python3 3.6 COMPONENTS Interpreter REQUIRED)
|
||||
find_package(Python3 3.5 COMPONENTS Interpreter REQUIRED)
|
||||
|
||||
add_library(cutlass_library_includes INTERFACE)
|
||||
add_library(nvidia::cutlass::library::includes ALIAS cutlass_library_includes)
|
||||
@@ -59,7 +59,7 @@ cutlass_add_library(
|
||||
src/operation_table.cu
|
||||
src/singleton.cu
|
||||
src/util.cu
|
||||
|
||||
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE GENERATOR_PYTHON_SOURCES CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/scripts/*.py)
|
||||
|
||||
@@ -45,6 +45,9 @@ private:
|
||||
/// Host workspace
|
||||
static int const kHostWorkspaceSize = (4 << 10);
|
||||
|
||||
/// Provider of operations
|
||||
Provider provider_;
|
||||
|
||||
/// CUDA device properties
|
||||
cudaDeviceProp device_;
|
||||
|
||||
@@ -90,6 +93,12 @@ public:
|
||||
/// Gets the current CUDA stream
|
||||
cudaStream_t get_stream() const;
|
||||
|
||||
/// Gets the current provider
|
||||
Provider get_provider() const;
|
||||
|
||||
/// Sets the provider of operations
|
||||
void set_provider(Provider provider);
|
||||
|
||||
/// Gets the device workspace size
|
||||
size_t get_workspace_size() const;
|
||||
|
||||
@@ -149,6 +158,56 @@ public:
|
||||
void * ptr_D, /// Pointer to D matrix
|
||||
int ldd /// Leading dimension of D matrix
|
||||
);
|
||||
|
||||
/// Executes a GEMM computation: D <= alpha * A*B + beta * C.
|
||||
//
|
||||
// Supports batched-strided, batched array or split-K serial or split-K parallel.
|
||||
//
|
||||
Status gemm_universal(
|
||||
|
||||
GemmUniversalMode mode, /// indicates the mode in which the kUniversal GEMM is launched
|
||||
|
||||
int M, /// GEMM M dimension
|
||||
int N, /// GEMM N dimension
|
||||
int K, /// GEMM K dimension
|
||||
|
||||
NumericTypeID element_compute, /// Data type of internal accumulation
|
||||
|
||||
NumericTypeID element_scalar, /// Data type of alpha/beta scalars
|
||||
|
||||
void const *alpha, /// Pointer to alpha scalar
|
||||
|
||||
NumericTypeID element_A, /// Data type of A matrix elements
|
||||
LayoutTypeID layout_A, /// Layout of A matrix
|
||||
ComplexTransform transform_A, /// Complex transformation applied to A matrix - ignored for real-valued matrices
|
||||
|
||||
void const * ptr_A, /// Pointer to A matrix in Global Memory
|
||||
int lda, /// Leading dimension of A matrix
|
||||
|
||||
NumericTypeID element_B, /// Data type of B matrix elements
|
||||
LayoutTypeID layout_B, /// Layout of B matrix
|
||||
ComplexTransform transform_B, /// Complex transformation applied to B matrix - ignored for real-valued matrices
|
||||
|
||||
void const * ptr_B, /// Pointer to B matrix in Global Memory
|
||||
int ldb, /// Leading dimension of B matrix
|
||||
|
||||
void const * beta, /// Pointer to beta scalar
|
||||
|
||||
NumericTypeID element_C, /// Data type of C and D matrices
|
||||
|
||||
void const * ptr_C, /// Pointer to C matrix
|
||||
int ldc, /// Leading dimension of C matrix
|
||||
|
||||
void * ptr_D, /// Pointer to D matrix
|
||||
int ldd, /// Leading dimension of D matrix
|
||||
|
||||
int batch_count = 1, /// Batch count or number of split-K slices
|
||||
|
||||
int64_t batch_stride_A = 0, /// Batch stride of A operand
|
||||
int64_t batch_stride_B = 0, /// Batch stride of B operand
|
||||
int64_t batch_stride_C = 0, /// Batch stride of C operand
|
||||
int64_t batch_stride_D = 0 /// Batch stride of D operand
|
||||
);
|
||||
|
||||
/// Planar complex GEMM
|
||||
///
|
||||
@@ -276,7 +335,6 @@ public:
|
||||
using HandlePtr = std::unique_ptr<Handle>;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace library
|
||||
} // namespace cutlass
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
#include "cutlass/cutlass.h"
|
||||
@@ -93,10 +94,14 @@ enum class NumericTypeID {
|
||||
kS32,
|
||||
kS64,
|
||||
kF16,
|
||||
kBF16,
|
||||
kTF32,
|
||||
kF32,
|
||||
kF64,
|
||||
kCF16,
|
||||
kCBF16,
|
||||
kCF32,
|
||||
kCTF32,
|
||||
kCF64,
|
||||
kCS4,
|
||||
kCS8,
|
||||
@@ -120,6 +125,7 @@ enum class ComplexTransform {
|
||||
|
||||
/// Providers
|
||||
enum class Provider {
|
||||
kNone,
|
||||
kCUTLASS,
|
||||
kReferenceHost,
|
||||
kReferenceDevice,
|
||||
@@ -132,6 +138,8 @@ enum class Provider {
|
||||
/// Enumeration indicating the kind of operation
|
||||
enum class OperationKind {
|
||||
kGemm,
|
||||
kEqGemm,
|
||||
kReduction,
|
||||
kInvalid
|
||||
};
|
||||
|
||||
@@ -160,9 +168,11 @@ enum class OpcodeClassID {
|
||||
};
|
||||
|
||||
enum class MathOperationID {
|
||||
kAdd,
|
||||
kMultiplyAdd,
|
||||
kMultiplyAddSaturate,
|
||||
kMultiplyAddComplex,
|
||||
kMultiplyAddGaussianComplex,
|
||||
kXorPopc,
|
||||
kInvalid
|
||||
};
|
||||
@@ -180,12 +190,17 @@ enum class GemmKind {
|
||||
kInvalid
|
||||
};
|
||||
|
||||
/// Mode of GEMM
|
||||
enum class GemmUniversalMode {
|
||||
kGemm,
|
||||
kGemmSplitKParallel,
|
||||
kBatched,
|
||||
kArray,
|
||||
/// Mode of Universal GEMM
|
||||
using GemmUniversalMode = cutlass::gemm::GemmUniversalMode;
|
||||
|
||||
enum class EpilogueKind {
|
||||
kUnknown,
|
||||
kConversion,
|
||||
kLinearCombination,
|
||||
kLinearCombinationClamp,
|
||||
kLinearCombinationPlanarComplex,
|
||||
kLinearCombinationRelu,
|
||||
kLinearCombinationSigmoid,
|
||||
kInvalid
|
||||
};
|
||||
|
||||
@@ -220,6 +235,22 @@ struct MathInstructionDescription {
|
||||
opcode_class(opcode_class),
|
||||
math_operation(math_operation) {}
|
||||
|
||||
// Equality operator
|
||||
inline
|
||||
bool operator==(MathInstructionDescription const& rhs) const{
|
||||
return (
|
||||
(instruction_shape == rhs.instruction_shape) &&
|
||||
(element_accumulator == rhs.element_accumulator) &&
|
||||
(opcode_class == rhs.opcode_class) &&
|
||||
(math_operation == rhs.math_operation));
|
||||
}
|
||||
|
||||
// Inequality operator
|
||||
inline
|
||||
bool operator!=(MathInstructionDescription const& rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/// Structure describing the tiled structure of a GEMM-like computation
|
||||
@@ -261,6 +292,24 @@ struct TileDescription {
|
||||
math_instruction(math_instruction),
|
||||
minimum_compute_capability(minimum_compute_capability),
|
||||
maximum_compute_capability(maximum_compute_capability) { }
|
||||
|
||||
// Equality operator
|
||||
inline
|
||||
bool operator==(TileDescription const& rhs) const{
|
||||
return (
|
||||
(threadblock_shape == rhs.threadblock_shape) &&
|
||||
(threadblock_stages == rhs.threadblock_stages) &&
|
||||
(warp_count == rhs.warp_count) &&
|
||||
(math_instruction == rhs.math_instruction) &&
|
||||
(minimum_compute_capability == rhs.minimum_compute_capability) &&
|
||||
(maximum_compute_capability == rhs.maximum_compute_capability));
|
||||
}
|
||||
|
||||
// Inequality operator
|
||||
inline
|
||||
bool operator!=(TileDescription const& rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
/// High-level description of an operation
|
||||
@@ -379,6 +428,20 @@ struct GemmDescription : public OperationDescription {
|
||||
transform_B(transform_B) {}
|
||||
};
|
||||
|
||||
|
||||
/// Description of all Reduction operations
|
||||
struct ReductionDescription : public OperationDescription {
|
||||
|
||||
/// Describes the data type of workspace
|
||||
NumericTypeID element_workspace;
|
||||
|
||||
/// Describes the data type of final output
|
||||
NumericTypeID element_output;
|
||||
|
||||
/// Describes the data type of the scalars passed to the epilogue
|
||||
NumericTypeID element_epilogue;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -549,6 +612,42 @@ struct GemmArrayArguments {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Universal GEMM supporting multiple split-K modes, multiple batched modes, real and complex
|
||||
//
|
||||
// OperationKind: Gemm
|
||||
// GemmKind: Universal
|
||||
|
||||
struct GemmUniversalConfiguration {
|
||||
|
||||
GemmUniversalMode mode;
|
||||
gemm::GemmCoord problem_size;
|
||||
int batch_count;
|
||||
|
||||
int64_t lda;
|
||||
int64_t ldb;
|
||||
int64_t ldc;
|
||||
int64_t ldd;
|
||||
};
|
||||
|
||||
struct GemmUniversalArguments {
|
||||
|
||||
void const *A;
|
||||
void const *B;
|
||||
void const *C;
|
||||
void *D;
|
||||
|
||||
void const *alpha;
|
||||
void const *beta;
|
||||
ScalarPointerMode pointer_mode;
|
||||
|
||||
int64_t batch_stride_A;
|
||||
int64_t batch_stride_B;
|
||||
int64_t batch_stride_C;
|
||||
int64_t batch_stride_D;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Complex valued GEMM in which real and imaginary parts are separated by a stride
|
||||
//
|
||||
// OperationKind: Gemm
|
||||
@@ -648,7 +747,6 @@ struct GemmPlanarComplexArrayArguments {
|
||||
ScalarPointerMode pointer_mode;
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace library
|
||||
|
||||
@@ -45,6 +45,13 @@ namespace cutlass {
|
||||
namespace library {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Forward declaration
|
||||
class Manifest;
|
||||
|
||||
// init and insert all cutlass gemm and conv2d op in manifest object (procedurally generated using generator.py)
|
||||
void initialize_all(Manifest &manifest);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// List of operations
|
||||
using OperationVector = std::vector<std::unique_ptr<Operation>>;
|
||||
|
||||
@@ -29,24 +29,28 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <iosfwd>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
|
||||
#include "cutlass/library/library.h"
|
||||
#include "cutlass/library/manifest.h"
|
||||
|
||||
#include "cutlass/library/util.h"
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace cutlass {
|
||||
namespace library {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Data Structures for Gemm Functional Maps
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Tuple uniquely identifying functional behavior
|
||||
/// Tuple uniquely identifying Gemm functional behavior
|
||||
struct GemmFunctionalKey {
|
||||
|
||||
Provider provider;
|
||||
GemmKind gemm_kind;
|
||||
NumericTypeID element_compute;
|
||||
NumericTypeID element_scalar;
|
||||
NumericTypeID element_A;
|
||||
@@ -63,6 +67,8 @@ struct GemmFunctionalKey {
|
||||
|
||||
inline
|
||||
GemmFunctionalKey(
|
||||
Provider provider,
|
||||
GemmKind gemm_kind = GemmKind::kGemm,
|
||||
NumericTypeID element_compute = NumericTypeID::kF32,
|
||||
NumericTypeID element_scalar = NumericTypeID::kF32,
|
||||
NumericTypeID element_A = NumericTypeID::kF16,
|
||||
@@ -73,6 +79,8 @@ struct GemmFunctionalKey {
|
||||
ComplexTransform transform_B = ComplexTransform::kNone,
|
||||
NumericTypeID element_C = NumericTypeID::kF16
|
||||
):
|
||||
provider(provider),
|
||||
gemm_kind(gemm_kind),
|
||||
element_compute(element_compute),
|
||||
element_scalar(element_scalar),
|
||||
element_A(element_A),
|
||||
@@ -87,6 +95,8 @@ struct GemmFunctionalKey {
|
||||
inline
|
||||
bool operator==(GemmFunctionalKey const &rhs) const {
|
||||
return
|
||||
(provider == rhs.provider) &&
|
||||
(gemm_kind == rhs.gemm_kind) &&
|
||||
(element_compute == rhs.element_compute) &&
|
||||
(element_scalar == rhs.element_scalar) &&
|
||||
(element_A == rhs.element_A) &&
|
||||
@@ -104,6 +114,28 @@ struct GemmFunctionalKey {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
inline
|
||||
std::ostream & operator<<(std::ostream &out, cutlass::library::GemmFunctionalKey const &k) {
|
||||
|
||||
out << "{\n"
|
||||
<< " provider: " << to_string(k.provider) << "\n"
|
||||
<< " gemm_kind: " << to_string(k.gemm_kind) << "\n"
|
||||
<< " element_compute: " << to_string(k.element_compute) << "\n"
|
||||
<< " element_scalar: " << to_string(k.element_scalar) << "\n"
|
||||
<< " element_A: " << to_string(k.element_A) << "\n"
|
||||
<< " layout_A: " << to_string(k.layout_A) << "\n"
|
||||
<< " transform_A: " << to_string(k.transform_A) << "\n"
|
||||
<< " element_B: " << to_string(k.element_B) << "\n"
|
||||
<< " layout_B: " << to_string(k.layout_B) << "\n"
|
||||
<< " transform_B: " << to_string(k.transform_B) << "\n"
|
||||
<< " element_C: " << to_string(k.element_C) << "\n"
|
||||
<< "}";
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Hash function for GemmFunctionalKey
|
||||
@@ -120,15 +152,17 @@ struct GemmFunctionalKeyHasher {
|
||||
IntHash hash;
|
||||
|
||||
return
|
||||
rotl(hash(int(key.element_compute)), 2) ^
|
||||
rotl(hash(int(key.element_scalar)), 3) ^
|
||||
rotl(hash(int(key.element_A)), 4) ^
|
||||
rotl(hash(int(key.layout_A)), 5) ^
|
||||
rotl(hash(int(key.transform_A)), 6) ^
|
||||
rotl(hash(int(key.element_B)), 7) ^
|
||||
rotl(hash(int(key.layout_B)), 8) ^
|
||||
rotl(hash(int(key.transform_B)), 9) ^
|
||||
rotl(hash(int(key.element_C)), 10);
|
||||
rotl(hash(int(key.provider)), 1) ^
|
||||
rotl(hash(int(key.gemm_kind)), 2) ^
|
||||
rotl(hash(int(key.element_compute)), 3) ^
|
||||
rotl(hash(int(key.element_scalar)), 4) ^
|
||||
rotl(hash(int(key.element_A)), 5) ^
|
||||
rotl(hash(int(key.layout_A)), 6) ^
|
||||
rotl(hash(int(key.transform_A)), 7) ^
|
||||
rotl(hash(int(key.element_B)), 8) ^
|
||||
rotl(hash(int(key.layout_B)), 9) ^
|
||||
rotl(hash(int(key.transform_B)), 10) ^
|
||||
rotl(hash(int(key.element_C)), 11);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -172,6 +206,7 @@ using GemmOperationFunctionalMap = std::unordered_map<
|
||||
GemmOperationVectorMap,
|
||||
GemmFunctionalKeyHasher
|
||||
>;
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -179,15 +214,10 @@ using GemmOperationFunctionalMap = std::unordered_map<
|
||||
class OperationTable {
|
||||
public:
|
||||
|
||||
/// Map of all operations of type kGemm and gemm_kind of type kGemm
|
||||
/// Map of all operations of type kGemm
|
||||
// provider (kCUTLASS)
|
||||
GemmOperationFunctionalMap gemm_operations;
|
||||
|
||||
/// Map of all operations of type kGemm and gemm_kind of type kPlanarComplex
|
||||
GemmOperationFunctionalMap gemm_planar_complex_operations;
|
||||
|
||||
/// Map of all operations of type kGemm and gemm_kind of type kPlanarComplexArray
|
||||
GemmOperationFunctionalMap gemm_planar_complex_array_operations;
|
||||
|
||||
public:
|
||||
|
||||
void append(Manifest const &manifest);
|
||||
@@ -202,4 +232,3 @@ public:
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::ostream & operator<<(std::ostream &out, cutlass::library::GemmFunctionalKey const &k);
|
||||
|
||||
|
||||
@@ -49,6 +49,9 @@ char const *to_string(Provider provider, bool pretty = false);
|
||||
/// Parses a Provider enumerant from a string
|
||||
template <> Provider from_string<Provider>(std::string const &str);
|
||||
|
||||
/// Converts a GemmKind enumerant to a string
|
||||
char const *to_string(GemmKind type, bool pretty = false);
|
||||
|
||||
/// Converts a NumericType enumerant to a string
|
||||
char const *to_string(OperationKind type, bool pretty = false);
|
||||
|
||||
@@ -111,6 +114,14 @@ char const *to_string(ComplexTransform type, bool pretty = false);
|
||||
template <>
|
||||
ComplexTransform from_string<ComplexTransform>(std::string const &str);
|
||||
|
||||
|
||||
/// Converts a SplitKMode enumerant to a string
|
||||
char const *to_string(SplitKMode split_k_mode, bool pretty = false);
|
||||
|
||||
/// Converts a SplitKMode enumerant from a string
|
||||
template <>
|
||||
SplitKMode from_string<SplitKMode>(std::string const &str);
|
||||
|
||||
/// Lexical cast from int64_t to string
|
||||
std::string lexical_cast(int64_t int_value);
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ from library import *
|
||||
class GemmOperation:
|
||||
#
|
||||
def __init__(self, gemm_kind, arch, tile_description, A, B, C, element_epilogue, \
|
||||
epilogue_functor = EpilogueFunctor.LinearCombination, swizzling_functor = SwizzlingFunctor.Cohort):
|
||||
epilogue_functor = EpilogueFunctor.LinearCombination, swizzling_functor = SwizzlingFunctor.Identity8):
|
||||
|
||||
self.operation_kind = OperationKind.Gemm
|
||||
self.arch = arch
|
||||
@@ -40,6 +40,7 @@ class GemmOperation:
|
||||
def is_complex(self):
|
||||
complex_operators = [
|
||||
MathOperation.multiply_add_complex,
|
||||
MathOperation.multiply_add_complex_gaussian
|
||||
]
|
||||
return self.tile_description.math_instruction.math_operation in complex_operators
|
||||
|
||||
@@ -58,6 +59,8 @@ class GemmOperation:
|
||||
|
||||
#
|
||||
def short_math_name(self):
|
||||
if self.tile_description.math_instruction.math_operation == MathOperation.multiply_add_complex_gaussian:
|
||||
return "g%s" % ShortDataTypeNames[self.accumulator_type()]
|
||||
return ShortDataTypeNames[self.accumulator_type()]
|
||||
|
||||
|
||||
@@ -259,6 +262,135 @@ class EmitGemmInstance:
|
||||
|
||||
###################################################################################################
|
||||
|
||||
#
|
||||
class EmitGemmUniversalInstance:
|
||||
''' Responsible for emitting a CUTLASS template definition'''
|
||||
|
||||
def __init__(self):
|
||||
self.gemm_template = """
|
||||
// Gemm operator ${operation_name}
|
||||
using ${operation_name}_base =
|
||||
typename cutlass::gemm::kernel::DefaultGemmUniversal<
|
||||
${element_b}, ${layout_b}, ${transform_b}, ${align_b}, // transposed B operand
|
||||
${element_a}, ${layout_a}, ${transform_a}, ${align_a}, // transposed A operand
|
||||
${element_c}, ${layout_c},
|
||||
${element_accumulator},
|
||||
${opcode_class},
|
||||
${arch},
|
||||
cutlass::gemm::GemmShape<${threadblock_shape_m}, ${threadblock_shape_n}, ${threadblock_shape_k}>,
|
||||
cutlass::gemm::GemmShape<${warp_shape_m}, ${warp_shape_n}, ${warp_shape_k}>,
|
||||
cutlass::gemm::GemmShape<${instruction_shape_m}, ${instruction_shape_n}, ${instruction_shape_k}>,
|
||||
${epilogue_functor}<
|
||||
${element_c},
|
||||
${epilogue_vector_length},
|
||||
${element_accumulator},
|
||||
${element_epilogue}
|
||||
>,
|
||||
${swizzling_functor},
|
||||
${stages},
|
||||
${math_operation}
|
||||
>::GemmKernel;
|
||||
|
||||
// Define named type
|
||||
struct ${operation_name} :
|
||||
public ${operation_name}_base { };
|
||||
"""
|
||||
self.gemm_template_interleaved = """
|
||||
// Gemm operator ${operation_name}
|
||||
using ${operation_name}_base =
|
||||
typename cutlass::gemm::kernel::DefaultGemmUniversal<
|
||||
${element_a}, ${layout_a}, ${transform_a}, ${align_a},
|
||||
${element_b}, ${layout_b}, ${transform_b}, ${align_b},
|
||||
${element_c}, ${layout_c},
|
||||
${element_accumulator},
|
||||
${opcode_class},
|
||||
${arch},
|
||||
cutlass::gemm::GemmShape<${threadblock_shape_m}, ${threadblock_shape_n}, ${threadblock_shape_k}>,
|
||||
cutlass::gemm::GemmShape<${warp_shape_m}, ${warp_shape_n}, ${warp_shape_k}>,
|
||||
cutlass::gemm::GemmShape<${instruction_shape_m}, ${instruction_shape_n}, ${instruction_shape_k}>,
|
||||
${epilogue_functor}<
|
||||
${element_c},
|
||||
${epilogue_vector_length},
|
||||
${element_accumulator},
|
||||
${element_epilogue}
|
||||
>,
|
||||
${swizzling_functor},
|
||||
${stages},
|
||||
${math_operation}
|
||||
>::GemmKernel;
|
||||
|
||||
// Define named type
|
||||
struct ${operation_name} :
|
||||
public ${operation_name}_base { };
|
||||
"""
|
||||
|
||||
def emit(self, operation):
|
||||
|
||||
threadblock_shape = operation.tile_description.threadblock_shape
|
||||
warp_count = operation.tile_description.warp_count
|
||||
|
||||
warp_shape = [threadblock_shape[idx] // warp_count[idx] for idx in range(3)]
|
||||
warp_shape[2] = operation.tile_description.threadblock_shape[2]
|
||||
|
||||
epilogue_vector_length = int(min(operation.C.alignment * DataTypeSize[operation.C.element], 128) / DataTypeSize[operation.C.element])
|
||||
|
||||
transpose_layouts = {
|
||||
LayoutType.ColumnMajor: LayoutType.RowMajor,
|
||||
LayoutType.RowMajor: LayoutType.ColumnMajor
|
||||
}
|
||||
|
||||
if operation.A.layout in transpose_layouts.keys() and \
|
||||
operation.B.layout in transpose_layouts.keys() and \
|
||||
operation.C.layout in transpose_layouts.keys():
|
||||
|
||||
instance_layout_A = transpose_layouts[operation.A.layout]
|
||||
instance_layout_B = transpose_layouts[operation.B.layout]
|
||||
instance_layout_C = transpose_layouts[operation.C.layout]
|
||||
|
||||
gemm_template = self.gemm_template
|
||||
else:
|
||||
instance_layout_A, instance_layout_B, instance_layout_C = \
|
||||
(operation.A.layout, operation.B.layout, operation.C.layout)
|
||||
|
||||
gemm_template = self.gemm_template_interleaved
|
||||
#
|
||||
|
||||
values = {
|
||||
'operation_name': operation.procedural_name(),
|
||||
'element_a': DataTypeTag[operation.A.element],
|
||||
'layout_a': LayoutTag[instance_layout_A],
|
||||
'element_b': DataTypeTag[operation.B.element],
|
||||
'layout_b': LayoutTag[instance_layout_B],
|
||||
'element_c': DataTypeTag[operation.C.element],
|
||||
'layout_c': LayoutTag[instance_layout_C],
|
||||
'element_accumulator': DataTypeTag[operation.accumulator_type()],
|
||||
'opcode_class': OpcodeClassTag[operation.tile_description.math_instruction.opcode_class],
|
||||
'arch': "cutlass::arch::Sm%d" % operation.arch,
|
||||
'threadblock_shape_m': str(operation.tile_description.threadblock_shape[0]),
|
||||
'threadblock_shape_n': str(operation.tile_description.threadblock_shape[1]),
|
||||
'threadblock_shape_k': str(operation.tile_description.threadblock_shape[2]),
|
||||
'warp_shape_m': str(warp_shape[0]),
|
||||
'warp_shape_n': str(warp_shape[1]),
|
||||
'warp_shape_k': str(warp_shape[2]),
|
||||
'instruction_shape_m': str(operation.tile_description.math_instruction.instruction_shape[0]),
|
||||
'instruction_shape_n': str(operation.tile_description.math_instruction.instruction_shape[1]),
|
||||
'instruction_shape_k': str(operation.tile_description.math_instruction.instruction_shape[2]),
|
||||
'epilogue_vector_length': str(epilogue_vector_length),
|
||||
'element_epilogue': str(DataTypeTag[operation.element_epilogue]),
|
||||
'epilogue_functor': EpilogueFunctorTag[operation.epilogue_functor],
|
||||
'swizzling_functor': SwizzlingFunctorTag[operation.swizzling_functor],
|
||||
'stages': str(operation.tile_description.stages),
|
||||
'align_a': str(operation.A.alignment),
|
||||
'align_b': str(operation.B.alignment),
|
||||
'transform_a': ComplexTransformTag[operation.A.complex_transform],
|
||||
'transform_b': ComplexTransformTag[operation.B.complex_transform],
|
||||
'math_operation': MathOperationTag[operation.tile_description.math_instruction.math_operation]
|
||||
}
|
||||
|
||||
return SubstituteTemplate(gemm_template, values)
|
||||
|
||||
###################################################################################################
|
||||
|
||||
#
|
||||
class EmitGemmPlanarComplexInstance:
|
||||
''' Responsible for emitting a CUTLASS template definition'''
|
||||
@@ -282,12 +414,13 @@ class EmitGemmPlanarComplexInstance:
|
||||
${element_accumulator},
|
||||
${element_epilogue}
|
||||
>,
|
||||
cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle,
|
||||
cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>,
|
||||
${stages},
|
||||
${math_operator}
|
||||
>::GemmKernel;
|
||||
|
||||
struct ${operation_name} : public Operation_${operation_name} { };
|
||||
struct ${operation_name} :
|
||||
public Operation_${operation_name} { };
|
||||
"""
|
||||
|
||||
def emit(self, operation):
|
||||
@@ -355,7 +488,7 @@ class EmitGemmPlanarComplexArrayInstance:
|
||||
${element_accumulator},
|
||||
${element_epilogue}
|
||||
>,
|
||||
cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle,
|
||||
cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>,
|
||||
${stages},
|
||||
${math_operator}
|
||||
>::GemmArrayKernel;
|
||||
@@ -419,12 +552,14 @@ class EmitGemmConfigurationLibrary:
|
||||
|
||||
self.instance_emitter = {
|
||||
GemmKind.Gemm: EmitGemmInstance,
|
||||
GemmKind.Universal: EmitGemmUniversalInstance,
|
||||
GemmKind.PlanarComplex: EmitGemmPlanarComplexInstance,
|
||||
GemmKind.PlanarComplexArray: EmitGemmPlanarComplexArrayInstance
|
||||
}
|
||||
|
||||
self.gemm_kind_wrappers = {
|
||||
GemmKind.Gemm: 'GemmOperation',
|
||||
GemmKind.Universal: 'GemmUniversalOperation',
|
||||
GemmKind.PlanarComplex: 'GemmPlanarComplexOperation',
|
||||
GemmKind.PlanarComplexArray: 'GemmPlanarComplexArrayOperation'
|
||||
}
|
||||
@@ -436,6 +571,13 @@ class EmitGemmConfigurationLibrary:
|
||||
${compile_guard_start}
|
||||
manifest.append(new ${gemm_kind}<Operation_${operation_name}>("${operation_name}"));
|
||||
${compile_guard_end}
|
||||
""",
|
||||
GemmKind.Universal: """
|
||||
${compile_guard_start}
|
||||
manifest.append(new ${gemm_kind}<
|
||||
cutlass::gemm::device::GemmUniversalAdapter<${operation_name}>
|
||||
>("${operation_name}"));
|
||||
${compile_guard_end}
|
||||
""",
|
||||
GemmKind.PlanarComplex: """
|
||||
${compile_guard_start}
|
||||
@@ -542,3 +684,4 @@ void initialize_${configuration_name}(Manifest &manifest) {
|
||||
|
||||
###################################################################################################
|
||||
###################################################################################################
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ from gemm_operation import *
|
||||
def CudaToolkitVersionSatisfies(semantic_ver_string, major, minor, patch = 0):
|
||||
|
||||
# by default, use the latest CUDA Toolkit version
|
||||
cuda_version = [10, 2, 82]
|
||||
cuda_version = [11, 0, 132]
|
||||
|
||||
# Update cuda_version based on parsed string
|
||||
if semantic_ver_string != '':
|
||||
@@ -36,7 +36,7 @@ def CudaToolkitVersionSatisfies(semantic_ver_string, major, minor, patch = 0):
|
||||
#
|
||||
def CreateGemmOperator(manifest, layouts, tile_descriptions, data_type, \
|
||||
alignment_constraints, complex_transforms = None, epilogue_functor = EpilogueFunctor.LinearCombination, \
|
||||
swizzling_functor = SwizzlingFunctor.Cohort):
|
||||
swizzling_functor = SwizzlingFunctor.Identity8):
|
||||
|
||||
if complex_transforms is None:
|
||||
complex_transforms = [(ComplexTransform.none, ComplexTransform.none),]
|
||||
@@ -61,7 +61,7 @@ def CreateGemmOperator(manifest, layouts, tile_descriptions, data_type, \
|
||||
B = TensorDescription(element_b, layout[1], alignment, complex_transform[1])
|
||||
C = TensorDescription(element_c, layout[2], alignment_c)
|
||||
|
||||
new_operation = GemmOperation(GemmKind.Gemm, tile_description.minimum_compute_capability, \
|
||||
new_operation = GemmOperation(GemmKind.Universal, tile_description.minimum_compute_capability, \
|
||||
tile_description, A, B, C, element_epilogue, epilogue_functor, swizzling_functor)
|
||||
|
||||
manifest.append(new_operation)
|
||||
@@ -466,6 +466,9 @@ def GenerateSM70_WmmaTensorOp_161616(manifest, args):
|
||||
def GenerateSM70(manifest, args):
|
||||
GenerateSM70_TensorOp_884(manifest, args)
|
||||
GenerateSM70_PlanarComplexTensorOp_884(manifest, args)
|
||||
|
||||
# To limit build size, WMMA GEMMs are disabled for now.
|
||||
#
|
||||
#GenerateSM70_WmmaTensorOp_161616(manifest, args)
|
||||
|
||||
###################################################################################################
|
||||
@@ -621,6 +624,11 @@ def GenerateSM75_TensorOp_8816_TN(manifest, args):
|
||||
DataType.s8, DataType.s8, DataType.s32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_saturate),
|
||||
MathInstruction( \
|
||||
[8, 8, 16], \
|
||||
DataType.u8, DataType.u8, DataType.s32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_saturate),
|
||||
]
|
||||
|
||||
min_cc = 75
|
||||
@@ -654,7 +662,7 @@ def GenerateSM75_TensorOp_8816_TN(manifest, args):
|
||||
data_type_mixed = [
|
||||
math_inst.element_a,
|
||||
math_inst.element_b,
|
||||
math_inst.element_a,
|
||||
DataType.s8,
|
||||
DataType.f32,
|
||||
]
|
||||
|
||||
@@ -687,6 +695,11 @@ def GenerateSM75_TensorOp_8816_Interleaved(manifest, args):
|
||||
DataType.s8, DataType.s8, DataType.s32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_saturate),
|
||||
MathInstruction( \
|
||||
[8, 8, 16], \
|
||||
DataType.u8, DataType.u8, DataType.s32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_saturate),
|
||||
]
|
||||
|
||||
min_cc = 75
|
||||
@@ -712,8 +725,7 @@ def GenerateSM75_TensorOp_8816_Interleaved(manifest, args):
|
||||
]
|
||||
|
||||
operations = CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp, \
|
||||
SwizzlingFunctor.Identity)
|
||||
data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
for op in operations:
|
||||
op.C.alignment = 8
|
||||
@@ -736,6 +748,11 @@ def GenerateSM75_TensorOp_8832_TN(manifest, args):
|
||||
DataType.s4, DataType.s4, DataType.s32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_saturate),
|
||||
MathInstruction( \
|
||||
[8, 8, 32], \
|
||||
DataType.u4, DataType.u4, DataType.s32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_saturate),
|
||||
]
|
||||
|
||||
min_cc = 75
|
||||
@@ -769,7 +786,7 @@ def GenerateSM75_TensorOp_8832_TN(manifest, args):
|
||||
data_type_mixed = [
|
||||
math_inst.element_a,
|
||||
math_inst.element_b,
|
||||
math_inst.element_a,
|
||||
DataType.s4,
|
||||
DataType.f32,
|
||||
]
|
||||
|
||||
@@ -804,6 +821,11 @@ def GenerateSM75_TensorOp_8832_Interleaved(manifest, args):
|
||||
DataType.s4, DataType.s4, DataType.s32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_saturate),
|
||||
MathInstruction( \
|
||||
[8, 8, 32], \
|
||||
DataType.u4, DataType.u4, DataType.s32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_saturate),
|
||||
]
|
||||
|
||||
min_cc = 75
|
||||
@@ -832,8 +854,7 @@ def GenerateSM75_TensorOp_8832_Interleaved(manifest, args):
|
||||
]
|
||||
|
||||
operations = CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp, \
|
||||
SwizzlingFunctor.Identity)
|
||||
data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
for op in operations:
|
||||
op.C.alignment = 16
|
||||
@@ -911,6 +932,831 @@ def GenerateSM75(manifest, args):
|
||||
###################################################################################################
|
||||
###################################################################################################
|
||||
|
||||
#
|
||||
def GenerateSM80_TensorOp_16816(manifest, args):
|
||||
|
||||
if not CudaToolkitVersionSatisfies(args.cuda_version, 11, 0):
|
||||
return
|
||||
|
||||
layouts = [
|
||||
(LayoutType.ColumnMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.ColumnMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
]
|
||||
|
||||
math_instructions = [
|
||||
MathInstruction( \
|
||||
[16, 8, 16], \
|
||||
DataType.f16, DataType.f16, DataType.f32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add),
|
||||
MathInstruction( \
|
||||
[16, 8, 16], \
|
||||
DataType.f16, DataType.f16, DataType.f16, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add),
|
||||
MathInstruction( \
|
||||
[16, 8, 16], \
|
||||
DataType.bf16, DataType.bf16, DataType.f32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add),
|
||||
]
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
|
||||
alignment_constraints = [8, 4, 2]
|
||||
|
||||
for math_inst in math_instructions:
|
||||
tile_descriptions = [
|
||||
TileDescription([256, 128, 32], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 32], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 32], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 32], 4, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 32], 4, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 32], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 32], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 64], 3, [1, 2, 2], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 64], 3, [2, 1, 2], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 64], 4, [1, 2, 2], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 64], 4, [2, 1, 2], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 32], 10, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 64], 4, [1, 2, 2], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 64], 5, [1, 2, 2], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 64], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 64], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 64], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 64], 4, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 64], 3, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
data_type = [
|
||||
math_inst.element_a,
|
||||
math_inst.element_b,
|
||||
math_inst.element_accumulator,
|
||||
math_inst.element_accumulator,
|
||||
]
|
||||
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints)
|
||||
|
||||
# Avoid emitting two kernels if the accumulator type does not differ from the input type (e.g. F16 accumulation)
|
||||
if math_inst.element_a != math_inst.element_accumulator:
|
||||
|
||||
data_type_mixed = [
|
||||
math_inst.element_a,
|
||||
math_inst.element_b,
|
||||
math_inst.element_a,
|
||||
math_inst.element_accumulator,
|
||||
]
|
||||
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints)
|
||||
|
||||
#
|
||||
|
||||
#
|
||||
def GenerateSM80_PlanarComplexTensorOp_16816(manifest, args):
|
||||
|
||||
if not CudaToolkitVersionSatisfies(args.cuda_version, 11, 0):
|
||||
return
|
||||
|
||||
layouts = [
|
||||
(LayoutType.ColumnMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.ColumnMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
]
|
||||
|
||||
complex_transforms = [
|
||||
(ComplexTransform.none, ComplexTransform.none),
|
||||
(ComplexTransform.conj, ComplexTransform.none),
|
||||
(ComplexTransform.none, ComplexTransform.conj),
|
||||
(ComplexTransform.conj, ComplexTransform.conj)
|
||||
]
|
||||
|
||||
math_instructions = [
|
||||
MathInstruction( \
|
||||
[16, 8, 16], \
|
||||
DataType.f16, DataType.f16, DataType.f32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add),
|
||||
MathInstruction( \
|
||||
[16, 8, 16], \
|
||||
DataType.bf16, DataType.bf16, DataType.f32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add),
|
||||
MathInstruction( \
|
||||
[16, 8, 16], \
|
||||
DataType.f16, DataType.f16, DataType.f16, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add),
|
||||
]
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
|
||||
alignment_constraints = [8, ]
|
||||
|
||||
for math_inst in math_instructions:
|
||||
tile_descriptions = [
|
||||
TileDescription([ 64, 128, 32], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 32], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 32], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
data_type = [
|
||||
math_inst.element_a,
|
||||
math_inst.element_b,
|
||||
math_inst.element_accumulator,
|
||||
math_inst.element_accumulator,
|
||||
]
|
||||
|
||||
CreateGemmPlanarComplexOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints, complex_transforms)
|
||||
|
||||
# Avoid emitting two kernels if the accumulator type does not differ from the input type (e.g. F16 accumulation)
|
||||
if math_inst.element_a != math_inst.element_accumulator:
|
||||
|
||||
data_type_mixed = [
|
||||
math_inst.element_a,
|
||||
math_inst.element_b,
|
||||
math_inst.element_a,
|
||||
math_inst.element_accumulator,
|
||||
]
|
||||
|
||||
CreateGemmPlanarComplexOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints, complex_transforms)
|
||||
|
||||
#
|
||||
def GenerateSM80_TensorOp_16832_TN(manifest, args):
|
||||
|
||||
if not CudaToolkitVersionSatisfies(args.cuda_version, 11, 0):
|
||||
return
|
||||
|
||||
layouts = [
|
||||
(LayoutType.RowMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
]
|
||||
|
||||
math_instructions = [
|
||||
MathInstruction( \
|
||||
[16, 8, 32], \
|
||||
DataType.s8, DataType.s8, DataType.s32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_saturate),
|
||||
MathInstruction( \
|
||||
[16, 8, 32], \
|
||||
DataType.u8, DataType.u8, DataType.s32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_saturate),
|
||||
]
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
|
||||
alignment_constraints = [16,]
|
||||
|
||||
for math_inst in math_instructions:
|
||||
tile_descriptions = [
|
||||
TileDescription([256, 128, 64], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 64], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 64], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 64], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 64], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 64], 5, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 64], 4, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([64, 256, 64], 4, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 128], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 128], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 128], 5, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 128], 3, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([64, 256, 128], 3, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
data_type = [math_inst.element_a, math_inst.element_b, DataType.s32, DataType.s32]
|
||||
data_type_mixed = [math_inst.element_a, math_inst.element_b, DataType.s8, DataType.f32]
|
||||
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
operations = []
|
||||
|
||||
operations += CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
for op in operations:
|
||||
if op.tile_description.threadblock_shape[1] >= 128:
|
||||
op.C.alignment = 16
|
||||
else:
|
||||
op.C.alignment = 8
|
||||
|
||||
#
|
||||
|
||||
#
|
||||
def GenerateSM80_TensorOp_16832_Interleaved(manifest, args):
|
||||
|
||||
if not CudaToolkitVersionSatisfies(args.cuda_version, 11, 0):
|
||||
return
|
||||
|
||||
layouts = [
|
||||
(LayoutType.ColumnMajorInterleaved32, LayoutType.RowMajorInterleaved32, LayoutType.ColumnMajorInterleaved32),
|
||||
]
|
||||
|
||||
math_instructions = [
|
||||
MathInstruction( \
|
||||
[16, 8, 32], \
|
||||
DataType.s8, DataType.s8, DataType.s32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_saturate),
|
||||
MathInstruction( \
|
||||
[16, 8, 32], \
|
||||
DataType.u8, DataType.u8, DataType.s32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_saturate),
|
||||
]
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
|
||||
alignment_constraints = [16,]
|
||||
|
||||
for math_inst in math_instructions:
|
||||
tile_descriptions = [
|
||||
TileDescription([256, 128, 64], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 64], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 64], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 64], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 64], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 64], 5, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
data_type_mixed = [math_inst.element_a, math_inst.element_b, DataType.s8, DataType.f32]
|
||||
|
||||
operations = CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
for op in operations:
|
||||
op.C.alignment = 8
|
||||
|
||||
#
|
||||
|
||||
#
|
||||
def GenerateSM80_TensorOp_16864_TN(manifest, args):
|
||||
|
||||
if not CudaToolkitVersionSatisfies(args.cuda_version, 11, 0):
|
||||
return
|
||||
|
||||
layouts = [
|
||||
(LayoutType.RowMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
]
|
||||
|
||||
math_instructions = [
|
||||
MathInstruction( \
|
||||
[16, 8, 64], \
|
||||
DataType.s4, DataType.s4, DataType.s32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_saturate),
|
||||
MathInstruction( \
|
||||
[16, 8, 64], \
|
||||
DataType.u4, DataType.u4, DataType.s32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_saturate),
|
||||
]
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
|
||||
alignment_constraints = [32,]
|
||||
|
||||
for math_inst in math_instructions:
|
||||
tile_descriptions = [
|
||||
TileDescription([256, 128, 128], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 128], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 128], 5, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 256], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 256], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 256], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 256], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 256], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 256], 5, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
data_type = [math_inst.element_a, math_inst.element_b, DataType.s32, DataType.s32]
|
||||
data_type_mixed = [math_inst.element_a, math_inst.element_b, DataType.s4, DataType.f32]
|
||||
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
operations = []
|
||||
|
||||
operations += CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
for op in operations:
|
||||
if op.tile_description.threadblock_shape[1] >= 128:
|
||||
op.C.alignment = 8
|
||||
elif op.tile_description.threadblock_shape[1] == 64:
|
||||
op.C.alignment = 8
|
||||
else:
|
||||
op.C.alignment = 4
|
||||
#
|
||||
|
||||
#
|
||||
def GenerateSM80_TensorOp_16864_Interleaved(manifest, args):
|
||||
|
||||
if not CudaToolkitVersionSatisfies(args.cuda_version, 11, 0):
|
||||
return
|
||||
|
||||
layouts = [
|
||||
(LayoutType.ColumnMajorInterleaved64, LayoutType.RowMajorInterleaved64, LayoutType.ColumnMajorInterleaved64),
|
||||
]
|
||||
|
||||
math_instructions = [
|
||||
MathInstruction( \
|
||||
[16, 8, 64], \
|
||||
DataType.s4, DataType.s4, DataType.s32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_saturate),
|
||||
MathInstruction( \
|
||||
[16, 8, 64], \
|
||||
DataType.u4, DataType.u4, DataType.s32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_saturate),
|
||||
]
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
|
||||
alignment_constraints = [32,]
|
||||
|
||||
for math_inst in math_instructions:
|
||||
tile_descriptions = [
|
||||
TileDescription([256, 128, 128], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 128], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 128], 5, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
data_type_mixed = [math_inst.element_a, math_inst.element_b, DataType.s4, DataType.f32]
|
||||
|
||||
operations = []
|
||||
|
||||
operations += CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
for op in operations:
|
||||
op.C.alignment = 16
|
||||
#
|
||||
|
||||
#
|
||||
def GenerateSM80_TensorOp_168256(manifest, args):
|
||||
|
||||
if not CudaToolkitVersionSatisfies(args.cuda_version, 11, 0):
|
||||
return
|
||||
|
||||
layouts = [
|
||||
(LayoutType.RowMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
]
|
||||
|
||||
math_instructions = [
|
||||
MathInstruction( \
|
||||
[16, 8, 256], \
|
||||
DataType.b1, DataType.b1, DataType.s32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.xor_popc),
|
||||
]
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
|
||||
alignment_constraints = [128,]
|
||||
|
||||
for math_inst in math_instructions:
|
||||
tile_descriptions = [
|
||||
TileDescription([256, 128, 512], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 512], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 512], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 512], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 512], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 512], 5, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 1024], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 1024], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 1024], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 1024], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 1024], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 1024], 5, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
data_type = [DataType.b1, DataType.b1, DataType.s32, DataType.s32]
|
||||
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
#
|
||||
|
||||
#
|
||||
def GenerateSM80_TensorOp_1688(manifest, args):
|
||||
|
||||
if not CudaToolkitVersionSatisfies(args.cuda_version, 11, 0):
|
||||
return
|
||||
|
||||
layouts = [
|
||||
(LayoutType.ColumnMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.ColumnMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
]
|
||||
|
||||
math_instructions = [
|
||||
MathInstruction( \
|
||||
[16, 8, 8], \
|
||||
DataType.tf32, DataType.tf32, DataType.f32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add)
|
||||
]
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
|
||||
alignment_constraints = [4, 2, 1]
|
||||
|
||||
for math_inst in math_instructions:
|
||||
tile_descriptions = [
|
||||
TileDescription([256, 128, 16], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 16], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 16], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 16], 4, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 16], 4, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 16], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 16], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 32], 3, [1, 2, 2], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 32], 3, [2, 1, 2], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 32], 4, [1, 2, 2], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 32], 4, [2, 1, 2], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 16], 10, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 32], 4, [1, 2, 2], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 32], 5, [1, 2, 2], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 32], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 32], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 32], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 32], 4, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 32], 3, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
data_type = [
|
||||
math_inst.element_a,
|
||||
math_inst.element_b,
|
||||
math_inst.element_accumulator,
|
||||
math_inst.element_accumulator,
|
||||
]
|
||||
|
||||
data_type_mixed = [
|
||||
math_inst.element_a,
|
||||
math_inst.element_b,
|
||||
math_inst.element_a,
|
||||
math_inst.element_accumulator,
|
||||
]
|
||||
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints)
|
||||
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints)
|
||||
|
||||
#
|
||||
|
||||
#
|
||||
def GenerateSM80_TensorOp_1688_fast_math(manifest, args):
|
||||
|
||||
if not CudaToolkitVersionSatisfies(args.cuda_version, 11, 0):
|
||||
return
|
||||
|
||||
layouts = [
|
||||
(LayoutType.ColumnMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.ColumnMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
]
|
||||
|
||||
math_instructions = [
|
||||
MathInstruction( \
|
||||
[16, 8, 8], \
|
||||
DataType.tf32, DataType.tf32, DataType.f32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add),
|
||||
MathInstruction( \
|
||||
[16, 8, 8], \
|
||||
DataType.f16, DataType.f16, DataType.f32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_fast_f16),
|
||||
MathInstruction( \
|
||||
[16, 8, 8], \
|
||||
DataType.bf16, DataType.bf16, DataType.f32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_fast_bf16)
|
||||
]
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
|
||||
alignment_constraints = [4, 2, 1]
|
||||
|
||||
for math_inst in math_instructions:
|
||||
tile_descriptions = [
|
||||
TileDescription([256, 128, 16], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 16], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 16], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 16], 4, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 16], 4, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 16], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 16], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 32], 3, [1, 2, 2], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 32], 3, [2, 1, 2], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 32], 4, [1, 2, 2], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 32], 4, [2, 1, 2], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 16], 10, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 32], 4, [1, 2, 2], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 32], 5, [1, 2, 2], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 32], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 32], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 32], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 32], 4, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 32], 3, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
data_type = [DataType.f32, DataType.f32, DataType.f32, DataType.f32]
|
||||
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints)
|
||||
|
||||
#
|
||||
|
||||
#
|
||||
def GenerateSM80_TensorOp_1688_complex(manifest, args):
|
||||
|
||||
if not CudaToolkitVersionSatisfies(args.cuda_version, 11, 0):
|
||||
return
|
||||
|
||||
layouts = [
|
||||
(LayoutType.ColumnMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.ColumnMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
]
|
||||
|
||||
math_inst = MathInstruction( \
|
||||
[16, 8, 8], \
|
||||
DataType.f32, DataType.f32, DataType.f32, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_complex)
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
|
||||
tile_descriptions = [
|
||||
TileDescription([64, 64, 16], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 16], 4, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([64, 128, 16], 4, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([64, 64, 16], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([64, 32, 16], 4, [2, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([32, 32, 16], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
data_type = [
|
||||
DataType.cf32, DataType.cf32, DataType.cf32, DataType.cf32
|
||||
]
|
||||
|
||||
alignment_constraints = [1,]
|
||||
|
||||
complex_transforms = [
|
||||
(ComplexTransform.none, ComplexTransform.none),
|
||||
(ComplexTransform.conj, ComplexTransform.none),
|
||||
(ComplexTransform.none, ComplexTransform.conj),
|
||||
(ComplexTransform.conj, ComplexTransform.conj)
|
||||
]
|
||||
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints, complex_transforms)
|
||||
#
|
||||
|
||||
#
|
||||
def GenerateSM80_TensorOp_884(manifest, args):
|
||||
|
||||
if not CudaToolkitVersionSatisfies(args.cuda_version, 11, 0):
|
||||
return
|
||||
|
||||
layouts = [
|
||||
(LayoutType.ColumnMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.ColumnMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
]
|
||||
|
||||
math_inst = \
|
||||
MathInstruction( \
|
||||
[8, 8, 4], \
|
||||
DataType.f64, DataType.f64, DataType.f64, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add)
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
|
||||
alignment_constraints = [1,]
|
||||
|
||||
tile_descriptions = [
|
||||
TileDescription([128, 128, 16], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([64, 128, 16], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 16], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([64, 64, 16], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([64, 32, 16], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([32, 64, 16], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([32, 32, 16], 5, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([16, 32, 16], 5, [1, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([32, 16, 16], 5, [2, 1, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
data_type = [DataType.f64, DataType.f64, DataType.f64, DataType.f64]
|
||||
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints)
|
||||
#
|
||||
|
||||
#
|
||||
def GenerateSM80_TensorOp_884_complex(manifest, args):
|
||||
|
||||
if not CudaToolkitVersionSatisfies(args.cuda_version, 11, 0):
|
||||
return
|
||||
|
||||
layouts = [
|
||||
(LayoutType.ColumnMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.ColumnMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
]
|
||||
|
||||
math_inst = \
|
||||
MathInstruction( \
|
||||
[8, 8, 4], \
|
||||
DataType.f64, DataType.f64, DataType.f64, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_complex)
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
|
||||
alignment_constraints = [1,]
|
||||
|
||||
tile_descriptions = [
|
||||
TileDescription([128, 64, 8], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([64, 128, 8], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([64, 64, 8], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([64, 32, 8], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([32, 64, 8], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([32, 32, 8], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([16, 32, 8], 4, [1, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([32, 16, 8], 4, [2, 1, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
data_type = [DataType.cf64, DataType.cf64, DataType.cf64, DataType.cf64]
|
||||
|
||||
complex_transforms = [
|
||||
(ComplexTransform.none, ComplexTransform.none),
|
||||
(ComplexTransform.conj, ComplexTransform.none),
|
||||
(ComplexTransform.none, ComplexTransform.conj),
|
||||
(ComplexTransform.conj, ComplexTransform.conj)
|
||||
]
|
||||
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints, complex_transforms)
|
||||
|
||||
#
|
||||
def GenerateSM80_TensorOp_884_complex_gaussian(manifest, args):
|
||||
|
||||
if not CudaToolkitVersionSatisfies(args.cuda_version, 11, 0):
|
||||
return
|
||||
|
||||
layouts = [
|
||||
(LayoutType.ColumnMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.ColumnMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
]
|
||||
|
||||
math_inst = \
|
||||
MathInstruction( \
|
||||
[8, 8, 4], \
|
||||
DataType.f64, DataType.f64, DataType.f64, \
|
||||
OpcodeClass.TensorOp, \
|
||||
MathOperation.multiply_add_complex_gaussian)
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
|
||||
alignment_constraints = [1,]
|
||||
|
||||
tile_descriptions = [
|
||||
TileDescription([64, 64, 8], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([64, 32, 8], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([32, 64, 8], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([32, 32, 8], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([16, 32, 8], 4, [1, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([32, 16, 8], 4, [2, 1, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
data_type = [DataType.cf64, DataType.cf64, DataType.cf64, DataType.cf64]
|
||||
|
||||
complex_transforms = [
|
||||
(ComplexTransform.none, ComplexTransform.none),
|
||||
(ComplexTransform.conj, ComplexTransform.none),
|
||||
(ComplexTransform.none, ComplexTransform.conj),
|
||||
(ComplexTransform.conj, ComplexTransform.conj)
|
||||
]
|
||||
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints, complex_transforms)
|
||||
#
|
||||
|
||||
###################################################################################################
|
||||
|
||||
#
|
||||
def GenerateSM80_Simt(manifest, args):
|
||||
layouts = [
|
||||
(LayoutType.ColumnMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.ColumnMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
]
|
||||
|
||||
math_instructions = [
|
||||
MathInstruction( \
|
||||
[1, 1, 1], \
|
||||
DataType.f32, DataType.f32, DataType.f32, \
|
||||
OpcodeClass.Simt, \
|
||||
MathOperation.multiply_add),
|
||||
]
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
|
||||
alignment_constraints = [1,]
|
||||
|
||||
for math_inst in math_instructions:
|
||||
tile_descriptions = [
|
||||
TileDescription([256, 128, 8], 5, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 8], 5, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 8], 5, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 8], 4, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 8], 4, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 8], 4, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 8], 5, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 8], 5, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 8], 5, [2, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 32, 8], 5, [2, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 32, 128, 8], 5, [1, 2, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
data_type = [
|
||||
math_inst.element_a,
|
||||
math_inst.element_b,
|
||||
math_inst.element_accumulator,
|
||||
math_inst.element_accumulator,
|
||||
]
|
||||
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints)
|
||||
#
|
||||
|
||||
###################################################################################################
|
||||
|
||||
#
|
||||
def GenerateSM80(manifest, args):
|
||||
|
||||
GenerateSM80_TensorOp_16816(manifest, args)
|
||||
GenerateSM80_PlanarComplexTensorOp_16816(manifest, args)
|
||||
GenerateSM80_TensorOp_1688(manifest, args)
|
||||
GenerateSM80_TensorOp_1688_fast_math(manifest, args)
|
||||
GenerateSM80_TensorOp_1688_complex(manifest, args)
|
||||
GenerateSM80_TensorOp_884(manifest, args)
|
||||
GenerateSM80_TensorOp_884_complex(manifest, args)
|
||||
GenerateSM80_TensorOp_884_complex_gaussian(manifest, args)
|
||||
GenerateSM80_TensorOp_16832_TN(manifest, args)
|
||||
GenerateSM80_TensorOp_16832_Interleaved(manifest, args)
|
||||
GenerateSM80_TensorOp_16864_TN(manifest, args)
|
||||
GenerateSM80_TensorOp_16864_Interleaved(manifest, args)
|
||||
GenerateSM80_TensorOp_168256(manifest, args)
|
||||
GenerateSM80_Simt(manifest, args)
|
||||
#
|
||||
|
||||
###################################################################################################
|
||||
|
||||
if __name__ == "__main__":
|
||||
@@ -920,7 +1766,7 @@ if __name__ == "__main__":
|
||||
parser.add_argument("--build-dir", default=".", required=False, help="CUTLASS top-level build directory")
|
||||
parser.add_argument("--curr-build-dir", default=".", help="CUTLASS current build directory. cmake files will be emitted in this directory")
|
||||
parser.add_argument("--generator-target", default='library', help="Target of CUTLASS Library Generator.")
|
||||
parser.add_argument("--architectures", default='50;60;61;75', help="Target compute architectures")
|
||||
parser.add_argument("--architectures", default='53;60;61;70;75;80', help="Target compute architectures")
|
||||
parser.add_argument("--kernels", default='', help='Comma delimited list to filter kernels by name.')
|
||||
parser.add_argument("--cuda-version", default="11.0.0", help="Semantic version string of CUDA Toolkit")
|
||||
|
||||
@@ -933,6 +1779,8 @@ if __name__ == "__main__":
|
||||
GenerateSM61(manifest, args)
|
||||
GenerateSM70(manifest, args)
|
||||
GenerateSM75(manifest, args)
|
||||
GenerateSM80(manifest, args)
|
||||
|
||||
if 'library' in args.generator_target.split(','):
|
||||
manifest.emit(GeneratorTarget.Library)
|
||||
|
||||
|
||||
@@ -4,14 +4,32 @@
|
||||
# \brief Generates the CUTLASS Library's instances
|
||||
#
|
||||
|
||||
import enum
|
||||
import re
|
||||
|
||||
###################################################################################################
|
||||
|
||||
import enum
|
||||
|
||||
# The following block implements enum.auto() for Python 3.5 variants that don't include it such
|
||||
# as the default 3.5.2 on Ubuntu 16.04.
|
||||
#
|
||||
# https://codereview.stackexchange.com/questions/177309/reimplementing-pythons-enum-auto-for-compatibility
|
||||
|
||||
try:
|
||||
from enum import auto as enum_auto
|
||||
except ImportError:
|
||||
__cutlass_library_auto_enum = 0
|
||||
def enum_auto() -> int:
|
||||
global __cutlass_library_auto_enum
|
||||
i = __cutlass_library_auto_enum
|
||||
__cutlass_library_auto_enum += 1
|
||||
return i
|
||||
|
||||
###################################################################################################
|
||||
|
||||
#
|
||||
class GeneratorTarget(enum.Enum):
|
||||
Library = enum.auto()
|
||||
Library = enum_auto()
|
||||
#
|
||||
GeneratorTargetNames = {
|
||||
GeneratorTarget.Library: 'library'
|
||||
@@ -22,33 +40,37 @@ GeneratorTargetNames = {
|
||||
|
||||
#
|
||||
class DataType(enum.Enum):
|
||||
b1 = enum.auto()
|
||||
u4 = enum.auto()
|
||||
u8 = enum.auto()
|
||||
u16 = enum.auto()
|
||||
u32 = enum.auto()
|
||||
u64 = enum.auto()
|
||||
s4 = enum.auto()
|
||||
s8 = enum.auto()
|
||||
s16 = enum.auto()
|
||||
s32 = enum.auto()
|
||||
s64 = enum.auto()
|
||||
f16 = enum.auto()
|
||||
f32 = enum.auto()
|
||||
f64 = enum.auto()
|
||||
cf16 = enum.auto()
|
||||
cf32 = enum.auto()
|
||||
cf64 = enum.auto()
|
||||
cs4 = enum.auto()
|
||||
cs8 = enum.auto()
|
||||
cs16 = enum.auto()
|
||||
cs32 = enum.auto()
|
||||
cs64 = enum.auto()
|
||||
cu4 = enum.auto()
|
||||
cu8 = enum.auto()
|
||||
cu16 = enum.auto()
|
||||
cu32 = enum.auto()
|
||||
cu64 = enum.auto()
|
||||
b1 = enum_auto()
|
||||
u4 = enum_auto()
|
||||
u8 = enum_auto()
|
||||
u16 = enum_auto()
|
||||
u32 = enum_auto()
|
||||
u64 = enum_auto()
|
||||
s4 = enum_auto()
|
||||
s8 = enum_auto()
|
||||
s16 = enum_auto()
|
||||
s32 = enum_auto()
|
||||
s64 = enum_auto()
|
||||
f16 = enum_auto()
|
||||
bf16 = enum_auto()
|
||||
f32 = enum_auto()
|
||||
tf32 = enum_auto()
|
||||
f64 = enum_auto()
|
||||
cf16 = enum_auto()
|
||||
cbf16 = enum_auto()
|
||||
cf32 = enum_auto()
|
||||
ctf32 = enum_auto()
|
||||
cf64 = enum_auto()
|
||||
cs4 = enum_auto()
|
||||
cs8 = enum_auto()
|
||||
cs16 = enum_auto()
|
||||
cs32 = enum_auto()
|
||||
cs64 = enum_auto()
|
||||
cu4 = enum_auto()
|
||||
cu8 = enum_auto()
|
||||
cu16 = enum_auto()
|
||||
cu32 = enum_auto()
|
||||
cu64 = enum_auto()
|
||||
|
||||
#
|
||||
ShortDataTypeNames = {
|
||||
@@ -74,10 +96,14 @@ DataTypeNames = {
|
||||
DataType.s32: "s32",
|
||||
DataType.s64: "s64",
|
||||
DataType.f16: "f16",
|
||||
DataType.bf16: "bf16",
|
||||
DataType.f32: "f32",
|
||||
DataType.tf32: "tf32",
|
||||
DataType.f64: "f64",
|
||||
DataType.cf16: "cf16",
|
||||
DataType.cbf16: "cbf16",
|
||||
DataType.cf32: "cf32",
|
||||
DataType.ctf32: "ctf32",
|
||||
DataType.cf64: "cf64",
|
||||
DataType.cu4: "cu4",
|
||||
DataType.cu8: "cu8",
|
||||
@@ -104,10 +130,14 @@ DataTypeTag = {
|
||||
DataType.s32: "int32_t",
|
||||
DataType.s64: "int64_t",
|
||||
DataType.f16: "cutlass::half_t",
|
||||
DataType.bf16: "cutlass::bfloat16_t",
|
||||
DataType.f32: "float",
|
||||
DataType.tf32: "cutlass::tfloat32_t",
|
||||
DataType.f64: "double",
|
||||
DataType.cf16: "cutlass::complex<cutlass::half_t>",
|
||||
DataType.cbf16: "cutlass::complex<cutlass::bfloat16_t>",
|
||||
DataType.cf32: "cutlass::complex<float>",
|
||||
DataType.ctf32: "cutlass::complex<cutlass::tfloat32_t>",
|
||||
DataType.cf64: "cutlass::complex<double>",
|
||||
DataType.cu4: "cutlass::complex<cutlass::uint4b_t>",
|
||||
DataType.cu8: "cutlass::complex<cutlass::uint8_t>",
|
||||
@@ -134,10 +164,14 @@ DataTypeSize = {
|
||||
DataType.s32: 32,
|
||||
DataType.s64: 64,
|
||||
DataType.f16: 16,
|
||||
DataType.bf16: 16,
|
||||
DataType.f32: 32,
|
||||
DataType.tf32: 32,
|
||||
DataType.f64: 64,
|
||||
DataType.cf16: 32,
|
||||
DataType.cbf16: 32,
|
||||
DataType.cf32: 64,
|
||||
DataType.ctf32: 32,
|
||||
DataType.cf64: 128,
|
||||
DataType.cu4: 8,
|
||||
DataType.cu8: 16,
|
||||
@@ -155,8 +189,8 @@ DataTypeSize = {
|
||||
|
||||
#
|
||||
class ComplexTransform(enum.Enum):
|
||||
none = enum.auto()
|
||||
conj = enum.auto()
|
||||
none = enum_auto()
|
||||
conj = enum_auto()
|
||||
|
||||
#
|
||||
ComplexTransformTag = {
|
||||
@@ -194,40 +228,47 @@ def get_real_from_complex(complex_type):
|
||||
|
||||
#
|
||||
class ComplexMultiplyOp(enum.Enum):
|
||||
multiply_add = enum.auto()
|
||||
gaussian = enum.auto()
|
||||
multiply_add = enum_auto()
|
||||
gaussian = enum_auto()
|
||||
|
||||
###################################################################################################
|
||||
|
||||
#
|
||||
class MathOperation(enum.Enum):
|
||||
multiply_add = enum.auto()
|
||||
multiply_add_saturate = enum.auto()
|
||||
xor_popc = enum.auto()
|
||||
multiply_add_complex = enum.auto()
|
||||
multiply_add = enum_auto()
|
||||
multiply_add_saturate = enum_auto()
|
||||
xor_popc = enum_auto()
|
||||
multiply_add_fast_bf16 = enum_auto()
|
||||
multiply_add_fast_f16 = enum_auto()
|
||||
multiply_add_complex = enum_auto()
|
||||
multiply_add_complex_gaussian = enum_auto()
|
||||
|
||||
#
|
||||
MathOperationTag = {
|
||||
MathOperation.multiply_add: 'cutlass::arch::OpMultiplyAdd',
|
||||
MathOperation.multiply_add_saturate: 'cutlass::arch::OpMultiplyAddSaturate',
|
||||
MathOperation.xor_popc: 'cutlass::arch::OpXorPopc',
|
||||
MathOperation.multiply_add_fast_bf16: 'cutlass::arch::OpMultiplyAddFastBF16',
|
||||
MathOperation.multiply_add_fast_f16: 'cutlass::arch::OpMultiplyAddFastF16',
|
||||
MathOperation.multiply_add_complex: 'cutlass::arch::OpMultiplyAddComplex',
|
||||
MathOperation.multiply_add_complex_gaussian: 'cutlass::arch::OpMultiplyAddGaussianComplex',
|
||||
}
|
||||
|
||||
###################################################################################################
|
||||
|
||||
#
|
||||
class LayoutType(enum.Enum):
|
||||
ColumnMajor = enum.auto()
|
||||
RowMajor = enum.auto()
|
||||
ColumnMajorInterleaved32 = enum.auto()
|
||||
RowMajorInterleaved32 = enum.auto()
|
||||
ColumnMajorInterleaved64 = enum.auto()
|
||||
RowMajorInterleaved64 = enum.auto()
|
||||
TensorNHWC = enum.auto()
|
||||
TensorNCHW = enum.auto()
|
||||
TensorNGHWC = enum.auto()
|
||||
TensorNCxHW32 = enum.auto()
|
||||
TensorNCxHW64 = enum.auto()
|
||||
ColumnMajor = enum_auto()
|
||||
RowMajor = enum_auto()
|
||||
ColumnMajorInterleaved32 = enum_auto()
|
||||
RowMajorInterleaved32 = enum_auto()
|
||||
ColumnMajorInterleaved64 = enum_auto()
|
||||
RowMajorInterleaved64 = enum_auto()
|
||||
TensorNHWC = enum_auto()
|
||||
TensorNCHW = enum_auto()
|
||||
TensorNGHWC = enum_auto()
|
||||
TensorNCxHW32 = enum_auto()
|
||||
TensorNCxHW64 = enum_auto()
|
||||
|
||||
#
|
||||
LayoutTag = {
|
||||
@@ -282,9 +323,9 @@ ShortComplexLayoutNames = {
|
||||
|
||||
#
|
||||
class OpcodeClass(enum.Enum):
|
||||
Simt = enum.auto()
|
||||
TensorOp = enum.auto()
|
||||
WmmaTensorOp = enum.auto()
|
||||
Simt = enum_auto()
|
||||
TensorOp = enum_auto()
|
||||
WmmaTensorOp = enum_auto()
|
||||
|
||||
OpcodeClassNames = {
|
||||
OpcodeClass.Simt: 'simt',
|
||||
@@ -302,7 +343,7 @@ OpcodeClassTag = {
|
||||
|
||||
#
|
||||
class OperationKind(enum.Enum):
|
||||
Gemm = enum.auto()
|
||||
Gemm = enum_auto()
|
||||
#
|
||||
OperationKindNames = {
|
||||
OperationKind.Gemm: 'gemm'
|
||||
@@ -310,7 +351,7 @@ OperationKindNames = {
|
||||
|
||||
#
|
||||
class Target(enum.Enum):
|
||||
library = enum.auto()
|
||||
library = enum_auto()
|
||||
|
||||
ArchitectureNames = {
|
||||
50: 'maxwell',
|
||||
@@ -318,6 +359,7 @@ ArchitectureNames = {
|
||||
61: 'pascal',
|
||||
70: 'volta',
|
||||
75: 'turing',
|
||||
80: 'ampere',
|
||||
}
|
||||
|
||||
###################################################################################################
|
||||
@@ -340,27 +382,27 @@ def SubstituteTemplate(template, values):
|
||||
|
||||
#
|
||||
class GemmKind(enum.Enum):
|
||||
Gemm = enum.auto()
|
||||
Batched = enum.auto()
|
||||
Array = enum.auto()
|
||||
Universal = enum.auto()
|
||||
PlanarComplex = enum.auto()
|
||||
PlanarComplexArray = enum.auto()
|
||||
Gemm = enum_auto()
|
||||
Batched = enum_auto()
|
||||
Array = enum_auto()
|
||||
Universal = enum_auto()
|
||||
PlanarComplex = enum_auto()
|
||||
PlanarComplexArray = enum_auto()
|
||||
|
||||
#
|
||||
GemmKindNames = {
|
||||
GemmKind.Gemm: "gemm",
|
||||
GemmKind.Batched: "gemm_batched",
|
||||
GemmKind.Array: "gemm_array",
|
||||
GemmKind.Universal: "gemm_universal",
|
||||
GemmKind.Universal: "gemm",
|
||||
GemmKind.PlanarComplex: "gemm_planar_complex",
|
||||
GemmKind.PlanarComplexArray: "gemm_planar_complex_array",
|
||||
}
|
||||
|
||||
#
|
||||
class EpilogueFunctor(enum.Enum):
|
||||
LinearCombination = enum.auto()
|
||||
LinearCombinationClamp = enum.auto()
|
||||
LinearCombination = enum_auto()
|
||||
LinearCombinationClamp = enum_auto()
|
||||
|
||||
#
|
||||
EpilogueFunctorTag = {
|
||||
@@ -370,13 +412,17 @@ EpilogueFunctorTag = {
|
||||
|
||||
#
|
||||
class SwizzlingFunctor(enum.Enum):
|
||||
Cohort = enum.auto()
|
||||
Identity = enum.auto()
|
||||
Identity1 = enum_auto()
|
||||
Identity2 = enum_auto()
|
||||
Identity4 = enum_auto()
|
||||
Identity8 = enum_auto()
|
||||
|
||||
#
|
||||
SwizzlingFunctorTag = {
|
||||
SwizzlingFunctor.Cohort: 'cutlass::gemm::threadblock::GemmCohortThreadblockSwizzle<${layout_a}, ${layout_b}>',
|
||||
SwizzlingFunctor.Identity: 'cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle',
|
||||
SwizzlingFunctor.Identity1: 'cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<1>',
|
||||
SwizzlingFunctor.Identity2: 'cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<2>',
|
||||
SwizzlingFunctor.Identity4: 'cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<4>',
|
||||
SwizzlingFunctor.Identity8: 'cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<8>',
|
||||
}
|
||||
###################################################################################################
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ class Manifest:
|
||||
if args.kernels == 'all':
|
||||
self.kernel_names = []
|
||||
else:
|
||||
self.kernel_names = args.kernels.split(',')
|
||||
self.kernel_names = [x for x in args.kernels.split(',') if x != '']
|
||||
|
||||
self.operation_count = 0
|
||||
self.operations_by_name = {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -29,13 +29,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "cutlass/cutlass.h"
|
||||
#include "cutlass/gemm/kernel/default_gemm_planar_complex_universal.h"
|
||||
|
||||
#include "cutlass/gemm/device/gemm.h"
|
||||
#include "cutlass/gemm/device/gemm_complex.h"
|
||||
#include "cutlass/gemm/device/gemm_batched.h"
|
||||
#include "cutlass/gemm/device/gemm_array.h"
|
||||
#include "cutlass/gemm/device/gemm_universal_adapter.h"
|
||||
#include "cutlass/gemm/kernel/default_gemm_universal.h"
|
||||
#include "cutlass/gemm/kernel/default_gemm_planar_complex_universal.h"
|
||||
|
||||
#include "cutlass/library/library.h"
|
||||
#include "library_internal.h"
|
||||
@@ -104,10 +105,10 @@ public:
|
||||
MathOperationMap<typename Operator::Operator>::kId;
|
||||
|
||||
description_.tile_description.minimum_compute_capability =
|
||||
ArchMap<typename Operator::ArchTag>::kMin;
|
||||
ArchMap<typename Operator::ArchTag, typename Operator::OperatorClass>::kMin;
|
||||
|
||||
description_.tile_description.maximum_compute_capability =
|
||||
ArchMap<typename Operator::ArchTag>::kMax;
|
||||
ArchMap<typename Operator::ArchTag, typename Operator::OperatorClass>::kMax;
|
||||
|
||||
description_.A = make_TensorDescription<ElementA, LayoutA>(Operator::kAlignmentA);
|
||||
description_.B = make_TensorDescription<ElementB, LayoutB>(Operator::kAlignmentB);
|
||||
@@ -698,6 +699,201 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Operator_>
|
||||
class GemmUniversalOperation : public GemmOperationBase<Operator_> {
|
||||
public:
|
||||
|
||||
using Operator = Operator_;
|
||||
using ElementA = typename Operator::ElementA;
|
||||
using LayoutA = typename Operator::LayoutA;
|
||||
using ElementB = typename Operator::ElementB;
|
||||
using LayoutB = typename Operator::LayoutB;
|
||||
using ElementC = typename Operator::ElementC;
|
||||
using LayoutC = typename Operator::LayoutC;
|
||||
using ElementAccumulator = typename Operator::ElementAccumulator;
|
||||
using ElementCompute = typename Operator::EpilogueOutputOp::ElementCompute;
|
||||
|
||||
using OperatorArguments = typename Operator::Arguments;
|
||||
|
||||
public:
|
||||
|
||||
/// Constructor
|
||||
GemmUniversalOperation(char const *name = "unknown_gemm"):
|
||||
GemmOperationBase<Operator_>(name) {
|
||||
|
||||
this->description_.gemm_kind = GemmKind::kUniversal;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/// Constructs the arguments structure given the configuration and arguments
|
||||
static Status construct_arguments_(
|
||||
OperatorArguments &operator_args,
|
||||
GemmUniversalConfiguration const *configuration) {
|
||||
|
||||
operator_args.mode = configuration->mode;
|
||||
|
||||
operator_args.problem_size = configuration->problem_size;
|
||||
operator_args.batch_count = configuration->batch_count;
|
||||
|
||||
operator_args.lda = int(configuration->lda);
|
||||
operator_args.ldb = int(configuration->ldb);
|
||||
operator_args.ldc = int(configuration->ldc);
|
||||
operator_args.ldd = int(configuration->ldd);
|
||||
|
||||
return Status::kSuccess;
|
||||
}
|
||||
|
||||
/// Constructs the arguments structure given the configuration and arguments
|
||||
static Status update_arguments_(
|
||||
OperatorArguments &operator_args,
|
||||
GemmUniversalArguments const *arguments) {
|
||||
|
||||
if (arguments->pointer_mode == ScalarPointerMode::kHost) {
|
||||
typename Operator::EpilogueOutputOp::Params params(
|
||||
*static_cast<ElementCompute const *>(arguments->alpha),
|
||||
*static_cast<ElementCompute const *>(arguments->beta)
|
||||
);
|
||||
operator_args.epilogue = params;
|
||||
}
|
||||
else if (arguments->pointer_mode == ScalarPointerMode::kDevice){
|
||||
typename Operator::EpilogueOutputOp::Params params(
|
||||
static_cast<ElementCompute const *>(arguments->alpha),
|
||||
static_cast<ElementCompute const *>(arguments->beta)
|
||||
);
|
||||
operator_args.epilogue = params;
|
||||
}
|
||||
else {
|
||||
return Status::kErrorInvalidProblem;
|
||||
}
|
||||
|
||||
// update arguments
|
||||
operator_args.ptr_A = arguments->A;
|
||||
operator_args.ptr_B = arguments->B;
|
||||
operator_args.ptr_C = arguments->C;
|
||||
operator_args.ptr_D = arguments->D;
|
||||
|
||||
operator_args.batch_stride_A = arguments->batch_stride_A;
|
||||
operator_args.batch_stride_B = arguments->batch_stride_B;
|
||||
operator_args.batch_stride_C = arguments->batch_stride_C;
|
||||
operator_args.batch_stride_D = arguments->batch_stride_D;
|
||||
|
||||
return Status::kSuccess;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// Returns success if the operation can proceed
|
||||
virtual Status can_implement(
|
||||
void const *configuration_ptr,
|
||||
void const *arguments_ptr) const {
|
||||
|
||||
GemmUniversalConfiguration const *configuration =
|
||||
static_cast<GemmUniversalConfiguration const *>(configuration_ptr);
|
||||
|
||||
GemmUniversalArguments const *arguments =
|
||||
static_cast<GemmUniversalArguments const *>(arguments_ptr);
|
||||
|
||||
OperatorArguments args;
|
||||
|
||||
Status status = construct_arguments_(args, configuration);
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = update_arguments_(args, arguments);
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return Operator::can_implement(args);
|
||||
}
|
||||
|
||||
/// Gets the host-side workspace
|
||||
virtual uint64_t get_host_workspace_size(
|
||||
void const *configuration) const {
|
||||
|
||||
return sizeof(Operator);
|
||||
}
|
||||
|
||||
/// Gets the device-side workspace
|
||||
virtual uint64_t get_device_workspace_size(
|
||||
void const *configuration_ptr) const {
|
||||
|
||||
OperatorArguments args;
|
||||
|
||||
Status status = construct_arguments_(
|
||||
args,
|
||||
static_cast<GemmUniversalConfiguration const *>(configuration_ptr));
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t size = Operator::get_workspace_size(args);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/// Initializes the workspace
|
||||
virtual Status initialize(
|
||||
void const *configuration_ptr,
|
||||
void *host_workspace,
|
||||
void *device_workspace,
|
||||
cudaStream_t stream = nullptr) const {
|
||||
|
||||
OperatorArguments args;
|
||||
|
||||
Status status = construct_arguments_(
|
||||
args,
|
||||
static_cast<GemmUniversalConfiguration const *>(configuration_ptr));
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
Operator *op = new (host_workspace) Operator;
|
||||
|
||||
status = op->initialize(args, device_workspace, stream);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Runs the kernel
|
||||
virtual Status run(
|
||||
void const *arguments_ptr,
|
||||
void *host_workspace,
|
||||
void *device_workspace = nullptr,
|
||||
cudaStream_t stream = nullptr) const {
|
||||
|
||||
OperatorArguments args;
|
||||
|
||||
Status status = update_arguments_(
|
||||
args,
|
||||
static_cast<GemmUniversalArguments const *>(arguments_ptr));
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
Operator *op = static_cast<Operator *>(host_workspace);
|
||||
|
||||
status = op->update(args, device_workspace);
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = op->run(stream);
|
||||
|
||||
return status;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Operator_>
|
||||
|
||||
+206
-7
@@ -26,7 +26,7 @@
|
||||
/*! \file
|
||||
\brief CUTLASS Library handle.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <cstdint>
|
||||
|
||||
@@ -43,7 +43,8 @@ namespace library {
|
||||
Handle::Handle(
|
||||
cudaStream_t stream,
|
||||
size_t workspace_size
|
||||
):
|
||||
):
|
||||
provider_(Provider::kCUTLASS),
|
||||
stream_(stream),
|
||||
workspace_(nullptr),
|
||||
workspace_size_(0),
|
||||
@@ -95,6 +96,7 @@ Handle::Handle(Handle && handle) {
|
||||
/// Move assignment operator
|
||||
Handle & Handle::operator=(Handle && handle) {
|
||||
|
||||
provider_ = handle.provider_;
|
||||
device_ = handle.device_;
|
||||
workspace_size_ = handle.workspace_size_;
|
||||
workspace_ = handle.workspace_;
|
||||
@@ -121,6 +123,16 @@ cudaStream_t Handle::get_stream() const {
|
||||
return stream_;
|
||||
}
|
||||
|
||||
/// Gets the current provider
|
||||
Provider Handle::get_provider() const {
|
||||
return provider_;
|
||||
}
|
||||
|
||||
/// Sets the provider of operations
|
||||
void Handle::set_provider(Provider provider) {
|
||||
provider_ = provider;
|
||||
}
|
||||
|
||||
/// Gets the device workspace size
|
||||
size_t Handle::get_workspace_size() const {
|
||||
return workspace_size_;
|
||||
@@ -351,6 +363,8 @@ Status Handle::gemm(
|
||||
//
|
||||
|
||||
GemmFunctionalKey key(
|
||||
provider_,
|
||||
GemmKind::kGemm,
|
||||
element_compute,
|
||||
element_scalar,
|
||||
element_A,
|
||||
@@ -457,6 +471,188 @@ Status Handle::gemm(
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Executes a GEMM computation: D <= alpha * A*B + beta * C.
|
||||
//
|
||||
// Supports batched-strided, batched array or split-K serial or split-K parallel.
|
||||
//
|
||||
Status Handle::gemm_universal(
|
||||
|
||||
GemmUniversalMode mode, /// indicates the mode in which the kUniversal GEMM is launched
|
||||
|
||||
int M, /// GEMM M dimension
|
||||
int N, /// GEMM N dimension
|
||||
int K, /// GEMM K dimension
|
||||
|
||||
NumericTypeID element_compute, /// Data type of internal accumulation
|
||||
|
||||
NumericTypeID element_scalar, /// Data type of alpha/beta scalars
|
||||
|
||||
void const *alpha, /// Pointer to alpha scalar
|
||||
|
||||
NumericTypeID element_A, /// Data type of A matrix elements
|
||||
LayoutTypeID layout_A, /// Layout of A matrix
|
||||
ComplexTransform transform_A, /// Complex transformation applied to A matrix - ignored for real-valued matrices
|
||||
|
||||
void const * ptr_A, /// Pointer to A matrix in Global Memory
|
||||
int lda, /// Leading dimension of A matrix
|
||||
|
||||
NumericTypeID element_B, /// Data type of B matrix elements
|
||||
LayoutTypeID layout_B, /// Layout of B matrix
|
||||
ComplexTransform transform_B, /// Complex transformation applied to B matrix - ignored for real-valued matrices
|
||||
|
||||
void const * ptr_B, /// Pointer to B matrix in Global Memory
|
||||
int ldb, /// Leading dimension of B matrix
|
||||
|
||||
void const * beta, /// Pointer to beta scalar
|
||||
|
||||
NumericTypeID element_C, /// Data type of C and D matrices
|
||||
|
||||
void const * ptr_C, /// Pointer to C matrix
|
||||
int ldc, /// Leading dimension of C matrix
|
||||
|
||||
void * ptr_D, /// Pointer to D matrix
|
||||
int ldd, /// Leading dimension of D matrix
|
||||
|
||||
int batch_count, /// Batch count or number of split-K slices
|
||||
|
||||
int64_t batch_stride_A, /// Batch stride of A operand
|
||||
int64_t batch_stride_B, /// Batch stride of B operand
|
||||
int64_t batch_stride_C, /// Batch stride of C operand
|
||||
int64_t batch_stride_D /// Batch stride of D operand
|
||||
) {
|
||||
|
||||
//
|
||||
// Find the operation
|
||||
//
|
||||
|
||||
GemmFunctionalKey key(
|
||||
provider_,
|
||||
GemmKind::kUniversal,
|
||||
element_compute,
|
||||
element_scalar,
|
||||
element_A,
|
||||
layout_A,
|
||||
transform_A,
|
||||
element_B,
|
||||
layout_B,
|
||||
transform_B,
|
||||
element_C
|
||||
);
|
||||
|
||||
auto operators_it = Singleton::get().operation_table.gemm_operations.find(key);
|
||||
|
||||
if (operators_it == Singleton::get().operation_table.gemm_operations.end()) {
|
||||
return cutlass::Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
if (operators_it->second.empty()) {
|
||||
return cutlass::Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
//
|
||||
// Compute the largest alignment restriction the kernel can satisfy.
|
||||
//
|
||||
|
||||
// Maximum alignment expectation among all kernels (in units of bytes)
|
||||
int const kMaximumAlignmentSize = 16;
|
||||
|
||||
void const *ptr_A_check = ptr_A;
|
||||
void const *ptr_B_check = ptr_B;
|
||||
void const *ptr_C_check = ptr_C;
|
||||
void * ptr_D_check = ptr_D;
|
||||
|
||||
// Ignore alignment of pointers to pointers. We can't check this from the host,
|
||||
// as each batch index has its own pointer in device memory.
|
||||
if (mode == GemmUniversalMode::kArray) {
|
||||
ptr_A_check = nullptr;
|
||||
ptr_B_check = nullptr;
|
||||
ptr_C_check = nullptr;
|
||||
ptr_D_check = nullptr;
|
||||
}
|
||||
|
||||
int alignment = gemm_problem_alignment(
|
||||
M, N, K,
|
||||
element_A, ptr_A_check, lda, 0,
|
||||
element_B, ptr_B_check, ldb, 0,
|
||||
element_C, ptr_C_check, ldc, 0,
|
||||
ptr_D_check, ldd, 0, kMaximumAlignmentSize
|
||||
);
|
||||
|
||||
//
|
||||
// Find the best kernel in descending order of preference.
|
||||
//
|
||||
|
||||
GemmPreferenceKey preference_key(compute_capability(), alignment);
|
||||
|
||||
Operation const *operation = find_gemm_operation(operators_it, preference_key);
|
||||
|
||||
if (!operation) {
|
||||
return cutlass::Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
last_operation_ = operation;
|
||||
|
||||
//
|
||||
// Configure operation
|
||||
//
|
||||
|
||||
GemmUniversalConfiguration configuration{
|
||||
mode,
|
||||
{M, N, K},
|
||||
batch_count,
|
||||
lda,
|
||||
ldb,
|
||||
ldc,
|
||||
ldd
|
||||
};
|
||||
|
||||
// Query host work space size
|
||||
uint64_t host_workspace_size_needed = operation->get_host_workspace_size(&configuration);
|
||||
|
||||
if (uint64_t(kHostWorkspaceSize) < host_workspace_size_needed) {
|
||||
return cutlass::Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
char host_workspace[kHostWorkspaceSize];
|
||||
|
||||
// Query device workspace size
|
||||
uint64_t device_workspace_size_needed = operation->get_device_workspace_size(&configuration);
|
||||
|
||||
if (uint64_t(workspace_size_) < device_workspace_size_needed) {
|
||||
return cutlass::Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
// Initialize host and device workspaces
|
||||
Status status = operation->initialize(
|
||||
&configuration,
|
||||
host_workspace,
|
||||
workspace_,
|
||||
stream_);
|
||||
|
||||
if (status != cutlass::Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// Run the operator
|
||||
GemmUniversalArguments arguments{
|
||||
ptr_A,
|
||||
ptr_B,
|
||||
ptr_C,
|
||||
ptr_D,
|
||||
alpha,
|
||||
beta,
|
||||
scalar_pointer_mode_,
|
||||
batch_stride_A,
|
||||
batch_stride_B,
|
||||
batch_stride_C,
|
||||
batch_stride_D
|
||||
};
|
||||
|
||||
return operation->run(&arguments, host_workspace, workspace_, stream_);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Planar complex GEMM
|
||||
Status Handle::gemm_planar_complex(
|
||||
|
||||
@@ -522,6 +718,8 @@ Status Handle::gemm_planar_complex(
|
||||
//
|
||||
|
||||
GemmFunctionalKey key(
|
||||
provider_,
|
||||
GemmKind::kPlanarComplex,
|
||||
element_compute,
|
||||
element_scalar,
|
||||
element_A,
|
||||
@@ -533,9 +731,9 @@ Status Handle::gemm_planar_complex(
|
||||
element_C
|
||||
);
|
||||
|
||||
auto operators_it = Singleton::get().operation_table.gemm_planar_complex_operations.find(key);
|
||||
auto operators_it = Singleton::get().operation_table.gemm_operations.find(key);
|
||||
|
||||
if (operators_it == Singleton::get().operation_table.gemm_planar_complex_operations.end()) {
|
||||
if (operators_it == Singleton::get().operation_table.gemm_operations.end()) {
|
||||
return cutlass::Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
@@ -714,6 +912,8 @@ Status Handle::gemm_planar_complex_array(
|
||||
//
|
||||
|
||||
GemmFunctionalKey key(
|
||||
provider_,
|
||||
GemmKind::kPlanarComplexArray,
|
||||
element_compute,
|
||||
element_scalar,
|
||||
element_A,
|
||||
@@ -725,9 +925,9 @@ Status Handle::gemm_planar_complex_array(
|
||||
element_C
|
||||
);
|
||||
|
||||
auto operators_it = Singleton::get().operation_table.gemm_planar_complex_array_operations.find(key);
|
||||
auto operators_it = Singleton::get().operation_table.gemm_operations.find(key);
|
||||
|
||||
if (operators_it == Singleton::get().operation_table.gemm_planar_complex_array_operations.end()) {
|
||||
if (operators_it == Singleton::get().operation_table.gemm_operations.end()) {
|
||||
return cutlass::Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
@@ -837,7 +1037,6 @@ Status Handle::gemm_planar_complex_array(
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace library
|
||||
} // namespace cutlass
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -125,6 +125,14 @@ template <> struct NumericTypeMap<cutlass::complex<double> > {
|
||||
static NumericTypeID const kId = NumericTypeID::kCF64;
|
||||
};
|
||||
|
||||
template <> struct NumericTypeMap<cutlass::bfloat16_t> {
|
||||
static NumericTypeID const kId = NumericTypeID::kBF16;
|
||||
};
|
||||
|
||||
template <> struct NumericTypeMap<cutlass::tfloat32_t> {
|
||||
static NumericTypeID const kId = NumericTypeID::kTF32;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename T> struct MathOperationMap {
|
||||
@@ -143,6 +151,10 @@ template <> struct MathOperationMap<cutlass::arch::OpMultiplyAddComplex> {
|
||||
static MathOperationID const kId = MathOperationID::kMultiplyAddComplex;
|
||||
};
|
||||
|
||||
template <> struct MathOperationMap<cutlass::arch::OpMultiplyAddGaussianComplex> {
|
||||
static MathOperationID const kId = MathOperationID::kMultiplyAddGaussianComplex;
|
||||
};
|
||||
|
||||
template <> struct MathOperationMap<cutlass::arch::OpXorPopc> {
|
||||
static MathOperationID const kId = MathOperationID::kXorPopc;
|
||||
};
|
||||
@@ -217,33 +229,43 @@ template <> struct ComplexTransformMap<cutlass::ComplexTransform::kConjugate> {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename T> struct ArchMap;
|
||||
template <typename ArchTag, typename OperatorClass> struct ArchMap;
|
||||
|
||||
template <> struct ArchMap<arch::Sm50> {
|
||||
template <> struct ArchMap<arch::Sm50, arch::OpClassSimt> {
|
||||
static int const kMin = 50;
|
||||
static int const kMax = 1024;
|
||||
};
|
||||
|
||||
template <> struct ArchMap<arch::Sm60> {
|
||||
template <> struct ArchMap<arch::Sm60, arch::OpClassSimt> {
|
||||
static int const kMin = 60;
|
||||
static int const kMax = 1024;
|
||||
};
|
||||
|
||||
template <> struct ArchMap<arch::Sm61> {
|
||||
template <> struct ArchMap<arch::Sm61, arch::OpClassSimt> {
|
||||
static int const kMin = 61;
|
||||
static int const kMax = 1024;
|
||||
};
|
||||
|
||||
template <> struct ArchMap<arch::Sm70> {
|
||||
template <> struct ArchMap<arch::Sm70, arch::OpClassWmmaTensorOp> {
|
||||
static int const kMin = 70;
|
||||
static int const kMax = 1024;
|
||||
};
|
||||
|
||||
template <> struct ArchMap<arch::Sm70, arch::OpClassTensorOp> {
|
||||
static int const kMin = 70;
|
||||
static int const kMax = 75;
|
||||
};
|
||||
|
||||
template <> struct ArchMap<arch::Sm75> {
|
||||
template <typename OperatorClass> struct ArchMap<arch::Sm75, OperatorClass> {
|
||||
static int const kMin = 75;
|
||||
static int const kMax = 1024;
|
||||
};
|
||||
|
||||
template <typename OperatorClass> struct ArchMap<arch::Sm80, OperatorClass> {
|
||||
static int const kMin = 80;
|
||||
static int const kMax = 1024;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Element, typename Layout>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -37,11 +37,6 @@ namespace library {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// init and insert all cutlass op in manifest object (procedurally generated using generator.py)
|
||||
void initialize_all(Manifest &manifest);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Top-level initialization
|
||||
Status Manifest::initialize() {
|
||||
|
||||
@@ -49,13 +44,8 @@ Status Manifest::initialize() {
|
||||
operations_.clear();
|
||||
}
|
||||
|
||||
switch(provider_) {
|
||||
case Provider::kCUTLASS:
|
||||
initialize_all(*this); break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// initialize procedurally generated cutlass op in manifest object
|
||||
initialize_all(*this);
|
||||
|
||||
return Status::kSuccess;
|
||||
}
|
||||
|
||||
@@ -28,30 +28,7 @@
|
||||
instances may be queried.
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "cutlass/library/library.h"
|
||||
#include "cutlass/library/operation_table.h"
|
||||
#include "cutlass/library/util.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::ostream & operator<<(std::ostream &out, cutlass::library::GemmFunctionalKey const &k) {
|
||||
|
||||
out << "{\n"
|
||||
<< " element_compute: " << to_string(k.element_compute) << "\n"
|
||||
<< " element_scalar: " << to_string(k.element_scalar) << "\n"
|
||||
<< " element_A: " << to_string(k.element_A) << "\n"
|
||||
<< " layout_A: " << to_string(k.layout_A) << "\n"
|
||||
<< " transform_A: " << to_string(k.transform_A) << "\n"
|
||||
<< " element_B: " << to_string(k.element_B) << "\n"
|
||||
<< " layout_B: " << to_string(k.layout_B) << "\n"
|
||||
<< " transform_B: " << to_string(k.transform_B) << "\n"
|
||||
<< " element_C: " << to_string(k.element_C) << "\n"
|
||||
<< "}";
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -67,85 +44,38 @@ void OperationTable::append(Manifest const &manifest) {
|
||||
|
||||
OperationDescription const &desc = operation->description();
|
||||
|
||||
// insert all gemm operation into operation table
|
||||
if (desc.kind == OperationKind::kGemm) {
|
||||
GemmDescription const &gemm_desc = static_cast<GemmDescription const &>(desc);
|
||||
|
||||
if (gemm_desc.gemm_kind == GemmKind::kGemm) {
|
||||
|
||||
GemmFunctionalKey functional_key(
|
||||
gemm_desc.tile_description.math_instruction.element_accumulator,
|
||||
gemm_desc.element_epilogue,
|
||||
gemm_desc.A.element,
|
||||
gemm_desc.A.layout,
|
||||
gemm_desc.transform_A,
|
||||
gemm_desc.B.element,
|
||||
gemm_desc.B.layout,
|
||||
gemm_desc.transform_B,
|
||||
gemm_desc.C.element
|
||||
);
|
||||
GemmFunctionalKey functional_key(
|
||||
gemm_desc.provider,
|
||||
gemm_desc.gemm_kind,
|
||||
gemm_desc.tile_description.math_instruction.element_accumulator,
|
||||
gemm_desc.element_epilogue,
|
||||
gemm_desc.A.element,
|
||||
gemm_desc.A.layout,
|
||||
gemm_desc.transform_A,
|
||||
gemm_desc.B.element,
|
||||
gemm_desc.B.layout,
|
||||
gemm_desc.transform_B,
|
||||
gemm_desc.C.element
|
||||
);
|
||||
|
||||
Operation const *op = operation.get();
|
||||
Operation const *op = operation.get();
|
||||
|
||||
int cc = gemm_desc.tile_description.minimum_compute_capability;
|
||||
int cc = gemm_desc.tile_description.minimum_compute_capability;
|
||||
|
||||
int alignment = std::max(std::max(
|
||||
gemm_desc.A.alignment, gemm_desc.B.alignment), gemm_desc.C.alignment);
|
||||
int alignment = std::max(std::max(
|
||||
gemm_desc.A.alignment, gemm_desc.B.alignment), gemm_desc.C.alignment);
|
||||
|
||||
GemmPreferenceKey preference_key(cc, alignment);
|
||||
GemmPreferenceKey preference_key(cc, alignment);
|
||||
|
||||
gemm_operations[functional_key][preference_key].push_back(op);
|
||||
}
|
||||
else if (gemm_desc.gemm_kind == GemmKind::kPlanarComplex) {
|
||||
|
||||
GemmFunctionalKey functional_key(
|
||||
gemm_desc.tile_description.math_instruction.element_accumulator,
|
||||
gemm_desc.element_epilogue,
|
||||
gemm_desc.A.element,
|
||||
gemm_desc.A.layout,
|
||||
gemm_desc.transform_A,
|
||||
gemm_desc.B.element,
|
||||
gemm_desc.B.layout,
|
||||
gemm_desc.transform_B,
|
||||
gemm_desc.C.element
|
||||
);
|
||||
|
||||
Operation const *op = operation.get();
|
||||
|
||||
int cc = gemm_desc.tile_description.minimum_compute_capability;
|
||||
|
||||
int alignment = std::max(std::max(
|
||||
gemm_desc.A.alignment, gemm_desc.B.alignment), gemm_desc.C.alignment);
|
||||
|
||||
GemmPreferenceKey preference_key(cc, alignment);
|
||||
|
||||
gemm_planar_complex_operations[functional_key][preference_key].push_back(op);
|
||||
}
|
||||
else if (gemm_desc.gemm_kind == GemmKind::kPlanarComplexArray) {
|
||||
|
||||
GemmFunctionalKey functional_key(
|
||||
gemm_desc.tile_description.math_instruction.element_accumulator,
|
||||
gemm_desc.element_epilogue,
|
||||
gemm_desc.A.element,
|
||||
gemm_desc.A.layout,
|
||||
gemm_desc.transform_A,
|
||||
gemm_desc.B.element,
|
||||
gemm_desc.B.layout,
|
||||
gemm_desc.transform_B,
|
||||
gemm_desc.C.element
|
||||
);
|
||||
|
||||
Operation const *op = operation.get();
|
||||
|
||||
int cc = gemm_desc.tile_description.minimum_compute_capability;
|
||||
|
||||
int alignment = std::max(std::max(
|
||||
gemm_desc.A.alignment, gemm_desc.B.alignment), gemm_desc.C.alignment);
|
||||
|
||||
GemmPreferenceKey preference_key(cc, alignment);
|
||||
|
||||
gemm_planar_complex_array_operations[functional_key][preference_key].push_back(op);
|
||||
}
|
||||
gemm_operations[functional_key][preference_key].push_back(op);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+203
-1
@@ -45,6 +45,7 @@ static struct {
|
||||
Provider enumerant;
|
||||
}
|
||||
Provider_enumerants[] = {
|
||||
{"none", "None", Provider::kNone},
|
||||
{"cutlass", "CUTLASS", Provider::kCUTLASS},
|
||||
{"host", "reference_host", Provider::kReferenceHost},
|
||||
{"device", "reference_device", Provider::kReferenceDevice},
|
||||
@@ -83,6 +84,38 @@ Provider from_string<Provider>(std::string const &str) {
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static struct {
|
||||
char const *text;
|
||||
char const *pretty;
|
||||
GemmKind enumerant;
|
||||
}
|
||||
GemmKind_enumerants[] = {
|
||||
{"gemm", "<Gemm>", GemmKind::kGemm},
|
||||
{"batched", "<Batched>", GemmKind::kBatched},
|
||||
{"array", "<Array>", GemmKind::kArray},
|
||||
{"universal", "<Universal>", GemmKind::kUniversal},
|
||||
{"planar_complex", "<PlanarComplex>", GemmKind::kPlanarComplex},
|
||||
{"planar_complex_array", "<PlanarComplexArray>", GemmKind::kPlanarComplexArray},
|
||||
};
|
||||
|
||||
/// Converts a ConvKind enumerant to a string
|
||||
char const *to_string(GemmKind type, bool pretty) {
|
||||
|
||||
for (auto const & possible : GemmKind_enumerants) {
|
||||
if (type == possible.enumerant) {
|
||||
if (pretty) {
|
||||
return possible.pretty;
|
||||
}
|
||||
else {
|
||||
return possible.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pretty ? "Invalid" : "invalid";
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -92,6 +125,7 @@ static struct {
|
||||
OperationKind enumerant;
|
||||
}
|
||||
OperationKind_enumerants[] = {
|
||||
{"eq_gemm", "EqGemm", OperationKind::kEqGemm},
|
||||
{"gemm", "Gemm", OperationKind::kGemm},
|
||||
};
|
||||
|
||||
@@ -194,10 +228,14 @@ NumericTypeID_enumerants[] = {
|
||||
{"s32", "S32", NumericTypeID::kS32},
|
||||
{"s64", "S64", NumericTypeID::kS64},
|
||||
{"f16", "F16", NumericTypeID::kF16},
|
||||
{"bf16", "BF16", NumericTypeID::kBF16},
|
||||
{"f32", "F32", NumericTypeID::kF32},
|
||||
{"tf32", "TF32", NumericTypeID::kTF32},
|
||||
{"f64", "F64", NumericTypeID::kF64},
|
||||
{"cf16", "CF16", NumericTypeID::kCF16},
|
||||
{"cbf16", "CBF16", NumericTypeID::kCBF16},
|
||||
{"cf32", "CF32", NumericTypeID::kCF32},
|
||||
{"ctf32", "CTF32", NumericTypeID::kCTF32},
|
||||
{"cf64", "CF64", NumericTypeID::kCF64},
|
||||
{"cu4", "CU4", NumericTypeID::kCU4},
|
||||
{"cu8", "CU8", NumericTypeID::kCU8},
|
||||
@@ -249,10 +287,14 @@ NumericTypeID from_string<NumericTypeID>(std::string const &str) {
|
||||
int sizeof_bits(NumericTypeID type) {
|
||||
switch (type) {
|
||||
case NumericTypeID::kF16: return 16;
|
||||
case NumericTypeID::kBF16: return 16;
|
||||
case NumericTypeID::kTF32: return 32;
|
||||
case NumericTypeID::kF32: return 32;
|
||||
case NumericTypeID::kF64: return 64;
|
||||
case NumericTypeID::kCF16: return 32;
|
||||
case NumericTypeID::kCBF16: return 32;
|
||||
case NumericTypeID::kCF32: return 64;
|
||||
case NumericTypeID::kCTF32: return 64;
|
||||
case NumericTypeID::kCF64: return 128;
|
||||
case NumericTypeID::kS4: return 4;
|
||||
case NumericTypeID::kS8: return 8;
|
||||
@@ -276,6 +318,8 @@ bool is_complex_type(NumericTypeID type) {
|
||||
case NumericTypeID::kCF16: return true;
|
||||
case NumericTypeID::kCF32: return true;
|
||||
case NumericTypeID::kCF64: return true;
|
||||
case NumericTypeID::kCBF16: return true;
|
||||
case NumericTypeID::kCTF32: return true;
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
@@ -287,6 +331,8 @@ NumericTypeID get_real_type(NumericTypeID type) {
|
||||
case NumericTypeID::kCF16: return NumericTypeID::kF16;
|
||||
case NumericTypeID::kCF32: return NumericTypeID::kF32;
|
||||
case NumericTypeID::kCF64: return NumericTypeID::kF64;
|
||||
case NumericTypeID::kCBF16: return NumericTypeID::kBF16;
|
||||
case NumericTypeID::kCTF32: return NumericTypeID::kTF32;
|
||||
default: break;
|
||||
}
|
||||
return type;
|
||||
@@ -314,6 +360,8 @@ bool is_integer_type(NumericTypeID type) {
|
||||
bool is_signed_type(NumericTypeID type) {
|
||||
switch (type) {
|
||||
case NumericTypeID::kF16: return true;
|
||||
case NumericTypeID::kBF16: return true;
|
||||
case NumericTypeID::kTF32: return true;
|
||||
case NumericTypeID::kF32: return true;
|
||||
case NumericTypeID::kF64: return true;
|
||||
case NumericTypeID::kS4: return true;
|
||||
@@ -340,9 +388,13 @@ bool is_unsigned_integer(NumericTypeID type) {
|
||||
bool is_float_type(NumericTypeID type) {
|
||||
switch (type) {
|
||||
case NumericTypeID::kF16: return true;
|
||||
case NumericTypeID::kBF16: return true;
|
||||
case NumericTypeID::kTF32: return true;
|
||||
case NumericTypeID::kF32: return true;
|
||||
case NumericTypeID::kF64: return true;
|
||||
case NumericTypeID::kCF16: return true;
|
||||
case NumericTypeID::kCBF16: return true;
|
||||
case NumericTypeID::kCTF32: return true;
|
||||
case NumericTypeID::kCF32: return true;
|
||||
case NumericTypeID::kCF64: return true;
|
||||
default: break;
|
||||
@@ -431,7 +483,7 @@ OpcodeClassID_enumerants[] = {
|
||||
{"simt", "<simt>", OpcodeClassID::kSimt},
|
||||
{"tensorop", "<tensorop>", OpcodeClassID::kTensorOp},
|
||||
{"wmmatensorop", "<wmmatensorop>", OpcodeClassID::kWmmaTensorOp},
|
||||
{"wmma", "<wmma>", OpcodeClassID::kWmmaTensorOp}
|
||||
{"wmma", "<wmma>", OpcodeClassID::kWmmaTensorOp},
|
||||
};
|
||||
|
||||
/// Converts a OpcodeClassID enumerant to a string
|
||||
@@ -509,6 +561,47 @@ ComplexTransform from_string<ComplexTransform>(std::string const &str) {
|
||||
}
|
||||
|
||||
|
||||
static struct {
|
||||
char const *text;
|
||||
char const *pretty;
|
||||
SplitKMode enumerant;
|
||||
}
|
||||
SplitKMode_enumerants[] = {
|
||||
{"serial", "<serial>", SplitKMode::kSerial},
|
||||
{"parallel", "<parallel>", SplitKMode::kParallel},
|
||||
};
|
||||
|
||||
/// Converts a SplitKMode enumerant to a string
|
||||
char const *to_string(SplitKMode type, bool pretty) {
|
||||
|
||||
for (auto const & possible : SplitKMode_enumerants) {
|
||||
if (type == possible.enumerant) {
|
||||
if (pretty) {
|
||||
return possible.pretty;
|
||||
}
|
||||
else {
|
||||
return possible.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pretty ? "Invalid" : "invalid";
|
||||
}
|
||||
|
||||
/// Converts a SplitKMode enumerant from a string
|
||||
template <>
|
||||
SplitKMode from_string<SplitKMode>(std::string const &str) {
|
||||
|
||||
for (auto const & possible : SplitKMode_enumerants) {
|
||||
if ((str.compare(possible.text) == 0) ||
|
||||
(str.compare(possible.pretty) == 0)) {
|
||||
return possible.enumerant;
|
||||
}
|
||||
}
|
||||
|
||||
return SplitKMode::kInvalid;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Lexical cast a string to a byte array. Returns true if cast is successful or false if invalid.
|
||||
bool lexical_cast(std::vector<uint8_t> &bytes, NumericTypeID type, std::string const &str) {
|
||||
@@ -570,6 +663,20 @@ bool lexical_cast(std::vector<uint8_t> &bytes, NumericTypeID type, std::string c
|
||||
*reinterpret_cast<half_t *>(bytes.data()) = static_cast<half_t>(tmp);
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kBF16:
|
||||
{
|
||||
float tmp;
|
||||
ss >> tmp;
|
||||
*reinterpret_cast<bfloat16_t *>(bytes.data()) = static_cast<bfloat16_t>(tmp);
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kTF32:
|
||||
{
|
||||
float tmp;
|
||||
ss >> tmp;
|
||||
*reinterpret_cast<tfloat32_t *>(bytes.data()) = static_cast<tfloat32_t>(tmp);
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kF32:
|
||||
{
|
||||
ss >> *reinterpret_cast<float *>(bytes.data());
|
||||
@@ -589,11 +696,29 @@ bool lexical_cast(std::vector<uint8_t> &bytes, NumericTypeID type, std::string c
|
||||
x->imag() = static_cast<half_t>(std::imag(tmp));
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kCBF16:
|
||||
{
|
||||
std::complex<float> tmp;
|
||||
ss >> tmp;
|
||||
cutlass::complex<cutlass::bfloat16_t> *x = reinterpret_cast<cutlass::complex<bfloat16_t> *>(bytes.data());
|
||||
x->real() = static_cast<bfloat16_t>(std::real(tmp));
|
||||
x->imag() = static_cast<bfloat16_t>(std::imag(tmp));
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kCF32:
|
||||
{
|
||||
ss >> *reinterpret_cast<std::complex<float>*>(bytes.data());
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kCTF32:
|
||||
{
|
||||
std::complex<float> tmp;
|
||||
ss >> tmp;
|
||||
cutlass::complex<cutlass::tfloat32_t> *x = reinterpret_cast<cutlass::complex<tfloat32_t> *>(bytes.data());
|
||||
x->real() = static_cast<tfloat32_t>(std::real(tmp));
|
||||
x->imag() = static_cast<tfloat32_t>(std::imag(tmp));
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kCF64:
|
||||
{
|
||||
ss >> *reinterpret_cast<std::complex<double>*>(bytes.data());
|
||||
@@ -674,6 +799,18 @@ std::string lexical_cast(std::vector<uint8_t> &bytes, NumericTypeID type) {
|
||||
ss << tmp;
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kBF16:
|
||||
{
|
||||
float tmp = *reinterpret_cast<bfloat16_t *>(bytes.data());;
|
||||
ss << tmp;
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kTF32:
|
||||
{
|
||||
float tmp = *reinterpret_cast<tfloat32_t *>(bytes.data());;
|
||||
ss << tmp;
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kF32:
|
||||
{
|
||||
ss << *reinterpret_cast<float *>(bytes.data());
|
||||
@@ -696,6 +833,18 @@ std::string lexical_cast(std::vector<uint8_t> &bytes, NumericTypeID type) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kCBF16:
|
||||
{
|
||||
cutlass::complex<bfloat16_t> const *x =
|
||||
reinterpret_cast<cutlass::complex<bfloat16_t> const *>(bytes.data());
|
||||
|
||||
ss << float(x->real());
|
||||
|
||||
if (x->imag() != cutlass::bfloat16_t()) {
|
||||
ss << "+i" << float(x->imag());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kCF32:
|
||||
{
|
||||
cutlass::complex<float> const * x = reinterpret_cast<cutlass::complex<float> const *>(bytes.data());
|
||||
@@ -707,6 +856,17 @@ std::string lexical_cast(std::vector<uint8_t> &bytes, NumericTypeID type) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kCTF32:
|
||||
{
|
||||
cutlass::complex<tfloat32_t> const * x = reinterpret_cast<cutlass::complex<tfloat32_t> const *>(bytes.data());
|
||||
|
||||
ss << float(x->real());
|
||||
|
||||
if (x->imag() != tfloat32_t()) {
|
||||
ss << "+i" << float(x->imag());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kCF64:
|
||||
{
|
||||
cutlass::complex<double> const * x = reinterpret_cast<cutlass::complex<double> const *>(bytes.data());
|
||||
@@ -780,6 +940,16 @@ bool cast_from_int64(std::vector<uint8_t> &bytes, NumericTypeID type, int64_t sr
|
||||
*reinterpret_cast<half_t *>(bytes.data()) = static_cast<half_t>(float(src));
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kBF16:
|
||||
{
|
||||
*reinterpret_cast<bfloat16_t *>(bytes.data()) = static_cast<bfloat16_t>(float(src));
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kTF32:
|
||||
{
|
||||
*reinterpret_cast<tfloat32_t *>(bytes.data()) = static_cast<tfloat32_t>(float(src));
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kF32:
|
||||
{
|
||||
*reinterpret_cast<float *>(bytes.data()) = static_cast<float>(src);
|
||||
@@ -870,6 +1040,16 @@ bool cast_from_uint64(std::vector<uint8_t> &bytes, NumericTypeID type, uint64_t
|
||||
*reinterpret_cast<half_t *>(bytes.data()) = static_cast<half_t>(float(src));
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kBF16:
|
||||
{
|
||||
*reinterpret_cast<bfloat16_t *>(bytes.data()) = static_cast<bfloat16_t>(float(src));
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kTF32:
|
||||
{
|
||||
*reinterpret_cast<tfloat32_t *>(bytes.data()) = static_cast<tfloat32_t>(float(src));
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kF32:
|
||||
{
|
||||
*reinterpret_cast<float *>(bytes.data()) = static_cast<float>(src);
|
||||
@@ -961,6 +1141,16 @@ bool cast_from_double(std::vector<uint8_t> &bytes, NumericTypeID type, double sr
|
||||
*reinterpret_cast<half_t *>(bytes.data()) = static_cast<half_t>(float(src));
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kBF16:
|
||||
{
|
||||
*reinterpret_cast<bfloat16_t *>(bytes.data()) = static_cast<bfloat16_t>(float(src));
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kTF32:
|
||||
{
|
||||
*reinterpret_cast<tfloat32_t *>(bytes.data()) = static_cast<tfloat32_t>(float(src));
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kF32:
|
||||
{
|
||||
*reinterpret_cast<float *>(bytes.data()) = static_cast<float>(src);
|
||||
@@ -978,11 +1168,23 @@ bool cast_from_double(std::vector<uint8_t> &bytes, NumericTypeID type, double sr
|
||||
x->imag() = static_cast<half_t>(float(0));
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kCBF16:
|
||||
{
|
||||
cutlass::complex<cutlass::bfloat16_t> *x = reinterpret_cast<cutlass::complex<bfloat16_t> *>(bytes.data());
|
||||
x->real() = static_cast<bfloat16_t>(bfloat16_t(src));
|
||||
x->imag() = static_cast<bfloat16_t>(bfloat16_t(0));
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kCF32:
|
||||
{
|
||||
*reinterpret_cast<std::complex<float>*>(bytes.data()) = std::complex<float>(float(src), float(0));
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kCTF32:
|
||||
{
|
||||
*reinterpret_cast<std::complex<tfloat32_t>*>(bytes.data()) = std::complex<tfloat32_t>(tfloat32_t(src), tfloat32_t(0));
|
||||
}
|
||||
break;
|
||||
case NumericTypeID::kCF64:
|
||||
{
|
||||
*reinterpret_cast<std::complex<double>*>(bytes.data()) = std::complex<double>(src, double(0));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
# Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -52,15 +52,35 @@ Status get_cutlass_status(cublasStatus_t cublas) {
|
||||
}
|
||||
|
||||
/// Maps a CUTLASS tensor layout to a cuBLAS transpose operation
|
||||
cublasOperation_t get_cublas_transpose_operation(library::LayoutTypeID layout) {
|
||||
bool get_cublas_transpose_operation(
|
||||
cublasOperation_t &operation,
|
||||
library::LayoutTypeID layout,
|
||||
library::ComplexTransform transform) {
|
||||
|
||||
switch (layout) {
|
||||
case library::LayoutTypeID::kColumnMajor:
|
||||
return CUBLAS_OP_N;
|
||||
if (transform == library::ComplexTransform::kNone) {
|
||||
operation = CUBLAS_OP_N;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case library::LayoutTypeID::kRowMajor:
|
||||
return CUBLAS_OP_T;
|
||||
if (transform == library::ComplexTransform::kNone) {
|
||||
operation = CUBLAS_OP_T;
|
||||
return true;
|
||||
}
|
||||
else if (transform == library::ComplexTransform::kConjugate) {
|
||||
operation = CUBLAS_OP_C;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
throw std::runtime_error("CUTLASS layout type does not correspond to cublas type");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Maps a CUTLASS numeric type to a cuBLAS data type enumeration
|
||||
@@ -114,6 +134,14 @@ bool get_cublas_datatype(cublasDataType_t &data_type, library::NumericTypeID ele
|
||||
|
||||
case library::NumericTypeID::kB1:
|
||||
break;
|
||||
|
||||
case library::NumericTypeID::kCF32:
|
||||
data_type = CUDA_C_32F;
|
||||
return true;
|
||||
|
||||
case library::NumericTypeID::kCF64:
|
||||
data_type = CUDA_C_64F;
|
||||
return true;
|
||||
|
||||
case library::NumericTypeID::kInvalid:
|
||||
|
||||
@@ -157,6 +185,104 @@ Status cublas_satisfies(library::GemmDescription const &desc) {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace detail {
|
||||
|
||||
cublasGemmExDispatcher::cublasGemmExDispatcher(
|
||||
library::GemmDescription const &op_desc,
|
||||
library::GemmUniversalConfiguration configuration_,
|
||||
library::GemmUniversalArguments arguments_,
|
||||
cublasGemmAlgo_t algorithm
|
||||
):
|
||||
configuration(configuration_), arguments(arguments_), algo(algorithm), status(Status::kSuccess) {
|
||||
|
||||
bool good = true;
|
||||
|
||||
good = (good && get_cublas_transpose_operation(trans_A, op_desc.A.layout, op_desc.transform_A));
|
||||
good = (good && get_cublas_transpose_operation(trans_B, op_desc.B.layout, op_desc.transform_B));
|
||||
good = (good && get_cublas_datatype(data_type_A, op_desc.A.element));
|
||||
good = (good && get_cublas_datatype(data_type_B, op_desc.B.element));
|
||||
good = (good && get_cublas_datatype(data_type_C, op_desc.C.element));
|
||||
|
||||
good = (good && get_cublas_datatype(
|
||||
compute_data_type,
|
||||
op_desc.tile_description.math_instruction.element_accumulator));
|
||||
|
||||
// cuBLAS introduces a separate cublasComputeType enumerant to more precisely describe
|
||||
// internal numerical data types used in the computation.
|
||||
#if (__CUDA_VER_MAJOR__ >= 11)
|
||||
library::OpcodeClassID const & opcode_class =
|
||||
op_desc.tile_description.math_instruction.opcode_class;
|
||||
|
||||
if (good &&
|
||||
op_desc.A.element == library::NumericTypeID::kF32 &&
|
||||
op_desc.B.element == library::NumericTypeID::kF32 &&
|
||||
opcode_class == library::OpcodeClassID::kTensorOp) {
|
||||
|
||||
compute_type = CUBLAS_COMPUTE_32F_FAST_TF32;
|
||||
}
|
||||
else if (good) {
|
||||
bool const isPedantic = false;
|
||||
switch (compute_data_type) {
|
||||
case CUDA_R_32F:
|
||||
case CUDA_C_32F:
|
||||
compute_type = isPedantic ? CUBLAS_COMPUTE_32F_PEDANTIC : CUBLAS_COMPUTE_32F;
|
||||
break;
|
||||
case CUDA_R_64F:
|
||||
case CUDA_C_64F:
|
||||
compute_type = isPedantic ? CUBLAS_COMPUTE_64F_PEDANTIC : CUBLAS_COMPUTE_64F;
|
||||
break;
|
||||
case CUDA_R_16F:
|
||||
compute_type = isPedantic ? CUBLAS_COMPUTE_16F_PEDANTIC : CUBLAS_COMPUTE_16F;
|
||||
break;
|
||||
case CUDA_R_32I:
|
||||
compute_type = isPedantic ? CUBLAS_COMPUTE_32I_PEDANTIC : CUBLAS_COMPUTE_32I;
|
||||
break;
|
||||
default:
|
||||
good = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // __CUDA_VER_MAJOR__ >= 11
|
||||
|
||||
if (!good) {
|
||||
status = Status::kErrorNotSupported;
|
||||
}
|
||||
}
|
||||
|
||||
/// Executes GEMM using these arguments
|
||||
cublasStatus_t cublasGemmExDispatcher::operator()(cublasHandle_t handle) {
|
||||
|
||||
return cublasGemmEx(
|
||||
handle,
|
||||
trans_A,
|
||||
trans_B,
|
||||
configuration.problem_size.m(),
|
||||
configuration.problem_size.n(),
|
||||
configuration.problem_size.k(),
|
||||
arguments.alpha,
|
||||
arguments.A,
|
||||
data_type_A,
|
||||
int(configuration.lda),
|
||||
arguments.B,
|
||||
data_type_B,
|
||||
int(configuration.ldb),
|
||||
arguments.beta,
|
||||
arguments.D,
|
||||
data_type_C,
|
||||
int(configuration.ldc),
|
||||
#if (__CUDA_VER_MAJOR__ >= 11)
|
||||
compute_type,
|
||||
#else
|
||||
compute_data_type,
|
||||
#endif
|
||||
algo
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
} // namespace detail
|
||||
|
||||
} // namespace profiler
|
||||
} // namespace cutlass
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -33,7 +33,10 @@
|
||||
|
||||
#include "cutlass/cutlass.h"
|
||||
#include "cutlass/library/library.h"
|
||||
#include "cutlass/library/util.h"
|
||||
|
||||
#include "options.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace cutlass {
|
||||
@@ -45,7 +48,10 @@ namespace profiler {
|
||||
Status get_cutlass_status(cublasStatus_t cublas);
|
||||
|
||||
/// Maps a CUTLASS tensor layout to a cuBLAS transpose operation
|
||||
cublasOperation_t get_cublas_transpose_operation(library::LayoutTypeID layout);
|
||||
bool get_cublas_transpose_operation(
|
||||
cublasOperation_t &operation,
|
||||
library::LayoutTypeID layout,
|
||||
library::ComplexTransform transform = library::ComplexTransform::kNone);
|
||||
|
||||
/// Maps a CUTLASS numeric type to a cuBLAS data type enumeration
|
||||
bool get_cublas_datatype(cublasDataType_t &data_type, library::NumericTypeID element_type);
|
||||
@@ -168,8 +174,8 @@ struct cublasGemmExDispatcher {
|
||||
//
|
||||
// Data members
|
||||
//
|
||||
library::GemmConfiguration configuration;
|
||||
library::GemmArguments arguments;
|
||||
library::GemmUniversalConfiguration configuration;
|
||||
library::GemmUniversalArguments arguments;
|
||||
|
||||
// cublass-specific data structures to fill cublas API call arguments
|
||||
cublasOperation_t trans_A;
|
||||
@@ -177,7 +183,12 @@ struct cublasGemmExDispatcher {
|
||||
cudaDataType_t data_type_A;
|
||||
cudaDataType_t data_type_B;
|
||||
cudaDataType_t data_type_C;
|
||||
cudaDataType_t compute_type;
|
||||
cudaDataType_t compute_data_type;
|
||||
|
||||
#if (__CUDA_VER_MAJOR__ >= 11)
|
||||
cublasComputeType_t compute_type;
|
||||
#endif
|
||||
|
||||
cublasGemmAlgo_t algo;
|
||||
Status status;
|
||||
|
||||
@@ -187,54 +198,13 @@ struct cublasGemmExDispatcher {
|
||||
|
||||
cublasGemmExDispatcher(
|
||||
library::GemmDescription const &op_desc,
|
||||
library::GemmConfiguration configuration_,
|
||||
library::GemmArguments arguments_,
|
||||
library::GemmUniversalConfiguration configuration_,
|
||||
library::GemmUniversalArguments arguments_,
|
||||
cublasGemmAlgo_t algorithm = CUBLAS_GEMM_DFALT
|
||||
):
|
||||
configuration(configuration_), arguments(arguments_), algo(algorithm), status(Status::kSuccess) {
|
||||
|
||||
trans_A = get_cublas_transpose_operation(op_desc.A.layout);
|
||||
trans_B = get_cublas_transpose_operation(op_desc.B.layout);
|
||||
|
||||
bool good = true;
|
||||
good = (good && get_cublas_datatype(data_type_A, op_desc.A.element));
|
||||
good = (good && get_cublas_datatype(data_type_B, op_desc.B.element));
|
||||
good = (good && get_cublas_datatype(data_type_C, op_desc.C.element));
|
||||
|
||||
good = (good && get_cublas_datatype(
|
||||
compute_type,
|
||||
op_desc.tile_description.math_instruction.element_accumulator));
|
||||
|
||||
if (!good) {
|
||||
status = Status::kErrorNotSupported;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/// Executes GEMM using these arguments
|
||||
cublasStatus_t operator()(cublasHandle_t handle) {
|
||||
|
||||
return cublasGemmEx(
|
||||
handle,
|
||||
trans_A,
|
||||
trans_B,
|
||||
configuration.problem_size.m(),
|
||||
configuration.problem_size.n(),
|
||||
configuration.problem_size.k(),
|
||||
arguments.alpha,
|
||||
arguments.A,
|
||||
data_type_A,
|
||||
int(configuration.lda),
|
||||
arguments.B,
|
||||
data_type_B,
|
||||
int(configuration.ldb),
|
||||
arguments.beta,
|
||||
arguments.D,
|
||||
data_type_C,
|
||||
int(configuration.ldc),
|
||||
compute_type,
|
||||
algo
|
||||
);
|
||||
}
|
||||
cublasStatus_t operator()(cublasHandle_t handle);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -44,7 +44,7 @@ CutlassProfiler::CutlassProfiler(
|
||||
):
|
||||
options_(options) {
|
||||
|
||||
operation_profilers_.emplace_back(new GemmOperationProfiler);
|
||||
operation_profilers_.emplace_back(new GemmOperationProfiler(options));
|
||||
|
||||
}
|
||||
|
||||
@@ -108,13 +108,6 @@ void CutlassProfiler::enumerate_() {
|
||||
/// Profiles all operations
|
||||
int CutlassProfiler::profile_() {
|
||||
|
||||
library::Manifest manifest(library::Provider::kCUTLASS);
|
||||
Status status = manifest.initialize();
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
DeviceContext device_context;
|
||||
|
||||
@@ -124,7 +117,7 @@ int CutlassProfiler::profile_() {
|
||||
if (options_.operation_kind == library::OperationKind::kInvalid ||
|
||||
options_.operation_kind == profiler->kind()) {
|
||||
|
||||
result = profiler->profile_all(options_, manifest, device_context);
|
||||
result = profiler->profile_all(options_, library::Singleton::get().manifest, device_context);
|
||||
|
||||
if (result) {
|
||||
return result;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -30,6 +30,7 @@
|
||||
// CUTLASS Library includes
|
||||
#include "cutlass/library/library.h"
|
||||
#include "cutlass/library/manifest.h"
|
||||
#include "cutlass/library/singleton.h"
|
||||
|
||||
#include "options.h"
|
||||
#include "operation_profiler.h"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -431,6 +431,14 @@ void DeviceAllocation::initialize_random_device(int seed, Distribution dist) {
|
||||
dist
|
||||
);
|
||||
break;
|
||||
case library::NumericTypeID::kCF32:
|
||||
cutlass::reference::device::BlockFillRandom<cutlass::complex<float>>(
|
||||
reinterpret_cast<cutlass::complex<float> *>(pointer_),
|
||||
capacity_,
|
||||
seed,
|
||||
dist
|
||||
);
|
||||
break;
|
||||
case library::NumericTypeID::kF64:
|
||||
cutlass::reference::device::BlockFillRandom<double>(
|
||||
reinterpret_cast<double *>(pointer_),
|
||||
@@ -548,6 +556,14 @@ void DeviceAllocation::initialize_random_host(int seed, Distribution dist) {
|
||||
dist
|
||||
);
|
||||
break;
|
||||
case library::NumericTypeID::kCF32:
|
||||
cutlass::reference::host::BlockFillRandom<cutlass::complex<float>>(
|
||||
reinterpret_cast<cutlass::complex<float> *>(host_data.data()),
|
||||
capacity_,
|
||||
seed,
|
||||
dist
|
||||
);
|
||||
break;
|
||||
case library::NumericTypeID::kF64:
|
||||
cutlass::reference::host::BlockFillRandom<double>(
|
||||
reinterpret_cast<double *>(host_data.data()),
|
||||
@@ -655,6 +671,12 @@ bool DeviceAllocation::block_compare_equal(
|
||||
reinterpret_cast<float const *>(ptr_A),
|
||||
reinterpret_cast<float const *>(ptr_B),
|
||||
capacity);
|
||||
|
||||
case library::NumericTypeID::kCF32:
|
||||
return reference::device::BlockCompareEqual<cutlass::complex<float> >(
|
||||
reinterpret_cast<complex<float> const *>(ptr_A),
|
||||
reinterpret_cast<complex<float> const *>(ptr_B),
|
||||
capacity);
|
||||
|
||||
case library::NumericTypeID::kCF16:
|
||||
return reference::device::BlockCompareEqual<complex<half_t>>(
|
||||
@@ -825,6 +847,23 @@ bool DeviceAllocation::block_compare_relatively_equal(
|
||||
static_cast<uint64_t>(epsilon),
|
||||
static_cast<uint64_t>(nonzero_floor));
|
||||
|
||||
// No relatively equal comparison for complex numbers.
|
||||
//
|
||||
// As a simplification, we can require bitwise equality. This avoids false positives.
|
||||
// (i.e. "pass" really means passing. "Fail" may not actually mean failure given appropriate epsilon.)
|
||||
//
|
||||
case library::NumericTypeID::kCF32:
|
||||
return reference::device::BlockCompareEqual<cutlass::complex<float> >(
|
||||
reinterpret_cast<complex<float> const *>(ptr_A),
|
||||
reinterpret_cast<complex<float> const *>(ptr_B),
|
||||
capacity);
|
||||
|
||||
case library::NumericTypeID::kCF64:
|
||||
return reference::device::BlockCompareEqual<cutlass::complex<double> >(
|
||||
reinterpret_cast<complex<double> const *>(ptr_A),
|
||||
reinterpret_cast<complex<double> const *>(ptr_B),
|
||||
capacity);
|
||||
|
||||
default:
|
||||
throw std::runtime_error("Unsupported numeric type");
|
||||
}
|
||||
@@ -970,6 +1009,14 @@ void DeviceAllocation::write_tensor_csv(
|
||||
case library::NumericTypeID::kU64:
|
||||
write_tensor_csv_static_type<uint64_t>(out, *this);
|
||||
break;
|
||||
|
||||
case library::NumericTypeID::kCF32:
|
||||
write_tensor_csv_static_type<cutlass::complex<float> >(out, *this);
|
||||
break;
|
||||
|
||||
case library::NumericTypeID::kCF64:
|
||||
write_tensor_csv_static_type<cutlass::complex<double> >(out, *this);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw std::runtime_error("Unsupported numeric type");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -50,7 +50,7 @@ T from_string(std::string const &);
|
||||
enum class ExecutionMode {
|
||||
kProfile, ///< regular verification and profiling
|
||||
kDryRun, ///< no kernels are launched or workspaces allocated; used to assess what operators might be launched
|
||||
kEnumerate, ///< no kernels launched or workspaces allocated; lists all function types and functions
|
||||
kEnumerate, ///< no kernels launched or workspaces allocated; lists all operation kind and operations
|
||||
kTrace, ///< executes a single device-side computation with no other kernel launches
|
||||
kInvalid
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -31,6 +31,8 @@
|
||||
#include <iomanip>
|
||||
#include <ios>
|
||||
|
||||
#include "cutlass/core_io.h"
|
||||
|
||||
#include "cublas_helpers.h"
|
||||
#include "gemm_operation_profiler.h"
|
||||
#include "gpu_timer.h"
|
||||
@@ -44,22 +46,27 @@ namespace profiler {
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Ctor
|
||||
GemmOperationProfiler::GemmOperationProfiler():
|
||||
OperationProfiler(library::OperationKind::kGemm,{
|
||||
{ArgumentTypeID::kEnumerated, {"Gemm_kind"}, "Variant of GEMM (e.g. gemm, planar complex, batched, ...)"},
|
||||
{ArgumentTypeID::kInteger, {"m", "problem-size::m"}, "M dimension of the GEMM problem space"},
|
||||
{ArgumentTypeID::kInteger, {"n", "problem-size::n"}, "N dimension of the GEMM problem space"},
|
||||
{ArgumentTypeID::kInteger, {"k", "problem-size::k"}, "K dimension of the GEMM problem space"},
|
||||
{ArgumentTypeID::kTensor, {"A"}, "Tensor storing the A operand"},
|
||||
{ArgumentTypeID::kTensor, {"B"}, "Tensor storing the B operand"},
|
||||
{ArgumentTypeID::kTensor, {"C"}, "Tensor storing the C operand"},
|
||||
{ArgumentTypeID::kScalar, {"alpha", "epilogue::alpha"}, "Epilogue scalar alpha"},
|
||||
{ArgumentTypeID::kScalar, {"beta", "epilogue::beta"}, "Epilogue scalar beta"},
|
||||
{ArgumentTypeID::kInteger, {"split_k_slices"}, "Number of partitions of K dimension"},
|
||||
{ArgumentTypeID::kInteger, {"batch_count"}, "Number of GEMMs computed in one batch"},
|
||||
}) {
|
||||
GemmOperationProfiler::GemmOperationProfiler(Options const &options):
|
||||
OperationProfiler(
|
||||
options,
|
||||
library::OperationKind::kGemm,
|
||||
{
|
||||
{ArgumentTypeID::kEnumerated, {"gemm_kind"}, "Variant of GEMM (gemm, batched, array, universal, planar_complex, planar_complex_array)"},
|
||||
{ArgumentTypeID::kInteger, {"m", "problem-size::m"}, "M dimension of the GEMM problem space"},
|
||||
{ArgumentTypeID::kInteger, {"n", "problem-size::n"}, "N dimension of the GEMM problem space"},
|
||||
{ArgumentTypeID::kInteger, {"k", "problem-size::k"}, "K dimension of the GEMM problem space"},
|
||||
{ArgumentTypeID::kTensor, {"A"}, "Tensor storing the A operand"},
|
||||
{ArgumentTypeID::kTensor, {"B"}, "Tensor storing the B operand"},
|
||||
{ArgumentTypeID::kTensor, {"C"}, "Tensor storing the C operand"},
|
||||
{ArgumentTypeID::kScalar, {"alpha", "epilogue::alpha"}, "Epilogue scalar alpha"},
|
||||
{ArgumentTypeID::kScalar, {"beta", "epilogue::beta"}, "Epilogue scalar beta"},
|
||||
{ArgumentTypeID::kInteger, {"split_k_slices", "split-k-slices"}, "Number of partitions of K dimension"},
|
||||
{ArgumentTypeID::kInteger, {"batch_count", "batch-count"}, "Number of GEMMs computed in one batch"},
|
||||
},
|
||||
{ library::Provider::kCUBLAS}
|
||||
) {
|
||||
|
||||
description_ = "General matrix-matrix product. D = alpha * A*B + beta * C";
|
||||
description_ = " General matrix-matrix product. D = alpha * A*B + beta * C";
|
||||
}
|
||||
|
||||
/// Destructor
|
||||
@@ -107,6 +114,8 @@ void GemmOperationProfiler::print_examples(std::ostream &out) const {
|
||||
<< " --providers=cutlass --output=functional-test.csv\n\n";
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if 0
|
||||
// used this for debugging
|
||||
static std::string byte_string(std::vector<uint8_t> const &bytes) {
|
||||
@@ -122,47 +131,34 @@ static std::string byte_string(std::vector<uint8_t> const &bytes) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Extracts the problem dimensions
|
||||
Status GemmOperationProfiler::initialize_configuration(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
Status GemmOperationProfiler::GemmProblem::parse(
|
||||
library::GemmDescription const &operation_desc,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem) {
|
||||
|
||||
library::GemmDescription const &operation_desc =
|
||||
static_cast<library::GemmDescription const &>(operation->description());
|
||||
|
||||
if (operation_desc.gemm_kind != library::GemmKind::kGemm) {
|
||||
return Status::kErrorInvalidProblem;
|
||||
|
||||
if (!arg_as_int(this->m, "m", problem_space, problem)) {
|
||||
// default value
|
||||
this->m = 1024;
|
||||
}
|
||||
|
||||
if (!arg_as_int(problem_.m, "m", problem_space, problem)) {
|
||||
if (!arg_as_int(this->n, "n", problem_space, problem)) {
|
||||
// default value
|
||||
problem_.m = 1024;
|
||||
}
|
||||
|
||||
if (!arg_as_int(problem_.n, "n", problem_space, problem)) {
|
||||
// default value
|
||||
problem_.n = 1024;
|
||||
this->n = 1024;
|
||||
}
|
||||
|
||||
if (!arg_as_int(problem_.k, "k", problem_space, problem)) {
|
||||
if (!arg_as_int(this->k, "k", problem_space, problem)) {
|
||||
// default value
|
||||
problem_.k = 1024;
|
||||
this->k = 1024;
|
||||
}
|
||||
|
||||
if (!arg_as_int(problem_.split_k_slices, "split_k_slices", problem_space, problem)) {
|
||||
if (!arg_as_int(this->split_k_slices, "split_k_slices", problem_space, problem)) {
|
||||
// default value
|
||||
problem_.split_k_slices = 1;
|
||||
this->split_k_slices = 1;
|
||||
}
|
||||
|
||||
if (!arg_as_int(problem_.batch_count, "batch_count", problem_space, problem)) {
|
||||
if (!arg_as_int(this->batch_count, "batch_count", problem_space, problem)) {
|
||||
// default value
|
||||
problem_.batch_count = 1;
|
||||
this->batch_count = 1;
|
||||
}
|
||||
|
||||
if (!tensor_description_satisfies(operation_desc.A, "A", problem_space, problem)) {
|
||||
@@ -178,37 +174,97 @@ Status GemmOperationProfiler::initialize_configuration(
|
||||
}
|
||||
|
||||
if (!arg_as_scalar(
|
||||
problem_.alpha,
|
||||
this->alpha,
|
||||
operation_desc.element_epilogue,
|
||||
"alpha",
|
||||
problem_space,
|
||||
problem)) {
|
||||
|
||||
if (!cast_from_double(problem_.alpha, operation_desc.element_epilogue, 1)) {
|
||||
if (!cast_from_double(this->alpha, operation_desc.element_epilogue, 1)) {
|
||||
return Status::kErrorInternal;
|
||||
}
|
||||
}
|
||||
|
||||
if (!arg_as_scalar(
|
||||
problem_.beta,
|
||||
this->beta,
|
||||
operation_desc.element_epilogue,
|
||||
"beta",
|
||||
problem_space,
|
||||
problem)) {
|
||||
|
||||
if (!cast_from_double(problem_.beta, operation_desc.element_epilogue, 0)) {
|
||||
if (!cast_from_double(this->beta, operation_desc.element_epilogue, 0)) {
|
||||
return Status::kErrorInternal;
|
||||
}
|
||||
}
|
||||
|
||||
problem_.lda = DeviceAllocation::get_packed_layout(
|
||||
operation_desc.A.layout, {int(problem_.m), int(problem_.k)}).front();
|
||||
this->lda = DeviceAllocation::get_packed_layout(
|
||||
operation_desc.A.layout, {int(this->m), int(this->k)}).front();
|
||||
|
||||
problem_.ldb = DeviceAllocation::get_packed_layout(
|
||||
operation_desc.B.layout, {int(problem_.k), int(problem_.n)}).front();
|
||||
this->ldb = DeviceAllocation::get_packed_layout(
|
||||
operation_desc.B.layout, {int(this->k), int(this->n)}).front();
|
||||
|
||||
problem_.ldc = DeviceAllocation::get_packed_layout(
|
||||
operation_desc.C.layout, {int(problem_.m), int(problem_.n)}).front();
|
||||
this->ldc = DeviceAllocation::get_packed_layout(
|
||||
operation_desc.C.layout, {int(this->m), int(this->n)}).front();
|
||||
|
||||
return Status::kSuccess;
|
||||
}
|
||||
|
||||
/// Initializes a performance result
|
||||
void GemmOperationProfiler::GemmProblem::initialize_result(
|
||||
PerformanceResult &result,
|
||||
library::GemmDescription const &operation_desc,
|
||||
ProblemSpace const &problem_space) {
|
||||
|
||||
result.arguments.resize(problem_space.rank());
|
||||
|
||||
set_argument(result, "gemm_kind", problem_space, library::to_string(operation_desc.gemm_kind));
|
||||
|
||||
set_argument(result, "A", problem_space,
|
||||
std::string(library::to_string(operation_desc.A.element)) + ":" + library::to_string(operation_desc.A.layout));
|
||||
|
||||
set_argument(result, "B", problem_space,
|
||||
std::string(library::to_string(operation_desc.B.element)) + ":" + library::to_string(operation_desc.B.layout));
|
||||
|
||||
set_argument(result, "C", problem_space,
|
||||
std::string(library::to_string(operation_desc.C.element)) + ":" + library::to_string(operation_desc.C.layout));
|
||||
|
||||
set_argument(result, "m", problem_space, m);
|
||||
set_argument(result, "n", problem_space, n);
|
||||
set_argument(result, "k", problem_space, k);
|
||||
|
||||
set_argument(result, "split_k_slices", problem_space, split_k_slices);
|
||||
set_argument(result, "batch_count", problem_space, batch_count);
|
||||
|
||||
set_argument(result, "alpha", problem_space,
|
||||
library::lexical_cast(alpha, operation_desc.element_epilogue));
|
||||
|
||||
set_argument(result, "beta", problem_space,
|
||||
library::lexical_cast(beta, operation_desc.element_epilogue));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Extracts the problem dimensions
|
||||
Status GemmOperationProfiler::initialize_configuration(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem) {
|
||||
|
||||
library::GemmDescription const &operation_desc =
|
||||
static_cast<library::GemmDescription const &>(operation->description());
|
||||
|
||||
if (operation_desc.gemm_kind != library::GemmKind::kUniversal) {
|
||||
return Status::kErrorInvalidProblem;
|
||||
}
|
||||
|
||||
Status status = problem_.parse(operation_desc, problem_space, problem);
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
gemm_workspace_.configuration.problem_size.m() = int(problem_.m);
|
||||
gemm_workspace_.configuration.problem_size.n() = int(problem_.n);
|
||||
@@ -217,7 +273,8 @@ Status GemmOperationProfiler::initialize_configuration(
|
||||
gemm_workspace_.configuration.ldb = problem_.ldb;
|
||||
gemm_workspace_.configuration.ldc = problem_.ldc;
|
||||
gemm_workspace_.configuration.ldd = problem_.ldc;
|
||||
gemm_workspace_.configuration.split_k_slices = int(problem_.split_k_slices);
|
||||
//gemm_workspace_.configuration.split_k_slices = int(problem_.split_k_slices);
|
||||
gemm_workspace_.configuration.batch_count = int(problem_.split_k_slices);
|
||||
|
||||
gemm_workspace_.arguments.A = nullptr;
|
||||
gemm_workspace_.arguments.B = nullptr;
|
||||
@@ -243,37 +300,24 @@ void GemmOperationProfiler::initialize_result_(
|
||||
result.disposition = Disposition::kNotRun;
|
||||
result.status = Status::kSuccess;
|
||||
result.operation_name = operation_desc.name;
|
||||
|
||||
result.arguments.resize(problem_space.rank());
|
||||
|
||||
set_argument_(result, "A", problem_space,
|
||||
std::string(library::to_string(operation_desc.A.element)) + ":" + library::to_string(operation_desc.A.layout));
|
||||
|
||||
set_argument_(result, "B", problem_space,
|
||||
std::string(library::to_string(operation_desc.B.element)) + ":" + library::to_string(operation_desc.B.layout));
|
||||
|
||||
set_argument_(result, "C", problem_space,
|
||||
std::string(library::to_string(operation_desc.C.element)) + ":" + library::to_string(operation_desc.C.layout));
|
||||
|
||||
set_argument_(result, "m", problem_space, problem_.m);
|
||||
set_argument_(result, "n", problem_space, problem_.n);
|
||||
set_argument_(result, "k", problem_space, problem_.k);
|
||||
|
||||
set_argument_(result, "split_k_slices", problem_space, problem_.split_k_slices);
|
||||
set_argument_(result, "batch_count", problem_space, problem_.batch_count);
|
||||
|
||||
set_argument_(result, "alpha", problem_space,
|
||||
library::lexical_cast(problem_.alpha, operation_desc.element_epilogue));
|
||||
|
||||
set_argument_(result, "beta", problem_space,
|
||||
library::lexical_cast(problem_.beta, operation_desc.element_epilogue));
|
||||
|
||||
problem_.initialize_result(result, operation_desc, problem_space);
|
||||
|
||||
OperationProfiler::initialize_result_(result, operation_desc, problem_space);
|
||||
|
||||
// Input bytes read and Output bytes written for the gemm problem
|
||||
result.bytes =
|
||||
int64_t(library::sizeof_bits(operation_desc.A.element) * problem_.m / 8) * problem_.k +
|
||||
int64_t(library::sizeof_bits(operation_desc.B.element) * problem_.n / 8) * problem_.k +
|
||||
int64_t(library::sizeof_bits(operation_desc.C.element) * problem_.m / 8) * problem_.n * 2;
|
||||
int64_t(library::sizeof_bits(operation_desc.C.element) * problem_.m / 8) * problem_.n;
|
||||
|
||||
// Set is_beta_zero true if beta is zero
|
||||
bool is_beta_zero = std::all_of(problem_.beta.begin(), problem_.beta.end(), [](uint8_t i) { return i==0; });
|
||||
|
||||
// Output bytes read for the gemm problem for non-zero beta values
|
||||
if (!is_beta_zero) {
|
||||
result.bytes += int64_t(library::sizeof_bits(operation_desc.C.element) * problem_.m / 8) * problem_.n;
|
||||
}
|
||||
|
||||
result.flops = 2 * (problem_.m * problem_.n * problem_.k + problem_.m * problem_.n);
|
||||
result.runtime = 0;
|
||||
@@ -378,8 +422,9 @@ Status GemmOperationProfiler::initialize_workspace(
|
||||
results_.back().provider = library::Provider::kCUTLASS;
|
||||
results_.back().op_kind = library::OperationKind::kGemm;
|
||||
results_.back().disposition = Disposition::kNotRun;
|
||||
for(auto &verification_provider : options.verification.providers) {
|
||||
results_.back().verification_map[verification_provider] = Disposition::kNotRun;
|
||||
|
||||
for(auto provider : verification_providers_) {
|
||||
results_.back().verification_map[provider] = Disposition::kNotRun;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,8 +604,7 @@ bool GemmOperationProfiler::verify_with_cublas_(
|
||||
);
|
||||
|
||||
if (gemm_op.status != Status::kSuccess) {
|
||||
|
||||
results_.back().verification_map[library::Provider::kCUBLAS] = Disposition::kFailed;
|
||||
results_.back().verification_map[library::Provider::kCUBLAS] = Disposition::kNotRun;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
||||
// CUTLASS Library includes
|
||||
@@ -75,6 +76,18 @@ public:
|
||||
|
||||
GemmProblem():
|
||||
m(16), n(16), k(16), lda(0), ldb(0), ldc(0), split_k_slices(1), batch_count(1) { }
|
||||
|
||||
/// Parses the problem
|
||||
Status parse(
|
||||
library::GemmDescription const &operation_desc,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Initializes a performance result
|
||||
void initialize_result(
|
||||
PerformanceResult &result,
|
||||
library::GemmDescription const &operation_desc,
|
||||
ProblemSpace const &problem_space);
|
||||
};
|
||||
|
||||
/// Workspace used
|
||||
@@ -86,8 +99,8 @@ public:
|
||||
DeviceAllocation *Computed;
|
||||
DeviceAllocation *Reference;
|
||||
|
||||
library::GemmConfiguration configuration;
|
||||
library::GemmArguments arguments;
|
||||
library::GemmUniversalConfiguration configuration;
|
||||
library::GemmUniversalArguments arguments;
|
||||
|
||||
/// Buffer used for the operation's host workspace
|
||||
std::vector<uint8_t> host_workspace;
|
||||
@@ -122,7 +135,7 @@ public:
|
||||
//
|
||||
|
||||
/// Ctor
|
||||
GemmOperationProfiler();
|
||||
GemmOperationProfiler(Options const &options);
|
||||
|
||||
/// Destructor
|
||||
virtual ~GemmOperationProfiler();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <iomanip>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef __unix__
|
||||
#include <unistd.h>
|
||||
@@ -55,30 +56,41 @@ OperationProfiler::OperationProfiler(): kind_(library::OperationKind::kInvalid)
|
||||
|
||||
/// Ctor
|
||||
OperationProfiler::OperationProfiler(
|
||||
Options const &options,
|
||||
library::OperationKind kind,
|
||||
ArgumentDescriptionVector const &arguments,
|
||||
ProviderVector const & reference_providers
|
||||
ProviderVector const & verification_providers
|
||||
):
|
||||
kind_(kind), arguments_(arguments), reference_providers_(reference_providers) {
|
||||
kind_(kind), arguments_(arguments) {
|
||||
|
||||
ArgumentDescriptionVector tile_description_arguments{
|
||||
{ArgumentTypeID::kEnumerated, {"op_class", "opcode-class"}, "Class of math instruction (SIMT or TensorOp)."},
|
||||
{ArgumentTypeID::kEnumerated, {"accum", "accumulator-type"}, "Math instruction accumulator data type."},
|
||||
{ArgumentTypeID::kInteger, {"cta_m", "threadblock-shape::m"}, "Threadblock shape in the M dimension."},
|
||||
{ArgumentTypeID::kInteger, {"cta_n", "threadblock-shape::n"}, "Threadblock shape in the N dimension."},
|
||||
{ArgumentTypeID::kInteger, {"cta_k", "threadblock-shape::k"}, "Threadblock shape in the K dimension."},
|
||||
{ArgumentTypeID::kInteger, {"stages", "threadblock-stages"}, "Number of stages of threadblock-scoped matrix multiply."},
|
||||
{ArgumentTypeID::kInteger, {"warps_m", "warp-count::m"}, "Number of warps within threadblock along the M dimension."},
|
||||
{ArgumentTypeID::kInteger, {"warps_n", "warp-count::n"}, "Number of warps within threadblock along the N dimension."},
|
||||
{ArgumentTypeID::kInteger, {"warps_k", "warp-count::k"}, "Number of warps within threadblock along the K dimension."},
|
||||
{ArgumentTypeID::kInteger, {"inst_m", "instruction-shape::m"}, "Math instruction shape in the M dimension."},
|
||||
{ArgumentTypeID::kInteger, {"inst_n", "instruction-shape::n"}, "Math instruction shape in the N dimension."},
|
||||
{ArgumentTypeID::kInteger, {"inst_k", "instruction-shape::k"}, "Math instruction shape in the K dimension."},
|
||||
{ArgumentTypeID::kInteger, {"min_cc", "minimum-compute-capability"}, "Minimum device compute capability."},
|
||||
{ArgumentTypeID::kInteger, {"max_cc", "maximum-compute-capability"}, "Maximum device compute capability."}
|
||||
{ArgumentTypeID::kEnumerated, {"op_class", "opcode-class"}, "Class of math instruction (simt, tensorop, wmmatensorop, wmma)"},
|
||||
{ArgumentTypeID::kEnumerated, {"accum", "accumulator-type"}, "Math instruction accumulator data type"},
|
||||
{ArgumentTypeID::kInteger, {"cta_m", "threadblock-shape::m"}, "Threadblock shape in the M dimension"},
|
||||
{ArgumentTypeID::kInteger, {"cta_n", "threadblock-shape::n"}, "Threadblock shape in the N dimension"},
|
||||
{ArgumentTypeID::kInteger, {"cta_k", "threadblock-shape::k"}, "Threadblock shape in the K dimension"},
|
||||
{ArgumentTypeID::kInteger, {"stages", "threadblock-stages"}, "Number of stages of threadblock-scoped matrix multiply"},
|
||||
{ArgumentTypeID::kInteger, {"warps_m", "warp-count::m"}, "Number of warps within threadblock along the M dimension"},
|
||||
{ArgumentTypeID::kInteger, {"warps_n", "warp-count::n"}, "Number of warps within threadblock along the N dimension"},
|
||||
{ArgumentTypeID::kInteger, {"warps_k", "warp-count::k"}, "Number of warps within threadblock along the K dimension"},
|
||||
{ArgumentTypeID::kInteger, {"inst_m", "instruction-shape::m"}, "Math instruction shape in the M dimension"},
|
||||
{ArgumentTypeID::kInteger, {"inst_n", "instruction-shape::n"}, "Math instruction shape in the N dimension"},
|
||||
{ArgumentTypeID::kInteger, {"inst_k", "instruction-shape::k"}, "Math instruction shape in the K dimension"},
|
||||
{ArgumentTypeID::kInteger, {"min_cc", "minimum-compute-capability"}, "Minimum device compute capability"},
|
||||
{ArgumentTypeID::kInteger, {"max_cc", "maximum-compute-capability"}, "Maximum device compute capability"}
|
||||
};
|
||||
|
||||
arguments_.insert(arguments_.end(), tile_description_arguments.begin(), tile_description_arguments.end());
|
||||
|
||||
for (auto provider : verification_providers) {
|
||||
if (std::find(
|
||||
options.verification.providers.begin(),
|
||||
options.verification.providers.end(),
|
||||
provider) != options.verification.providers.end()) {
|
||||
|
||||
verification_providers_.push_back(provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Destructor
|
||||
@@ -248,8 +260,9 @@ int OperationProfiler::profile_all(
|
||||
auto min_cc = operation->description().tile_description.minimum_compute_capability;
|
||||
auto max_cc = operation->description().tile_description.maximum_compute_capability;
|
||||
|
||||
// Execute compatible operations if they satisfy the current device's compute capability
|
||||
// Execute compatible cutlass operations if they satisfy the current device's compute capability
|
||||
if (operation->description().kind == kind_ &&
|
||||
operation->description().provider == library::Provider::kCUTLASS &&
|
||||
options.device.compute_capability() >= min_cc &&
|
||||
options.device.compute_capability() <= max_cc) {
|
||||
|
||||
@@ -259,7 +272,7 @@ int OperationProfiler::profile_all(
|
||||
if (!filtered_by_name) {
|
||||
|
||||
for (auto const & op_name : options.operation_names) {
|
||||
if (operation_name.find(op_name) !=std::string::npos) {
|
||||
if (find_string_matches_(op_name, operation_name)) {
|
||||
filtered_by_name = true;
|
||||
break;
|
||||
}
|
||||
@@ -278,7 +291,7 @@ int OperationProfiler::profile_all(
|
||||
operation,
|
||||
problem_space,
|
||||
problem);
|
||||
|
||||
|
||||
if (status == Status::kErrorInternal) {
|
||||
// Stop profiling if there was an internal error
|
||||
return false;
|
||||
@@ -548,29 +561,28 @@ void OperationProfiler::initialize_result_(
|
||||
library::OperationDescription const &operation_desc,
|
||||
ProblemSpace const &problem_space) {
|
||||
|
||||
set_argument_(result, "op_class", problem_space,
|
||||
set_argument(result, "op_class", problem_space,
|
||||
library::to_string(operation_desc.tile_description.math_instruction.opcode_class));
|
||||
|
||||
set_argument_(result, "accum", problem_space,
|
||||
set_argument(result, "accum", problem_space,
|
||||
library::to_string(operation_desc.tile_description.math_instruction.element_accumulator));
|
||||
|
||||
set_argument_(result, "cta_m", problem_space, operation_desc.tile_description.threadblock_shape.m());
|
||||
set_argument_(result, "cta_n", problem_space, operation_desc.tile_description.threadblock_shape.n());
|
||||
set_argument_(result, "cta_k", problem_space, operation_desc.tile_description.threadblock_shape.k());
|
||||
set_argument_(result, "stages", problem_space, operation_desc.tile_description.threadblock_stages);
|
||||
set_argument_(result, "warps_m", problem_space, operation_desc.tile_description.warp_count.m());
|
||||
set_argument_(result, "warps_n", problem_space, operation_desc.tile_description.warp_count.n());
|
||||
set_argument_(result, "warps_k", problem_space, operation_desc.tile_description.warp_count.k());
|
||||
set_argument_(result, "inst_m", problem_space, operation_desc.tile_description.math_instruction.instruction_shape.m());
|
||||
set_argument_(result, "inst_n", problem_space, operation_desc.tile_description.math_instruction.instruction_shape.n());
|
||||
set_argument_(result, "inst_k", problem_space, operation_desc.tile_description.math_instruction.instruction_shape.k());
|
||||
set_argument_(result, "min_cc", problem_space, operation_desc.tile_description.minimum_compute_capability);
|
||||
set_argument_(result, "max_cc", problem_space, operation_desc.tile_description.maximum_compute_capability);
|
||||
set_argument(result, "cta_m", problem_space, operation_desc.tile_description.threadblock_shape.m());
|
||||
set_argument(result, "cta_n", problem_space, operation_desc.tile_description.threadblock_shape.n());
|
||||
set_argument(result, "cta_k", problem_space, operation_desc.tile_description.threadblock_shape.k());
|
||||
set_argument(result, "stages", problem_space, operation_desc.tile_description.threadblock_stages);
|
||||
set_argument(result, "warps_m", problem_space, operation_desc.tile_description.warp_count.m());
|
||||
set_argument(result, "warps_n", problem_space, operation_desc.tile_description.warp_count.n());
|
||||
set_argument(result, "warps_k", problem_space, operation_desc.tile_description.warp_count.k());
|
||||
set_argument(result, "inst_m", problem_space, operation_desc.tile_description.math_instruction.instruction_shape.m());
|
||||
set_argument(result, "inst_n", problem_space, operation_desc.tile_description.math_instruction.instruction_shape.n());
|
||||
set_argument(result, "inst_k", problem_space, operation_desc.tile_description.math_instruction.instruction_shape.k());
|
||||
set_argument(result, "min_cc", problem_space, operation_desc.tile_description.minimum_compute_capability);
|
||||
set_argument(result, "max_cc", problem_space, operation_desc.tile_description.maximum_compute_capability);
|
||||
}
|
||||
|
||||
|
||||
/// Helper
|
||||
void OperationProfiler::set_argument_(
|
||||
void OperationProfiler::set_argument(
|
||||
PerformanceResult &result,
|
||||
char const *name,
|
||||
ProblemSpace const &problem_space,
|
||||
@@ -579,7 +591,7 @@ void OperationProfiler::set_argument_(
|
||||
result.arguments.at(problem_space.argument_index(name)) = make_pair(std::string(name), value);
|
||||
}
|
||||
|
||||
void OperationProfiler::set_argument_(
|
||||
void OperationProfiler::set_argument(
|
||||
PerformanceResult &result,
|
||||
char const *name,
|
||||
ProblemSpace const &problem_space,
|
||||
@@ -588,6 +600,39 @@ void OperationProfiler::set_argument_(
|
||||
result.arguments.at(problem_space.argument_index(name)) = make_pair(std::string(name), library::lexical_cast(value));
|
||||
}
|
||||
|
||||
|
||||
/// finds string matches filter_string in operation_name
|
||||
bool OperationProfiler::find_string_matches_(
|
||||
std::string const &filter_string,
|
||||
std::string const &operation_name) {
|
||||
// Returns true if all substrings appear in the operation_name in order
|
||||
|
||||
// Split filter_string of the format "gemm*f32*nt" to tokens ["gemm", "f32", "nt"]
|
||||
std::string item;
|
||||
std::istringstream iss(filter_string);
|
||||
std::vector<std::string> filter_tokens;
|
||||
while (std::getline(iss, item, '*')) {
|
||||
filter_tokens.push_back(item);
|
||||
}
|
||||
|
||||
// Search filter_tokens in operation_name in order
|
||||
size_t start = 0, idx = 0;
|
||||
for(auto & token : filter_tokens) {
|
||||
// Check if characters left to be parsed in operation_name
|
||||
if (start < operation_name.length()) {
|
||||
// Find token in operation_name[start:]
|
||||
idx = operation_name.substr(start).find(token);
|
||||
if (idx == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
start += (idx + token.length());
|
||||
}
|
||||
|
||||
// All tokens in filter_string found in operation_name
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace profiler
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -73,7 +73,7 @@ protected:
|
||||
ArgumentDescriptionVector arguments_;
|
||||
|
||||
/// List of providers used to verify and compare each result
|
||||
ProviderVector reference_providers_;
|
||||
ProviderVector verification_providers_;
|
||||
|
||||
/// Model performance result initailized by the operation profiler with workload statistics
|
||||
/// and reasonable default state.
|
||||
@@ -92,9 +92,10 @@ public:
|
||||
OperationProfiler();
|
||||
|
||||
OperationProfiler(
|
||||
Options const &options,
|
||||
library::OperationKind kind,
|
||||
ArgumentDescriptionVector const &arguments = ArgumentDescriptionVector(),
|
||||
ProviderVector const & reference_providers = ProviderVector());
|
||||
ProviderVector const & verification_providers = ProviderVector());
|
||||
|
||||
/// Destructor
|
||||
virtual ~OperationProfiler();
|
||||
@@ -196,6 +197,20 @@ public:
|
||||
library::OperationDescription const &desc,
|
||||
library::Provider provider,
|
||||
library::Provider verification_provider = library::Provider::kInvalid);
|
||||
|
||||
/// Helper to set a performance result member
|
||||
static void set_argument(
|
||||
PerformanceResult &result,
|
||||
char const *name,
|
||||
ProblemSpace const &problem_space,
|
||||
std::string const &value);
|
||||
|
||||
/// Helper to set a performance result member
|
||||
static void set_argument(
|
||||
PerformanceResult &result,
|
||||
char const *name,
|
||||
ProblemSpace const &problem_space,
|
||||
int64_t value);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -205,20 +220,6 @@ protected:
|
||||
library::OperationDescription const &operation_desc,
|
||||
ProblemSpace const &problem_space);
|
||||
|
||||
/// Helper to set a performance result member
|
||||
static void set_argument_(
|
||||
PerformanceResult &result,
|
||||
char const *name,
|
||||
ProblemSpace const &problem_space,
|
||||
std::string const &value);
|
||||
|
||||
/// Helper to set a performance result member
|
||||
static void set_argument_(
|
||||
PerformanceResult &result,
|
||||
char const *name,
|
||||
ProblemSpace const &problem_space,
|
||||
int64_t value);
|
||||
|
||||
/// Method to profile an initialized CUTLASS operation
|
||||
virtual Status profile_cutlass_(
|
||||
double &runtime,
|
||||
@@ -227,6 +228,12 @@ protected:
|
||||
void const *arguments,
|
||||
void *host_workspace,
|
||||
void *device_workspace);
|
||||
|
||||
private:
|
||||
/// finds string matches filter_string in operation_name
|
||||
bool find_string_matches_(
|
||||
std::string const &filter_string,
|
||||
std::string const &operation_name);
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -76,7 +76,7 @@ Options::Device::Device(cutlass::CommandLine const &cmdline) {
|
||||
void Options::Device::print_usage(std::ostream &out) const {
|
||||
|
||||
out << "Device:\n"
|
||||
<< " --device=<int> "
|
||||
<< " --device=<int> "
|
||||
<< " CUDA Device ID\n\n";
|
||||
|
||||
int device_count = 0;
|
||||
@@ -106,7 +106,7 @@ void Options::Device::print_usage(std::ostream &out) const {
|
||||
}
|
||||
|
||||
out
|
||||
<< " --compute-capability=<int> "
|
||||
<< " --compute-capability=<int> "
|
||||
<< " Override the compute capability.\n\n";
|
||||
|
||||
}
|
||||
@@ -255,12 +255,6 @@ void Options::Initialization::get_distribution(
|
||||
continue; // next token
|
||||
}
|
||||
|
||||
// Casts as integer without scaling
|
||||
if (it->first.compare("integer") == 0) {
|
||||
dist.int_scale = 0;
|
||||
continue; // next token
|
||||
}
|
||||
|
||||
// initialize other members
|
||||
for (int m = 0; members[m].label; ++m) {
|
||||
if (it->first == members[m].label && !it->second.empty()) {
|
||||
@@ -276,19 +270,23 @@ void Options::Initialization::print_usage(std::ostream &out) const {
|
||||
|
||||
out << "Initialization:\n"
|
||||
|
||||
<< " --initialization=<bool> "
|
||||
<< " --initialization=<bool> "
|
||||
<< " Enables initialization (default: true). If false, device memory is" << end_of_line
|
||||
<< "not initialized after allocation.\n\n"
|
||||
<< " not initialized after allocation.\n\n"
|
||||
|
||||
<< " --initialization-provider=<provider> "
|
||||
<< " Selects 'device' or 'host' initialization.\n\n"
|
||||
<< " --initialization-provider=<provider> "
|
||||
<< " Selects initialization provider {host, device*}. (default: '*')\n\n"
|
||||
|
||||
<< " --dist=<distribution> "
|
||||
<< " Data distribution of input tensors\n\n"
|
||||
<< " --dist=<distribution> "
|
||||
<< " Data distribution of input tensors {uniform*, gaussian, identity, sequential}" << end_of_line
|
||||
<< " --dist=uniform,min:<double>,max:<double>,scale:<integer>" << end_of_line
|
||||
<< " --dist=gaussian,mean:<double>,stddev:<double>,scale:<integer>" << end_of_line
|
||||
<< " --dist=sequential,start:<double>,delta:<double>,scale:<integer>" << end_of_line
|
||||
<< " --dist=identity\n\n"
|
||||
|
||||
<< " --seed=<int> "
|
||||
<< " --seed=<int> "
|
||||
<< " Random number generator seed. Used to enforce deterministic" << end_of_line
|
||||
<< "initialization.\n\n";
|
||||
<< " initialization.\n\n";
|
||||
|
||||
}
|
||||
|
||||
@@ -339,12 +337,12 @@ void Options::Library::print_usage(std::ostream &out) const {
|
||||
|
||||
out << "Library:\n"
|
||||
|
||||
<< " --library-algo-mode=<mode> "
|
||||
<< " --library-algo-mode=<mode> "
|
||||
<< " Indicates algorithm mode used to call libraries such as cuBLAS and cuDNN.\n"
|
||||
<< " "
|
||||
<< " "
|
||||
<< " mode={default*,matching,best}\n\n"
|
||||
|
||||
<< " --library-algos=<range-list> "
|
||||
<< " --library-algos=<range-list> "
|
||||
<< " If --algorithm-mode=best, permits specifying a selection of algorithms.\n\n";
|
||||
|
||||
}
|
||||
@@ -393,21 +391,25 @@ void Options::Profiling::print_usage(std::ostream &out) const {
|
||||
|
||||
out << "Profiling:\n"
|
||||
|
||||
<< " --profiling-iterations=<iterations> "
|
||||
<< " --profiling-iterations=<iterations> "
|
||||
<< " Number of iterations to profile each kernel. If zero, kernels" << end_of_line
|
||||
<< "are launched up to the profiling duration.\n\n"
|
||||
<< " are launched up to the profiling duration.\n\n"
|
||||
|
||||
<< " --warmup-iterations=<iterations> "
|
||||
<< " --warmup-iterations=<iterations> "
|
||||
<< " Number of iterations to execute each kernel prior to profiling.\n\n"
|
||||
|
||||
<< " --sleep-duration=<duration> "
|
||||
<< " Number of ms to sleep between profiling periods (ms)\n\n"
|
||||
<< " --sleep-duration=<duration> "
|
||||
<< " Number of ms to sleep between profiling periods (ms).\n\n"
|
||||
|
||||
<< " --profiling-enabled=<bool> "
|
||||
<< " --profiling-enabled=<bool> "
|
||||
<< " If true, profiling is actually conducted.\n\n"
|
||||
|
||||
<< " --providers=<providers> "
|
||||
<< " List of providers to be profiled for performance\n\n";
|
||||
<< " --providers=<providers> "
|
||||
<< " List of providers to be profiled for performance. (default: '*')" << end_of_line
|
||||
<< " Gemm providers {cutlass*"
|
||||
<< "}" << end_of_line
|
||||
<< "\n\n";
|
||||
|
||||
}
|
||||
|
||||
void Options::Profiling::print_options(std::ostream &out, int indent) const {
|
||||
@@ -477,6 +479,7 @@ Options::Verification::Verification(cutlass::CommandLine const &cmdline) {
|
||||
}
|
||||
else {
|
||||
providers.push_back(library::Provider::kCUBLAS);
|
||||
providers.push_back(library::Provider::kReferenceDevice);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,22 +487,27 @@ void Options::Verification::print_usage(std::ostream &out) const {
|
||||
|
||||
out << "Verification:\n"
|
||||
|
||||
<< " --verification-enabled=<bool> "
|
||||
<< " --verification-enabled=<bool> "
|
||||
<< " Whether to perform verification checks.\n\n"
|
||||
|
||||
<< " --epsilon=<error> "
|
||||
<< " --epsilon=<error> "
|
||||
<< " Error threshold. Setting to zero (default) requires" << end_of_line
|
||||
<< "bit-level equivalence.\n\n"
|
||||
<< " bit-level equivalence.\n\n"
|
||||
|
||||
<< " --nonzero-floor=<floor> "
|
||||
<< " --nonzero-floor=<floor> "
|
||||
<< " Results whose absolute value is less than this quantity" << end_of_line
|
||||
<< "are treated as zero for comparisons.\n\n"
|
||||
<< " are treated as zero for comparisons.\n\n"
|
||||
|
||||
<< " --save-workspace={*never,incorrect,always}"
|
||||
<< " Specifies when to save the GEMM inputs and results to the filesystem.\n\n"
|
||||
<< " --save-workspace=<string> "
|
||||
<< " Specifies when to save the GEMM inputs and results to the filesystem." << end_of_line
|
||||
<< " --save-workspace=never never save workspace (default)" << end_of_line
|
||||
<< " --save-workspace=incorrect save workspace for incorrect results" << end_of_line
|
||||
<< " --save-workspace=always always save workspace\n\n"
|
||||
|
||||
<< " --verification-providers=<providers> "
|
||||
<< " List of providers used to verify result. (default: device)\n\n";
|
||||
<< " --verification-providers=<providers> "
|
||||
<< " List of providers used to verify result. (default: '*')" << end_of_line
|
||||
<< " Gemm verification-providers {cublas*}" << end_of_line
|
||||
<< "\n\n";
|
||||
}
|
||||
|
||||
void Options::Verification::print_options(std::ostream &out, int indent) const {
|
||||
@@ -554,22 +562,22 @@ void Options::Report::print_usage(std::ostream &out) const {
|
||||
|
||||
out << "Report:\n"
|
||||
|
||||
<< " --append=<bool> "
|
||||
<< " --append=<bool> "
|
||||
<< " If true, result is appended to possibly existing file. Otherwise, " << end_of_line
|
||||
<< "any existing file is overwritten.\n\n"
|
||||
<< " any existing file is overwritten.\n\n"
|
||||
|
||||
<< " --output=<path> "
|
||||
<< " Path to output file for machine readable results.\n\n"
|
||||
<< " --output=<path> "
|
||||
<< " Path to output file for machine readable results. Operation kind and '.csv' is appended.\n\n"
|
||||
|
||||
<< " --report-not-run=<bool> "
|
||||
<< " --report-not-run=<bool> "
|
||||
<< " If true, reports the status of all kernels including those that" << end_of_line
|
||||
<< "do not satisfy the given arguments.\n\n"
|
||||
<< " do not satisfy the given arguments.\n\n"
|
||||
|
||||
<< " --tags=<column:tag,...> "
|
||||
<< " --tags=<column:tag,...> "
|
||||
<< " Inserts leading columns in output table and uniform values for each" << end_of_line
|
||||
<< "column. Useful for generating pivot tables.\n\n"
|
||||
<< " column. Useful for generating pivot tables.\n\n"
|
||||
|
||||
<< " --verbose=<bool> "
|
||||
<< " --verbose=<bool> "
|
||||
<< " Prints human-readable text to stdout. If false, nothing is written to stdout.\n\n";
|
||||
}
|
||||
|
||||
@@ -600,7 +608,7 @@ Options::About::About(cutlass::CommandLine const &cmdline) {
|
||||
void Options::About::print_usage(std::ostream &out) const {
|
||||
|
||||
out << "About:\n"
|
||||
<< " --version ";
|
||||
<< " --version ";
|
||||
|
||||
print_version(out);
|
||||
|
||||
@@ -675,22 +683,29 @@ Options::Options(cutlass::CommandLine const &cmdline):
|
||||
void Options::print_usage(std::ostream &out) const {
|
||||
|
||||
out
|
||||
<< "CUTLASS Performance Tool\n"
|
||||
<< "CUTLASS Profiler\n"
|
||||
<< "usage:\n\n"
|
||||
<< " cutlass_profiler [options]\n\n"
|
||||
<< " --help\n\n"
|
||||
|
||||
<< " --mode={profile*,single,dry,trace,enumerate} "
|
||||
<< " Regular profiling, single kernel mode only, or no profiling.\n\n"
|
||||
<< " --mode=<string> "
|
||||
<< " Cutlass profiler execution mode." << end_of_line
|
||||
<< " --mode=profile regular verification and profiling (default)" << end_of_line
|
||||
<< " --mode=dry_run no kernels are launched or workspaces allocated" << end_of_line
|
||||
<< " --mode=enumerate lists all operation kind and operations" << end_of_line
|
||||
<< " --mode=trace executes a single device-side computation with" << end_of_line
|
||||
<< " no other kernel launches\n\n"
|
||||
|
||||
<< " --device-info "
|
||||
<< " --device-info "
|
||||
<< " Prints information on all GPUs present in the system\n\n"
|
||||
|
||||
<< " --operation=<operation_kind> "
|
||||
<< " --operation=<operation_kind> "
|
||||
<< " CUTLASS operation to profile.\n\n"
|
||||
|
||||
<< " --kernels=<string_list> "
|
||||
<< " List of substrings to filter operations by name.\n\n"
|
||||
<< " --kernels=<string_list> "
|
||||
<< " Filter operations by kernel names. For example, call all kernels with" << end_of_line
|
||||
<< " (\"s1688\" and \"nt\") or (\"s844\" and \"tn\" and \"align8\") in their" << end_of_line
|
||||
<< " operation name using --kernels=\"s1688*nt, s884*tn*align8\"\n\n"
|
||||
;
|
||||
|
||||
//
|
||||
@@ -755,4 +770,3 @@ std::string Options::indent_str(int indent) {
|
||||
|
||||
} // namespace profiler
|
||||
} // namespace cutlass
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -68,9 +68,11 @@ PerformanceReport::PerformanceReport(
|
||||
):
|
||||
options_(options), argument_names_(argument_names), problem_index_(0), good_(true), op_kind_(op_kind) {
|
||||
|
||||
std::string file_name = options_.report.output_path.substr(0, options_.report.output_path.rfind("."));
|
||||
std::string file_extension = options_.report.output_path.substr(options_.report.output_path.rfind(".") + 1);
|
||||
op_file_name_ = file_name + "." + to_string(op_kind_) + "." + file_extension;
|
||||
// Strip '.csv' if present
|
||||
std::string base_path = options_.report.output_path.substr(
|
||||
0, options_.report.output_path.rfind(".csv"));
|
||||
|
||||
op_file_name_ = base_path + "." + to_string(op_kind_) + ".csv";
|
||||
|
||||
//
|
||||
// Open output file for operation of PerformanceReport::op_kind
|
||||
@@ -166,6 +168,7 @@ void PerformanceReport::close() {
|
||||
static const char *disposition_status_color(Disposition disposition) {
|
||||
switch (disposition) {
|
||||
case Disposition::kPassed: return SHELL_COLOR_GREEN();
|
||||
case Disposition::kIncorrect: return SHELL_COLOR_RED();
|
||||
case Disposition::kFailed: return SHELL_COLOR_RED();
|
||||
default:
|
||||
break;
|
||||
@@ -195,16 +198,17 @@ std::ostream & PerformanceReport::print_result_pretty_(
|
||||
|
||||
out
|
||||
<< "\n"
|
||||
<< " Provider: " << SHELL_COLOR_BRIGHT() << library::to_string(result.provider, true) << SHELL_COLOR_END() << "\n"
|
||||
<< " Operation: " << result.operation_name << "\n\n"
|
||||
<< " Status: " << SHELL_COLOR_BRIGHT() << library::to_string(result.status, true) << SHELL_COLOR_END() << "\n"
|
||||
<< " Verification: " << SHELL_COLOR_BRIGHT() << (options_.verification.enabled ? "ON":"OFF") << SHELL_COLOR_END() << "\n"
|
||||
<< " Disposition: " << disposition_status_color(result.disposition) << to_string(result.disposition, true) << SHELL_COLOR_END() << "\n\n";
|
||||
<< " Provider: " << SHELL_COLOR_BRIGHT() << library::to_string(result.provider, true) << SHELL_COLOR_END() << "\n"
|
||||
<< " OperationKind: " << SHELL_COLOR_BRIGHT() << library::to_string(result.op_kind) << SHELL_COLOR_END() << "\n"
|
||||
<< " Operation: " << result.operation_name << "\n\n"
|
||||
<< " Status: " << SHELL_COLOR_BRIGHT() << library::to_string(result.status, true) << SHELL_COLOR_END() << "\n"
|
||||
<< " Verification: " << SHELL_COLOR_BRIGHT() << (options_.verification.enabled ? "ON":"OFF") << SHELL_COLOR_END() << "\n"
|
||||
<< " Disposition: " << disposition_status_color(result.disposition) << to_string(result.disposition, true) << SHELL_COLOR_END() << "\n\n";
|
||||
|
||||
// Display individual verification results for each verification-provider
|
||||
if (options_.verification.enabled) {
|
||||
|
||||
static int const indent_spaces = 22;
|
||||
static int const indent_spaces = 16;
|
||||
|
||||
for(auto & m : result.verification_map) {
|
||||
out << std::right << std::setw(indent_spaces) << library::to_string(m.first, true) << ": " << to_string(m.second, true) << "\n";
|
||||
@@ -212,15 +216,15 @@ std::ostream & PerformanceReport::print_result_pretty_(
|
||||
}
|
||||
|
||||
out
|
||||
<< "\n Arguments: ";
|
||||
<< "\n Arguments:";
|
||||
|
||||
int column_idx = 0;
|
||||
for (auto const &arg : result.arguments) {
|
||||
if (!arg.second.empty()) {
|
||||
out << " --" << arg.first << "=" << arg.second;
|
||||
column_idx += int(4 + arg.first.size() + arg.second.size());
|
||||
if (column_idx > 90) {
|
||||
out << " \\\n ";
|
||||
if (column_idx > 98) {
|
||||
out << " \\\n ";
|
||||
column_idx = 0;
|
||||
}
|
||||
}
|
||||
@@ -228,15 +232,15 @@ std::ostream & PerformanceReport::print_result_pretty_(
|
||||
out << "\n\n";
|
||||
|
||||
out
|
||||
<< " Bytes: " << result.bytes << " bytes\n"
|
||||
<< " FLOPs: " << result.flops << " flops\n\n";
|
||||
<< " Bytes: " << result.bytes << " bytes\n"
|
||||
<< " FLOPs: " << result.flops << " flops\n\n";
|
||||
|
||||
if (result.good()) {
|
||||
|
||||
out
|
||||
<< " Runtime: " << result.runtime << " ms\n"
|
||||
<< " Memory: " << result.gbytes_per_sec() << " GiB/s\n"
|
||||
<< "\n Math: " << result.gflops_per_sec() << " GFLOP/s\n";
|
||||
<< " Runtime: " << result.runtime << " ms\n"
|
||||
<< " Memory: " << result.gbytes_per_sec() << " GiB/s\n"
|
||||
<< "\n Math: " << result.gflops_per_sec() << " GFLOP/s\n";
|
||||
|
||||
}
|
||||
|
||||
@@ -256,7 +260,7 @@ std::ostream & PerformanceReport::print_csv_header_(
|
||||
|
||||
out
|
||||
<< (column_idx ? "," : "") << "Problem,Provider"
|
||||
<< ",Operation,Disposition,Status";
|
||||
<< ",OperationKind,Operation,Disposition,Status";
|
||||
|
||||
for (auto const &arg_name : argument_names_) {
|
||||
out << "," << arg_name;
|
||||
@@ -289,6 +293,7 @@ std::ostream & PerformanceReport::print_result_csv_(
|
||||
<< (column_idx ? "," : "")
|
||||
<< result.problem_index
|
||||
<< "," << to_string(result.provider, true)
|
||||
<< "," << to_string(result.op_kind)
|
||||
<< "," << result.operation_name
|
||||
<< "," << to_string(result.disposition)
|
||||
<< "," << library::to_string(result.status);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2020, 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.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
/* \file
|
||||
\brief
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "cutlass/cutlass.h"
|
||||
|
||||
// CUTLASS Profiler includes
|
||||
#include "enumerated_types.h"
|
||||
#include "performance_result.h"
|
||||
|
||||
// CUTLASS Library includes
|
||||
#include "cutlass/library/library.h"
|
||||
#include "cutlass/library/util.h"
|
||||
|
||||
namespace cutlass {
|
||||
namespace profiler {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace profiler
|
||||
} // namespace cutlass
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -65,7 +65,7 @@ struct PerformanceResult {
|
||||
/// Outcome of verification (all verification results)
|
||||
DispositionMap verification_map;
|
||||
|
||||
/// Operation object
|
||||
/// Operation name
|
||||
std::string operation_name;
|
||||
|
||||
/// Stringified vector of argument values
|
||||
@@ -119,3 +119,4 @@ using PerformanceResultVector = std::vector<PerformanceResult>;
|
||||
|
||||
} // namespace profiler
|
||||
} // namespace cutlass
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -849,6 +849,47 @@ bool arg_as_OpcodeClassID(
|
||||
return arg_as_OpcodeClassID(opcode_class, value_ptr);
|
||||
}
|
||||
|
||||
|
||||
/// Lexically casts an argument to an int64 if it is defined. Returns true if not null.
|
||||
bool arg_as_SplitKModeID(
|
||||
library::SplitKMode &split_k_mode,
|
||||
KernelArgument::Value const *value_ptr) {
|
||||
|
||||
if (value_ptr->not_null) {
|
||||
if (value_ptr->argument->description->type == ArgumentTypeID::kEnumerated) {
|
||||
|
||||
split_k_mode = library::from_string<library::SplitKMode>(
|
||||
static_cast<EnumeratedTypeArgument::EnumeratedTypeValue const *>(value_ptr)->element);
|
||||
|
||||
if (split_k_mode == library::SplitKMode::kInvalid) {
|
||||
throw std::runtime_error(
|
||||
"arg_as_SplitKModeID() - illegal cast.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
throw std::runtime_error(
|
||||
"arg_as_SplitKModeID() - illegal cast.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Lexically casts an argument to an int64 if it is defined. Returns true if not null.
|
||||
bool arg_as_SplitKModeID(
|
||||
library::SplitKMode &split_k_mode,
|
||||
char const *name,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem) {
|
||||
|
||||
size_t idx = problem_space.argument_index(name);
|
||||
KernelArgument::Value const *value_ptr = problem.at(idx).get();
|
||||
|
||||
return arg_as_SplitKModeID(split_k_mode, value_ptr);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Lexically casts an argument to a given type stored in a byte array. Returns true if not null.
|
||||
bool arg_as_scalar(
|
||||
@@ -939,7 +980,6 @@ bool tensor_description_satisfies(
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace profiler
|
||||
} // namespace cutlass
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -811,6 +811,17 @@ bool arg_as_OpcodeClassID(
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
|
||||
/// Lexically casts an argument to an int64 if it is defined. Returns true if not null.
|
||||
bool arg_as_SplitKModeID(library::SplitKMode &split_k_mode, KernelArgument::Value const *value_ptr);
|
||||
|
||||
/// Lexically casts an argument to an int64 if it is defined. Returns true if not null.
|
||||
bool arg_as_SplitKModeID(
|
||||
library::SplitKMode &split_k_mode,
|
||||
char const *name,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Lexically casts an argument to a given type stored in a byte array. Returns true if not null.
|
||||
bool arg_as_scalar(
|
||||
std::vector<uint8_t> &bytes,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
# Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2011-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2011-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are not permitted.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2011-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2011-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are not permitted.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2011-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2011-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are not permitted.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2020, 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.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
/* \file
|
||||
\brief Defines device-side elementwise operations on TensorView. Note, the operations defined
|
||||
in this header are not specialized for any particular data layout and are therefore not
|
||||
intended to offer the best possible performance. Rather, they are intended to be generic
|
||||
reference implementations to support the CUTLASS unit tests.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Cutlass includes
|
||||
#include "cutlass/cutlass.h"
|
||||
#include "cutlass/tensor_view.h"
|
||||
|
||||
#include "cutlass/util/reference/device/tensor_foreach.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace cutlass {
|
||||
namespace reference {
|
||||
namespace device {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <
|
||||
typename Element, ///< Element type
|
||||
typename Layout> ///< Layout function
|
||||
struct TensorReLuFunc {
|
||||
|
||||
/// View type
|
||||
using TensorView = TensorView<Element, Layout>;
|
||||
|
||||
/// Coordinate in tensor's index space
|
||||
using TensorCoord = typename TensorView::TensorCoord;
|
||||
|
||||
/// Parameters structure
|
||||
struct Params {
|
||||
|
||||
//
|
||||
// Data members
|
||||
//
|
||||
|
||||
TensorView view;
|
||||
Element threshold;
|
||||
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
Params(
|
||||
TensorView view_ = TensorView(),
|
||||
Element threshold_ = Element(0)
|
||||
):
|
||||
view(view_), threshold(threshold_) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Data members
|
||||
//
|
||||
|
||||
Params params;
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
CUTLASS_DEVICE
|
||||
TensorReLuFunc(Params const ¶ms): params(params) {
|
||||
|
||||
}
|
||||
|
||||
CUTLASS_DEVICE
|
||||
void operator()(TensorCoord const &coord) {
|
||||
|
||||
Element const & value = params.view.at(coord);
|
||||
params.view.at(coord) = (value < params.threshold) ? params.threshold : value;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Apply ReLu on a tensor
|
||||
template <
|
||||
typename Element, ///< Element type
|
||||
typename Layout> ///< Layout function
|
||||
void TensorReLu(
|
||||
TensorView<Element, Layout> view, ///< destination tensor
|
||||
Element threshold = Element(0)) { ///< ReLu threshold
|
||||
|
||||
using Func = detail::TensorReLuFunc<Element, Layout>;
|
||||
using Params = typename Func::Params;
|
||||
|
||||
TensorForEach<Func, Layout::kRank, Params>(
|
||||
view.extent(),
|
||||
Params(view, threshold)
|
||||
);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace device
|
||||
} // namespace reference
|
||||
} // namespace cutlass
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
@@ -37,11 +37,41 @@
|
||||
#include "cutlass/tensor_view.h"
|
||||
#include "cutlass/gemm/gemm.h"
|
||||
#include "cutlass/arch/mma.h"
|
||||
#include "cutlass/util/host_tensor.h"
|
||||
|
||||
namespace cutlass {
|
||||
namespace reference {
|
||||
namespace host {
|
||||
|
||||
template<typename Out, typename In>
|
||||
struct CastIfScalar {
|
||||
static Out cast(In in) {
|
||||
return Out(in);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename OutScalar, typename In>
|
||||
struct CastIfScalar<cutlass::complex<OutScalar>, In> {
|
||||
typedef cutlass::complex<OutScalar> Out;
|
||||
static Out cast(In in) {
|
||||
return Out(static_cast<OutScalar>(in));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename OutScalar, typename InScalar>
|
||||
struct CastIfScalar<cutlass::complex<OutScalar>, cutlass::complex<InScalar>> {
|
||||
typedef cutlass::complex<OutScalar> Out;
|
||||
typedef cutlass::complex<InScalar> In;
|
||||
static Out cast(In in) {
|
||||
return Out(in);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Out, typename In>
|
||||
Out cast_if_scalar(In in) {
|
||||
return CastIfScalar<Out, In>::cast(in);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Computes a general matrix product among matrices (tensors of rank=2) pointed to by TensorRef
|
||||
@@ -107,7 +137,10 @@ void compute_gemm(
|
||||
ElementA a = tensor_a.at(MatrixCoord(row, k_block));
|
||||
ElementB b = tensor_b.at(MatrixCoord(k_block, col));
|
||||
|
||||
accum[i][j] = inner_product_op(ComputeType(a), ComputeType(b), accum[i][j]);
|
||||
ComputeType compute_a(cast_if_scalar<ComputeType>(a));
|
||||
ComputeType compute_b(cast_if_scalar<ComputeType>(b));
|
||||
|
||||
accum[i][j] = inner_product_op(compute_a, compute_b, accum[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2020, 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:
|
||||
|
||||
Reference in New Issue
Block a user