Added first version of a tuner for the ConvGemm direct kernel

pull/343/head
Cedric Nugteren 2018-07-29 15:07:51 +02:00 committed by Koichi Akabe
parent 301dc280df
commit 1f0cd61824
5 changed files with 242 additions and 3 deletions

View File

@ -213,6 +213,7 @@ endif()
# Sets the supported routines and the used kernels. New routines and kernels should be added here.
set(KERNELS copy_fast copy_pad transpose_fast transpose_pad xaxpy xdot xger
xgemm xgemm_direct xgemv invert)
set(KERNELS_EXTRA xconvgemm) # kernels for which not to include a tuner in 'all tuners' target
set(DATABASES copy pad padtranspose transpose xaxpy xdot
xgemm xgemm_direct xgemv xgemv_fast xgemv_fast_rot xger invert
gemm_routine trsv_routine)
@ -434,7 +435,8 @@ if(TUNERS)
endif()
# Adds tuning executables
foreach(KERNEL ${KERNELS})
set(ALLKERNELS ${KERNELS} ${KERNELS_EXTRA})
foreach(KERNEL ${ALLKERNELS})
add_executable(clblast_tuner_${KERNEL} ${TUNERS_COMMON} src/tuning/kernels/${KERNEL}.cpp)
target_link_libraries(clblast_tuner_${KERNEL} ${API_LIBRARIES})
target_include_directories(clblast_tuner_${KERNEL} PUBLIC $<TARGET_PROPERTY:clblast,INTERFACE_INCLUDE_DIRECTORIES> ${API_INCLUDE_DIRS})

View File

@ -0,0 +1,38 @@
// =================================================================================================
// This file is part of the CLBlast project. The project is licensed under Apache Version 2.0. This
// project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max-
// width of 100 characters per line.
//
// Author(s):
// Cedric Nugteren <www.cedricnugteren.nl>
//
// This file uses the auto-tuner to tune the convgemm kernels.
//
// =================================================================================================
#include "tuning/kernels/xconvgemm.hpp"
// Shortcuts to the clblast namespace
using half = clblast::half;
using float2 = clblast::float2;
using double2 = clblast::double2;
// Function to tune a specific variation V (not within the clblast namespace)
template <int V>
void StartVariation(int argc, char *argv[]) {
const auto command_line_args = clblast::RetrieveCommandLineArguments(argc, argv);
switch(clblast::GetPrecision(command_line_args)) {
case clblast::Precision::kHalf: clblast::Tuner<half>(argc, argv, V, clblast::XConvGemmGetTunerDefaults, clblast::XConvGemmGetTunerSettings<half>, clblast::XConvGemmTestValidArguments<half>, clblast::XConvGemmSetConstraints, clblast::XConvGemmComputeLocalMemSize<half>, clblast::XConvGemmSetArguments<half>); break;
case clblast::Precision::kSingle: clblast::Tuner<float>(argc, argv, V, clblast::XConvGemmGetTunerDefaults, clblast::XConvGemmGetTunerSettings<float>, clblast::XConvGemmTestValidArguments<float>, clblast::XConvGemmSetConstraints, clblast::XConvGemmComputeLocalMemSize<float>, clblast::XConvGemmSetArguments<float>); break;
case clblast::Precision::kDouble: clblast::Tuner<double>(argc, argv, V, clblast::XConvGemmGetTunerDefaults, clblast::XConvGemmGetTunerSettings<double>, clblast::XConvGemmTestValidArguments<double>, clblast::XConvGemmSetConstraints, clblast::XConvGemmComputeLocalMemSize<double>, clblast::XConvGemmSetArguments<double>); break;
}
}
// Main function (not within the clblast namespace)
int main(int argc, char *argv[]) {
StartVariation<1>(argc, argv);
return 0;
}
// =================================================================================================

View File

