commit
f94c6dc470
@ -0,0 +1 @@ |
|||||||
|
|
@ -0,0 +1,3 @@ |
|||||||
|
[submodule "kompute"] |
||||||
|
path = kompute |
||||||
|
url = https://github.com/KomputeProject/kompute/ |
@ -0,0 +1 @@ |
|||||||
|
Subproject commit 1d449daa11257442de6c6c9ffa48a587c3c92a68 |
@ -0,0 +1,3 @@ |
|||||||
|
*.spv |
||||||
|
*.comp |
||||||
|
test1 |
@ -0,0 +1,9 @@ |
|||||||
|
CPPFLAGS = -Wall -Wextra -g
|
||||||
|
# link kompute as a static library and the rest as dynamic
|
||||||
|
LDFLAGS = -L/usr/local/lib -Wl,-Bstatic -lkompute -lkp_logger -Wl,-Bdynamic -lvulkan -lfmt -Wl,--as-needed
|
||||||
|
|
||||||
|
test1: main.cpp |
||||||
|
g++ ${CPPFLAGS} main.cpp -o test1 ${LDFLAGS}
|
||||||
|
|
||||||
|
clean: |
||||||
|
rm -f test1
|
@ -0,0 +1,2 @@ |
|||||||
|
test1: |
||||||
|
simple sum, sum of two tensors |
@ -0,0 +1,70 @@ |
|||||||
|
#include <iostream> |
||||||
|
#include <memory> |
||||||
|
#include <vector> |
||||||
|
|
||||||
|
#include <kompute/Kompute.hpp> |
||||||
|
|
||||||
|
|
||||||
|
const std::string shader_code(R"(#version 450 |
||||||
|
// The execution structure
|
||||||
|
layout (local_size_x = 1) in; |
||||||
|
|
||||||
|
// The buffers are provided via the tensors
|
||||||
|
layout(binding = 0) buffer bufA { float a[]; }; |
||||||
|
layout(binding = 1) buffer bufB { float b[]; }; |
||||||
|
layout(binding = 2) buffer bufOut { float o[]; }; |
||||||
|
|
||||||
|
void main() { |
||||||
|
uint index = gl_GlobalInvocationID.x; |
||||||
|
o[index] = a[index] * b[index]; |
||||||
|
})"); |
||||||
|
|
||||||
|
|
||||||
|
static std::vector<uint32_t> compileSource(const std::string& source) |
||||||
|
{ |
||||||
|
std::ofstream fileOut("tmp_kp_shader.comp"); |
||||||
|
fileOut << source; |
||||||
|
fileOut.close(); |
||||||
|
if (system(std::string("glslangValidator -V tmp_kp_shader.comp -o tmp_kp_shader.comp.spv").c_str())) |
||||||
|
throw std::runtime_error("Error running glslangValidator command"); |
||||||
|
std::ifstream fileStream("tmp_kp_shader.comp.spv", std::ios::binary); |
||||||
|
std::vector<char> buffer; |
||||||
|
buffer.insert(buffer.begin(), std::istreambuf_iterator<char>(fileStream), {}); |
||||||
|
return {(uint32_t*)buffer.data(), (uint32_t*)(buffer.data() + buffer.size())}; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
int main() |
||||||
|
{ |
||||||
|
kp::Manager mgr; |
||||||
|
|
||||||
|
std::shared_ptr<kp::TensorT<float>> tensorInA = mgr.tensor({ 2.0, 4.0, 6.0 }); |
||||||
|
std::shared_ptr<kp::TensorT<float>> tensorInB = mgr.tensor({ 0.0, 1.0, 2.0 }); |
||||||
|
std::shared_ptr<kp::TensorT<float>> tensorOut = mgr.tensor({ 0.0, 0.0, 0.0 }); |
||||||
|
|
||||||
|
const std::vector<std::shared_ptr<kp::Tensor>> params = {
|
||||||
|
tensorInA, tensorInB, tensorOut |
||||||
|
}; |
||||||
|
|
||||||
|
const std::vector<uint32_t> shader = compileSource(shader_code); |
||||||
|
std::shared_ptr<kp::Algorithm> algo = mgr.algorithm(params, shader); |
||||||
|
|
||||||
|
mgr.sequence() |
||||||
|
->record<kp::OpTensorSyncDevice>(params) |
||||||
|
->record<kp::OpAlgoDispatch>(algo) |
||||||
|
->record<kp::OpTensorSyncLocal>(params) |
||||||
|
->eval(); |
||||||
|
|
||||||
|
// prints "Output { 0 4 12 }"
|
||||||
|
std::cout << "Output: { "; |
||||||
|
for (const float& elem : tensorOut->vector()) { |
||||||
|
std::cout << elem << " "; |
||||||
|
} |
||||||
|
std::cout << "}" << std::endl; |
||||||
|
|
||||||
|
if (tensorOut->vector() != std::vector<float>{ 0, 4, 12 }) { |
||||||
|
throw std::runtime_error("Result does not match"); |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
*.spv |
||||||
|
*.comp |
||||||
|
test1 |
@ -0,0 +1,9 @@ |
|||||||
|
CPPFLAGS = -Wall -Wextra -g
|
||||||
|
# link kompute as a static library and the rest as dynamic
|
||||||
|
LDFLAGS = -L/usr/local/lib -Wl,-Bstatic -lkompute -lkp_logger -Wl,-Bdynamic -lvulkan -lfmt -Wl,--as-needed
|
||||||
|
|
||||||
|
test2: main.cpp |
||||||
|
g++ ${CPPFLAGS} main.cpp -o test2 ${LDFLAGS}
|
||||||
|
|
||||||
|
clean: |
||||||
|
rm -f test2
|
@ -0,0 +1,2 @@ |
|||||||
|
test2: |
||||||
|
matrix multiplication |
@ -0,0 +1,158 @@ |
|||||||
|
#include <fstream> |
||||||
|
#include <iostream> |
||||||
|
#include <iterator> |
||||||
|
#include <memory> |
||||||
|
#include <regex> |
||||||
|
#include <sstream> |
||||||
|
#include <vector> |
||||||
|
|
||||||
|
#include <kompute/Kompute.hpp> |
||||||
|
#include <vulkan/vulkan_handles.hpp> |
||||||
|
|
||||||
|
|
||||||
|
static std::vector<uint32_t> compile_shader(const std::string& source) |
||||||
|
{ |
||||||
|
std::ofstream fileOut("tmp_kp_shader.comp"); |
||||||
|
fileOut << source; |
||||||
|
fileOut.close(); |
||||||
|
if (system(std::string("glslangValidator -V tmp_kp_shader.comp -o tmp_kp_shader.comp.spv").c_str())) |
||||||
|
throw std::runtime_error("Error running glslangValidator command"); |
||||||
|
std::ifstream fileStream("tmp_kp_shader.comp.spv", std::ios::binary); |
||||||
|
std::vector<char> buffer; |
||||||
|
buffer.insert(buffer.begin(), std::istreambuf_iterator<char>(fileStream), {}); |
||||||
|
return {(uint32_t*)buffer.data(), (uint32_t*)(buffer.data() + buffer.size())}; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static std::string shader_to_string(const char *path) |
||||||
|
{ |
||||||
|
std::ifstream comp_file; |
||||||
|
|
||||||
|
comp_file.open(path); |
||||||
|
if (comp_file.is_open() == false) { |
||||||
|
return std::string("// bad code"); |
||||||
|
} |
||||||
|
|
||||||
|
std::ostringstream outstr; |
||||||
|
outstr << comp_file.rdbuf(); |
||||||
|
return outstr.str(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// the sed replace command as a function
|
||||||
|
// 1. /pattern/replace/
|
||||||
|
// 2. /pattern//
|
||||||
|
static std::string regex_replace(const char *expr_string, std::string str) |
||||||
|
{ |
||||||
|
std::string expr(expr_string); |
||||||
|
std::string pattern, replace; |
||||||
|
|
||||||
|
if (expr.size() < 3 || expr[0] != '/' || expr.back() != '/') { |
||||||
|
return str; |
||||||
|
} else { |
||||||
|
// shift 1
|
||||||
|
expr = expr.substr(1, expr.size()-2); |
||||||
|
} |
||||||
|
for (size_t pos = 0, nxpos = 0; ; pos = nxpos) { |
||||||
|
nxpos = expr.find("/", pos); |
||||||
|
if (nxpos == std::string::npos) { |
||||||
|
break; |
||||||
|
} |
||||||
|
// skip escaped '/'
|
||||||
|
if (nxpos > 0 && expr[nxpos-1] == '\\') { |
||||||
|
if (nxpos > 1 && expr[nxpos-2] != '\\') { |
||||||
|
continue; |
||||||
|
} |
||||||
|
} |
||||||
|
pattern = expr.substr(0, nxpos); |
||||||
|
replace = expr.substr(nxpos+1); |
||||||
|
break; |
||||||
|
} |
||||||
|
if (pattern.empty()) { |
||||||
|
return str; |
||||||
|
} |
||||||
|
|
||||||
|
std::regex reg(pattern); |
||||||
|
std::string newstr = std::regex_replace(str, reg, replace); |
||||||
|
return newstr; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
template <typename T> std::string regex_subst(const char *expr, T val, std::string str) |
||||||
|
{ |
||||||
|
std::regex reg(expr); |
||||||
|
std::regex_match(); |
||||||
|
return newstr; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
int main() |
||||||
|
{ |
||||||
|
// create the kompute manager
|
||||||
|
kp::Manager mgr; |
||||||
|
|
||||||
|
// C = A*B
|
||||||
|
float matrixA[1024][1024] = {0}; |
||||||
|
float matrixB[1024][1024] = {0}; |
||||||
|
float matrixC[1024][1024] = {0}; |
||||||
|
// fill an identity matrix
|
||||||
|
for (int y = 0; y < 1024; y++) { |
||||||
|
matrixA[y][y] = 1.0; |
||||||
|
} |
||||||
|
// fill a matrix with data
|
||||||
|
for (int y = 0; y < 1024; y++) { |
||||||
|
for (int x = 0; x < 1024; x++) { |
||||||
|
matrixB[y][x] = x*0.74 - y*0.22; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// create the tensors, tensors are just arrays, in the shader we will have
|
||||||
|
// to describe how it translates to matrices
|
||||||
|
kp::Tensor::TensorDataTypes dtype = kp::Tensor::TensorDataTypes::eFloat; |
||||||
|
|
||||||
|
// auto because fuck C++
|
||||||
|
auto tensorA = mgr.tensor(matrixA, 1024*1024, sizeof(float), dtype); |
||||||
|
auto tensorB = mgr.tensor(matrixB, 1024*1024, sizeof(float), dtype); |
||||||
|
auto tensorC = mgr.tensor(matrixC, 1024*1024, sizeof(float), dtype); |
||||||
|
|
||||||
|
const std::vector<std::shared_ptr<kp::Tensor>> params = { |
||||||
|
tensorA, tensorB, tensorC |
||||||
|
}; |
||||||
|
|
||||||
|
// workgroup, dispatch a 2D array of workgroups (2D matrices)
|
||||||
|
// TODO: determine the size of the workgroups by doing some calls to vk
|
||||||
|
const int wgrp_x = 32, wgrp_y = 32; |
||||||
|
// this should call vkCmdDispatch(x, y, z)
|
||||||
|
kp::Workgroup workgroup({wgrp_x, wgrp_y, 1}); |
||||||
|
|
||||||
|
// substitute the values in the shader
|
||||||
|
const char *shader_path = "shader.comp"; |
||||||
|
std::string shader_str = shader_to_string(shader_path); |
||||||
|
shader_str = regex_replace("/{lcsize_x}/", shader_str); |
||||||
|
const std::vector<uint32_t> shader = compile_shader(shader_to_string("shader.comp")); |
||||||
|
|
||||||
|
|
||||||
|
std::shared_ptr<kp::Algorithm> algo = mgr.algorithm( |
||||||
|
params, |
||||||
|
shader, |
||||||
|
workgroup, |
||||||
|
{1024.0} |
||||||
|
); |
||||||
|
|
||||||
|
mgr.sequence() |
||||||
|
->record<kp::OpTensorSyncDevice>(params) |
||||||
|
->record<kp::OpAlgoDispatch>(algo) |
||||||
|
->record<kp::OpTensorSyncLocal>(params) |
||||||
|
->eval(); |
||||||
|
|
||||||
|
|
||||||
|
// print the resulting matrix
|
||||||
|
std::cout << "Output: { "; |
||||||
|
for (const float& elem : tensorC->vector<float>()) { |
||||||
|
printf("%.2f, ", elem); |
||||||
|
} |
||||||
|
std::cout << "}" << std::endl; |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
Binary file not shown.
Loading…
Reference in new issue