Skip to content

Commit

Permalink
Test case for a trivial example kernel extension.
Browse files Browse the repository at this point in the history
- Created a small example extension that is built and used as a test case.
  - The build of the extension is isolated from the DAPHNE build on purpose, since DAPHNE extensions can be separate code bases.
  - Thus, building/cleaning the extension is part of the test case itself.
- Added a CLI arg for adding a kernel extension to DAPHNE at runtime.
  - DAPHNE does not need to be re-built to use the extension.
- Slightly changed a few files in "src/runtime/local/datastructures/" by moving problematic includes from header to source files etc., in order to make including a few DAPHNE headers in the extension easy.
  - In the future, this aspect will need more attention.
  • Loading branch information
pdamme committed Apr 19, 2024
1 parent 027e89f commit e6397e8
Show file tree
Hide file tree
Showing 16 changed files with 236 additions and 18 deletions.
6 changes: 6 additions & 0 deletions src/api/internal/daphne_internal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,10 @@ int startDAPHNE(int argc, const char** argv, DaphneLibResult* daphneLibRes, int
"mlir-hybrid-codegen", cat(daphneOptions),
desc("Enables prototypical hybrid code generation combining pre-compiled kernels and MLIR code generation.")
);
static opt<string> kernelExt(
"kernel-ext", cat(daphneOptions),
desc("Additional kernel extension to register (path to a kernel catalog JSON file).")
);