@ -0,0 +1,186 @@
// =================================================================================================
// This file is part of the CLBlast project. The project is licensed under Apache Version 2.0. This
// project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max-
// width of 100 characters per line.
//
// Author(s):
// Cedric Nugteren <www.cedricnugteren.nl>
//
// This file uses the auto-tuner to tune the ConvGemm kernels. These kernels are based on the GEMM
// direct kernel and will use those parameters, this tuner is just optional to use for advanced
// users.
//
// =================================================================================================
#include <string>
#include <vector>
#include "utilities/utilities.hpp"
#include "tuning/tuning.hpp"
namespace clblast {
// =================================================================================================
// Helper functions
template <typename T>
size_t OutputHeight(const Arguments<T> &args) {
const auto size = args.height + 2 * args.pad_h;
const auto padding = args.dilation_h * (args.kernel_h - 1) + 1;
if (size >= padding) { return (size - padding) / args.stride_h + 1; }
return 1;
}
template <typename T>
size_t OutputWidth(const Arguments<T> &args) {
const auto size = args.width + 2 * args.pad_w;
const auto padding = args.dilation_w * (args.kernel_w - 1) + 1;
if (size >= padding) { return (size - padding) / args.stride_w + 1; }
return 1;
}
// Settings for this kernel (default command-line arguments)
TunerDefaults XConvGemmGetTunerDefaults(const int) {
auto settings = TunerDefaults();
settings.options = {kArgChannels, kArgHeight, kArgWidth, kArgKernelH, kArgKernelW,
kArgNumKernels, kArgBatchCount, kArgFraction};
settings.channels = 32;
settings.height = 64;
settings.width = 64;
settings.kernel_h = 3;
settings.kernel_w = 3;
settings.num_kernels = 32;
settings.default_batch_count = 16;
settings.default_fraction = 1.0;
settings.default_num_runs = 2;
return settings;
}
// Settings for this kernel (general)
template <typename T>
TunerSettings XConvGemmGetTunerSettings(const int, const Arguments<T> &args) {
auto settings = TunerSettings();
// Identification of the kernel
settings.kernel_family = "xconvgemm";
settings.kernel_name = "Xconvgemm";
settings.sources =
"#define ROUTINE_CONVGEMM"
#include "../src/kernels/level3/xgemm_direct_part1.opencl"
#include "../src/kernels/level3/xgemm_direct_part2.opencl"
#include "../src/kernels/level3/xgemm_direct_part3.opencl"
#include "../src/kernels/levelx/xconvgemm_part1.opencl"
#include "../src/kernels/levelx/xconvgemm_part2.opencl"
;
// Helper variables
const auto patch_size = args.kernel_h * args.kernel_w * args.channels;
const auto num_patches = OutputHeight(args) * OutputWidth(args);
// Buffer sizes
settings.size_a = args.batch_count * args.channels * args.height * args.width;
settings.size_b = args.num_kernels * args.channels * args.kernel_h * args.kernel_w;
settings.size_a = args.batch_count * args.num_kernels * OutputHeight(args) * OutputWidth(args);
// Inputs and outputs IDs (X:0, Y:1, A:2, B:3, C:4, temp:5)
settings.inputs = {2, 3, 4};
settings.outputs = {4};
// Sets the base thread configuration
settings.global_size = {num_patches, args.num_kernels};
settings.global_size_ref = settings.global_size;
settings.local_size = {1, 1};
settings.local_size_ref = {8, 8};
// Transforms the thread configuration based on the parameters
settings.mul_local = {{"MDIMCD", "NDIMCD"}};
settings.mul_global = {{"MDIMCD", "NDIMCD"}};
settings.div_global = {{"WGD", "WGD"}};
// Sets the tuning parameters and their possible values
settings.parameters = {
{"WGD", {8, 16, 32}},
{"MDIMCD", {8, 16, 32}},
{"NDIMCD", {8, 16, 32}},
{"MDIMAD", {8, 16, 32}},
{"NDIMBD", {8, 16, 32}},
{"KWID", {1}},
{"VWMD", {1, 2, 4, 8}},
{"VWND", {1, 2, 4, 8}},
{"PADA", {0}},
{"PADB", {0}},
};
// Describes how to compute the performance metrics
settings.metric_amount = args.batch_count * 2 * num_patches * args.num_kernels * patch_size;
settings.performance_unit = "GFLOPS";
return settings;
}
// Tests for valid arguments
template <typename T>
void XConvGemmTestValidArguments(const int, const Arguments<T> &) { }
std::vector<Constraint> XConvGemmSetConstraints(const int) {
auto constraints = std::vector<Constraint>();
auto MultipleOfX = [] (std::vector<size_t> v) { return IsMultiple(v[0], v[1]); };
auto MultipleOfXMulY = [] (std::vector<size_t> v) { return IsMultiple(v[0], v[1]*v[2]); };
auto MultipleOfXMulYDivZ = [] (std::vector<size_t> v) { return IsMultiple(v[0], (v[1]*v[2])/v[3]); };
// Requirement for unrolling the WGD loop
constraints.push_back({MultipleOfX, {"WGD", "KWID"}});
// Required for integer MWID and NWID
constraints.push_back({MultipleOfXMulY, {"WGD", "MDIMCD", "VWMD"}});
constraints.push_back({MultipleOfXMulY, {"WGD", "NDIMCD", "VWND"}});
// Required for integer MWIAD and NWIBD
constraints.push_back({MultipleOfXMulY, {"WGD", "MDIMAD", "VWMD"}});
constraints.push_back({MultipleOfXMulY, {"WGD", "NDIMBD", "VWND"}});
// WGD has to be a multiple of KDIMAD = ((MDIMCD*NDIMCD)/(MDIMAD)) and KDIMBD = (...)
constraints.push_back({MultipleOfXMulYDivZ, {"WGD", "MDIMCD", "NDIMCD", "MDIMAD"}});
constraints.push_back({MultipleOfXMulYDivZ, {"WGD", "MDIMCD", "NDIMCD", "NDIMBD"}});
return constraints;
}
template <typename T>
LocalMemSizeInfo XConvGemmComputeLocalMemSize(const int) {
return {
[] (std::vector<size_t> v) -> size_t {
return GetBytes(PrecisionValue<T>()) * ((v[0]*(v[0] + v[1]) + v[0]*(v[0] + v[2])));
},
{"WGD", "PADA", "PADB"}
};
}
// Sets the kernel's arguments
template <typename T>
void XConvGemmSetArguments(const int, Kernel &kernel, const Arguments<T> &args, std::vector<Buffer<T>>& buffers) {
const auto output_h = OutputHeight(args);
const auto output_w = OutputWidth(args);
const auto patch_size = args.kernel_h * args.kernel_w * args.channels;
const auto num_patches = output_h * output_w;
const auto result_stride = args.num_kernels * output_h * output_w;
kernel.SetArgument(0, static_cast<int>(num_patches));
kernel.SetArgument(1, static_cast<int>(args.num_kernels));
kernel.SetArgument(2, static_cast<int>(patch_size));
kernel.SetArgument(3, buffers[3]()); // 3 == B matrix ==> kernel buffer
kernel.SetArgument(4, 0); // c_offset
kernel.SetArgument(5, buffers[4]()); // 4 == C matrix ==> result buffer
kernel.SetArgument(6, 0); // c_offset
kernel.SetArgument(7, static_cast<int>(result_stride));
kernel.SetArgument(8, buffers[2]()); // 2 == A matrix ==> image buffer
kernel.SetArgument(9, 0); // c_offset
kernel.SetArgument(10, static_cast<int>(args.height));
kernel.SetArgument(11, static_cast<int>(args.width));
kernel.SetArgument(12, static_cast<int>(args.channels));
kernel.SetArgument(13, static_cast<int>(args.kernel_h));
kernel.SetArgument(14, static_cast<int>(args.kernel_w));
kernel.SetArgument(15, 0); // pad_h
kernel.SetArgument(16, 0); // pad_w
kernel.SetArgument(17, 1); // stride_h
kernel.SetArgument(18, 1); // stride_w
kernel.SetArgument(19, 1); // dilation_h
kernel.SetArgument(20, 1); // dilation_w
kernel.SetArgument(21, static_cast<int>(output_h));
kernel.SetArgument(22, static_cast<int>(output_w));
}
// =================================================================================================
} // namespace clblast