enum ExplainArgs {
kernels,
Expand Down Expand Up @@ -533,6 +537,8 @@ int startDAPHNE(int argc, const char** argv, DaphneLibResult* daphneLibRes, int
if(user_config.use_cuda)
kcp.parseKernelCatalog(user_config.libdir + "/CUDAcatalog.json", kc);
// kc.dump();
if(!kernelExt.empty())
kcp.parseKernelCatalog(kernelExt, kc);

// ************************************************************************
// Parse, compile and execute DaphneDSL script
Expand Down
1 change: 1 addition & 0 deletions src/runtime/local/datastructures/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ add_library(DataStructures
DenseMatrix.cpp
CSRMatrix.cpp
Frame.cpp
Structure.cpp
IAllocationDescriptor.h
MetaDataObject.h
MetaDataObject.cpp
Expand Down
1 change: 1 addition & 0 deletions src/runtime/local/datastructures/DenseMatrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

#include <runtime/local/datastructures/AllocationDescriptorHost.h>
#include <runtime/local/io/DaphneSerializer.h>
#include "DenseMatrix.h"

Expand Down
1 change: 0 additions & 1 deletion src/runtime/local/datastructures/DenseMatrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

#pragma once

#include <runtime/local/datastructures/AllocationDescriptorHost.h>
#include <runtime/local/datastructures/DataObjectFactory.h>
#include <runtime/local/datastructures/Matrix.h>
#include <runtime/local/datastructures/ValueTypeUtils.h>
Expand Down
1 change: 1 addition & 0 deletions src/runtime/local/datastructures/MetaDataObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

#include "DataPlacement.h"
#include "MetaDataObject.h"

DataPlacement* MetaDataObject::addDataPlacement(const IAllocationDescriptor *allocInfo, Range *r) {
Expand Down
3 changes: 2 additions & 1 deletion src/runtime/local/datastructures/MetaDataObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@

#pragma once

#include "DataPlacement.h"
class DataPlacement;
#include "IAllocationDescriptor.h"
#include "Range.h"

#include <algorithm>
Expand Down
36 changes: 36 additions & 0 deletions src/runtime/local/datastructures/Structure.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2024 The DAPHNE Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <runtime/local/datastructures/Structure.h>
#include <runtime/local/datastructures/DataPlacement.h>

Structure::Structure(size_t numRows, size_t numCols) : refCounter(1), numRows(numRows), numCols(numCols) {
mdo = std::make_shared<MetaDataObject>();
};

void Structure::clone_mdo(const Structure* src) {
// FIXME: This clones the meta data to avoid locking (thread synchronization for data copy)
for(int i = 0; i < static_cast<int>(ALLOCATION_TYPE::NUM_ALLOC_TYPES); i++) {
auto placements = src->mdo->getDataPlacementByType(static_cast<ALLOCATION_TYPE>(i));
for(auto it = placements->begin(); it != placements->end(); it++) {
auto src_alloc = it->get()->allocation.get();
auto src_range = it->get()->range.get();
auto new_data_placement = this->mdo->addDataPlacement(src_alloc, src_range);
if(src->mdo->isLatestVersion(it->get()->dp_id))
this->mdo->addLatest(new_data_placement->dp_id);
}
}
}
19 changes: 3 additions & 16 deletions src/runtime/local/datastructures/Structure.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,25 +42,12 @@ class Structure
size_t numRows;
size_t numCols;

Structure(size_t numRows, size_t numCols) : refCounter(1), numRows(numRows), numCols(numCols) {
mdo = std::make_shared<MetaDataObject>();
};
Structure(size_t numRows, size_t numCols);

mutable std::shared_ptr<MetaDataObject> mdo;

void clone_mdo(const Structure* src) {
// FIXME: This clones the meta data to avoid locking (thread synchronization for data copy)
for(int i = 0; i < static_cast<int>(ALLOCATION_TYPE::NUM_ALLOC_TYPES); i++) {
auto placements = src->mdo->getDataPlacementByType(static_cast<ALLOCATION_TYPE>(i));
for(auto it = placements->begin(); it != placements->end(); it++) {
auto src_alloc = it->get()->allocation.get();
auto src_range = it->get()->range.get();
auto new_data_placement = this->mdo->addDataPlacement(src_alloc, src_range);
if(src->mdo->isLatestVersion(it->get()->dp_id))
this->mdo->addLatest(new_data_placement->dp_id);
}
}
}
void clone_mdo(const Structure* src);

public:
virtual ~Structure() = default;

Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ set(TEST_SOURCES
api/cli/expressions/CastTest.cpp
api/cli/expressions/CondTest.cpp
api/cli/expressions/MatrixLiteralTest.cpp
api/cli/extensibility/ExtensionTest.cpp
api/cli/extensibility/HintTest.cpp
api/cli/functions/FunctionsTest.cpp
api/cli/functions/RecursiveFunctionsTest.cpp
Expand Down
84 changes: 84 additions & 0 deletions test/api/cli/extensibility/ExtensionTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright 2024 The DAPHNE Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <api/cli/Utils.h>

#include <tags.h>

#include <catch.hpp>

#include <sstream>
#include <string>

const std::string dirPath = "test/api/cli/extensibility/";

TEST_CASE("extension_kernel", TAG_EXTENSIBILITY) {
int status = -1;
std::stringstream out;
std::stringstream err;

std::string extDir = std::string(dirPath + "kernel_extension_test");

// *************************************************************************
// Build the custom kernel extension.
// *************************************************************************
// The extension's build process is on purpose isolated from DAPHNE's build
// process, since extensions are developed in stand-alone code bases and
// exactly that shall be tested here.
// We use ninja as the build system, since ninja is anyway required in the
// DAPHNE development environment. It would also work with make, but make
// would create an additional dependency.
status = runProgram(out, err, "ninja", "ninja", "-C", extDir.c_str());
if(status) {
// We don't expect any specifc output from ninja, but only if ninja failed,
// we want to see what it printed to stdout and stderr.
CHECK(out.str() == "");
CHECK(err.str() == "");
}
// Don't continue in case the build of the extension failed.
REQUIRE(status == 0);

// *************************************************************************
// Use the custom kernel extension.
// *************************************************************************
// Run a DaphneDSL script which uses a kernel from the extension through a
// kernel hint. The extension is registered with DAPHNE at run-time. DAPHNE
// itself is not re-built or anything.
compareDaphneToStr(
"hello from mySumAll\n2\n",
std::string(dirPath + "extension_kernel_usage.daphne").c_str(),
"--kernel-ext",
std::string(dirPath + "kernel_extension_test/myKernels.json").c_str()
);

// Clear the streams.
out.clear();
err.clear();

// *************************************************************************
// Clean the build of the custom kernel extension.
// *************************************************************************
// Such that the next invocation of this test case needs to build the extension
// again, thereby testing again if the extension can be built successfully.
status = runProgram(out, err, "ninja", "ninja", "-C", extDir.c_str(), "-t", "clean");
if(status) {
// We don't expect any specifc output from ninja, but only if ninja failed,
// we want to see what it printed to stdout and stderr.
CHECK(out.str() == "");
CHECK(err.str() == "");
}
CHECK(status == 0);
}
5 changes: 5 additions & 0 deletions test/api/cli/extensibility/extension_kernel_usage.daphne
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Manual use of a custom kernel through a kernel hint.

X = as.f32([1.0, 4.0, -5.0, 2.0]);
s = sum::mySumAll(X);
print(s);
4 changes: 4 additions & 0 deletions test/api/cli/extensibility/kernel_extension_test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.ninja_deps
.ninja_log
libMyKernels.so
myKernels.o
22 changes: 22 additions & 0 deletions test/api/cli/extensibility/kernel_extension_test/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2024 The DAPHNE Consortium
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

libMyKernels.so: myKernels.o
g++ -shared myKernels.o -o libMyKernels.so

myKernels.o: myKernels.cpp
g++ -c -fPIC myKernels.cpp -I../../../../../src -std=c++17 -o myKernels.o

clean:
rm -rf myKernels.o libMyKernels.so
21 changes: 21 additions & 0 deletions test/api/cli/extensibility/kernel_extension_test/build.ninja
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2024 The DAPHNE Consortium
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

rule buildSharedLib
command = g++ -shared $in -o $out
build libMyKernels.so: buildSharedLib myKernels.o

rule compileSrc
command = g++ -c -fPIC $in -I../../../../../src -std=c++17 -o $out
build myKernels.o: compileSrc myKernels.cpp
39 changes: 39 additions & 0 deletions test/api/cli/extensibility/kernel_extension_test/myKernels.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2024 The DAPHNE Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// TODO Should be <daphne/runtime/local/datastructures/DenseMatrix.h> for more clarity.
#include <runtime/local/datastructures/DenseMatrix.h>

#include <iostream>

#include <cstdlib>

class DaphneContext;

extern "C" {

void mySumAll(float* res, const DenseMatrix<float>* arg, DaphneContext* ctx) {
std::cout << "hello from mySumAll" << std::endl;
const float* valuesArg = arg->getValues();
*res = 0;
for(size_t r = 0; r < arg->getNumRows(); r++) {
for(size_t c = 0; c < arg->getNumCols(); c++)
*res += valuesArg[c];
valuesArg += arg->getRowSkip();
}
}

}
10 changes: 10 additions & 0 deletions test/api/cli/extensibility/kernel_extension_test/myKernels.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"opMnemonic": "sumAll",
"kernelFuncName": "mySumAll",
"resTypes": ["float"],
"argTypes": ["DenseMatrix<float>"],
"backend": "CPP",
"libPath": "libMyKernels.so"
}
]

0 comments on commit e6397e8

Please sign in to comment.