View File

@ -122,8 +122,14 @@ void Tuner(int argc, char* argv[], const int V,
if (o == kArgM) { args.m = GetArgument(command_line_args, help, kArgM, defaults.default_m); }
if (o == kArgN) { args.n = GetArgument(command_line_args, help, kArgN, defaults.default_n); }
if (o == kArgK) { args.k = GetArgument(command_line_args, help, kArgK, defaults.default_k); }
if (o == kArgAlpha) { args.alpha = GetArgument(command_line_args, help, kArgAlpha, GetScalar<T>()); }
if (o == kArgBeta) { args.beta = GetArgument(command_line_args, help, kArgBeta, GetScalar<T>()); }
if (o == kArgChannels) { args.channels = GetArgument(command_line_args, help, kArgChannels, defaults.channels); }
if (o == kArgHeight) { args.height = GetArgument(command_line_args, help, kArgHeight, defaults.height); }
if (o == kArgWidth) { args.width = GetArgument(command_line_args, help, kArgWidth, defaults.width); }
if (o == kArgKernelH) { args.kernel_h = GetArgument(command_line_args, help, kArgKernelH, defaults.kernel_h); }
if (o == kArgKernelW) { args.kernel_w = GetArgument(command_line_args, help, kArgKernelW, defaults.kernel_w); }
if (o == kArgNumKernels) { args.num_kernels = GetArgument(command_line_args, help, kArgNumKernels, defaults.num_kernels); }
if (o == kArgAlpha) { args.alpha = GetArgument(command_line_args, help, kArgAlpha, GetScalar<T>()); }
if (o == kArgBeta) { args.beta = GetArgument(command_line_args, help, kArgBeta, GetScalar<T>()); }
if (o == kArgBatchCount) { args.batch_count = GetArgument(command_line_args, help, kArgBatchCount, defaults.default_batch_count); }
}
args.fraction = GetArgument(command_line_args, help, kArgFraction, defaults.default_fraction);

View File

@ -41,6 +41,13 @@ struct TunerDefaults {
size_t default_m = 1;
size_t default_n = 1;
size_t default_k = 1;
size_t channels = 1;
size_t height = 1;
size_t width = 1;
size_t kernel_h = 3;
size_t kernel_w = 3;
size_t num_kernels = 1;
size_t batch_count = 1;
// Other defaults
size_t default_batch_count = 1;