Skip to content

Commit

Permalink
[DAPHNE-daphne-eu#416] Initial Intel FPGA Support
Browse files Browse the repository at this point in the history
This commit introduces support for the Intel PAC D5005 FPGA accelerator card. It adds the necessary bits in the compiler infrastructure, a runtime kernel for SGEMM and context handling. The precompiled bitstream will be provided in the separate repository github.com/daphne-eu/supplemental-binaries to avoid blowing up the size of the main repository.
  • Loading branch information
ratusz authored and corepointer committed Oct 6, 2022
1 parent 7e262cb commit b501c59
Show file tree
Hide file tree
Showing 27 changed files with 1,423 additions and 6 deletions.
17 changes: 17 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,19 @@ if(USE_ARROW)
message(STATUS "Arrow/Parquet enabled")
endif()

option(USE_FPGAOPENCL "Whether to activate compilation of FPGA OpenCL features" OFF)
if(USE_FPGAOPENCL)
if(NOT DEFINED ENV{QUARTUSDIR})
message(SEND_ERROR "Intel(R) Quartus installation directory should be defined by QUARTUSDIR varaiable (e.g. /opt/intel/intelFPGA_pro/21.4/)")
execute_process(COMMAND sleep 10)
endif()
include_directories($ENV{QUARTUSDIR}/hld/examples_aoc/common/inc/ $ENV{QUARTUSDIR}/hld/host/include/)
message(STATUS "cmake: using FPGA")
add_definitions(-DUSE_FPGAOPENCL)
endif()

set(CMAKE_VERBOSE_MAKEFILE ON)

# *****************************************************************************
# Project-specific include directories
# *****************************************************************************
Expand All @@ -170,6 +183,10 @@ add_subdirectory(src/runtime/distributed/worker)
add_subdirectory(src/runtime/local/datastructures)
add_subdirectory(src/runtime/local/io)
add_subdirectory(src/runtime/local/kernels)
if(USE_FPGAOPENCL)
add_subdirectory(src/runtime/local/kernels/FPGAOPENCL)
endif()
add_subdirectory(src/util)


add_subdirectory(test)
18 changes: 17 additions & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ par_acceptAll="0"
unknown_options=""
BUILD_CUDA="-DUSE_CUDA=OFF"
BUILD_ARROW="-DUSE_ARROW=OFF"
BUILD_FPGAOPENCL="-DUSE_FPGAOPENCL=OFF"
BUILD_DEBUG="-DCMAKE_BUILD_TYPE=Release"

while [[ $# -gt 0 ]]; do
Expand Down Expand Up @@ -414,6 +415,10 @@ while [[ $# -gt 0 ]]; do
echo using ARROW
BUILD_ARROW="-DUSE_ARROW=ON"
;;
--fpgaopencl)
echo using FPGAOPENCL
export BUILD_FPGAOPENCL="-DUSE_FPGAOPENCL=ON"
;;
--debug)
echo building DEBUG version
export BUILD_DEBUG="-DCMAKE_BUILD_TYPE=Debug"
Expand Down Expand Up @@ -701,14 +706,25 @@ else
daphne_msg "No need to build MLIR/LLVM again."
fi

if [[ $BUILD_FPGAOPENCL = *"ON"* ]]; then
FPGAOPENCL_BISTREAM_DIR="$projectRoot/src/runtime/local/kernels/FPGAOPENCL/bitstreams"
FPGAOPENCL_BISTREAM_URL="https://github.com/daphne-eu/supplemental-binaries/raw/main/fpga_bitstreams/"
if [ ! -d $FPGAOPENCL_BISTREAM_DIR ]; then
echo fetching FPGA bitstreams
mkdir -p $FPGAOPENCL_BISTREAM_DIR
cd $FPGAOPENCL_BISTREAM_DIR
wget $FPGAOPENCL_BISTREAM_URL/sgemm.aocx
cd -
fi
fi

# *****************************************************************************
# Build DAPHNE target.
# *****************************************************************************

daphne_msg "Build Daphne"

cmake -S "$projectRoot" -B "$daphneBuildDir" -G Ninja $BUILD_CUDA $BUILD_ARROW $BUILD_DEBUG \
cmake -S "$projectRoot" -B "$daphneBuildDir" -G Ninja $BUILD_CUDA $BUILD_ARROW $BUILD_FPGAOPENCL $BUILD_DEBUG \
-DCMAKE_PREFIX_PATH="$installPrefix" -DANTLR_VERSION="$antlrVersion" \
-DMLIR_DIR="$buildPrefix/$llvmName/lib/cmake/mlir/" \
-DLLVM_DIR="$buildPrefix/$llvmName/lib/cmake/llvm/"
Expand Down
62 changes: 62 additions & 0 deletions doc/FPGAconfiguration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<!--
Copyright 2021 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.
-->

# FPGA configuration for usage in DAPHNE


### System requirments

Daphne build script for FPGA kernels support requires additional QUARTUSDIR system variable definition.
Example command is presented in fpga-build-env.sh or in the following command:

export QUARTUSDIR=/opt/intel/intelFPGA_pro/21.4

To build the Daphne with the FPGA support -fpgaopencl flag has to be used:

./build.sh --fpgaopenc


To run developed or precompiled, included in Daphne repository FPGA OpenCL kernels an installedand configured FPGA device is required.
Our example kernels have been tested using Intel(R) PAC D5005 card (https://www.intel.com/content/www/us/en/products/sku/193921/intel-fpga-pac-d5005/specifications.html)

DAPHNE contains some example linear algebra kernels developed using T2SP framework(https://github.com/IntelLabs/t2sp/blob/master/README.md).
Example precompiled FPGA kernels can be usedon DAPHNE DSL description level.
To prepare the system for the precompiled FPGA kernels some FPGA and OpenCL system variables are required.
The easiest way to set up required varables is to use the init_opencl.sh script from installed Intel(R) Quartus sowtware or from the
Intel(R) OpenCL RTE or Intel(R) OpenCL SDK packages.

Example script usage:
source /opt/intel/intelFPGA_pro/21.4/hld/init_opencl.sh

For additional details please look into https://www.intel.com/content/www/us/en/docs/programmable/683550/18-1/standard-edition-getting-started-guide.html
or https://www.intel.com/content/www/us/en/software/programmable/sdk-for-opencl/overview.html.


### Precompiled FPGA kernels usage

To use a precompiled FPGA kernel a FPGA image is required (*.aocx). FPGA device has to programmed with particular image which contains required kernel implementation.
Example FPGA programming command using example FPGA image:

aocl program acl0 src/runtime/local/kernels/FPGAOPENCL/bitstreams/sgemm.aocx


Additionally the BITSTREAM variable has to be defind in the system.
Please look into the following example:

export BITSTREAM=src/runtime/local/kernels/FPGAOPENCL/bitstreams/sgemm.aocx

When another FPGA image contains implementation for another required computational kernel then FPGA device has to be reprogrammed and BITSTREAM variable value has to be changed.

9 changes: 9 additions & 0 deletions fpga-build-env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
#initialize Intel FPGA OpenCL environment
export QUARTUSDIR=/opt/intel/intelFPGA_pro/21.4
source $QUARTUSDIR/hld/init_opencl.sh
echo $INTELFPGAOCLSDKROOT
export ALTERAOCLSDKROOT=$INTELFPGAOCLSDKROOT
#set up BITSTREAM variable for required FPGA image (can be different different for varius implemented kernels)
export BITSTREAM=src/runtime/local/kernels/FPGAOPENCL/bitstreams/sgemm.aocx # SGEMM computational kernel

43 changes: 43 additions & 0 deletions scripts/examples/fpga-gemm.daph
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2021 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.
*/

############## IMPORTANT #################
# EXAMPLE command to run the script:
#
# env BITSTREAM=../../src/runtime/local/kernels/FPGAOPENCL/bistreams/sgemm.aocx ./build/bin/daphne -fpgaopencl scripts/examples/fpga-gemm.daph
#
# WHERE:
# -fpgaopencl is a flag required for FPGA usage
# BITSTREAM variable point out required FPGA image with its location
#########################################

# Creating input matrices
m = rand(448,1024, as.f32(2.0), as.f32(2.0), 1.0, -1);
//m = rand(896,8192, as.f32(2.0), as.f32(2.0), 1.0, -1);
//m = rand(448,16384, as.f32(2.0), as.f32(2.0), 1.0, -1);

m2 = rand(1024,512, as.f32(1.0), as.f32(1.0), 1.0, -1);
//m2 = rand(8192,1024, as.f32(1.0), as.f32(1.0), 1.0, -1);
//m2 = rand(16384,1024, as.f32(1.0), as.f32(1.0), 1.0, -1);

# test prints
//print(m[0,]);
//print(m2[0,]);

Z = m @ m2;
//print(Z[,0]);

print("Bye!");
4 changes: 4 additions & 0 deletions src/api/cli/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ if(USE_CUDA AND CMAKE_CUDA_COMPILER)
list(APPEND LIB_DEPS CUDAKernels)
endif()

if(USE_FPGAOPENCL)
list(APPEND LIB_DEPS FPGAOPENCLKernels)
endif()

add_llvm_executable(daphne daphne.cpp DaphneUserConfig.h DEPENDS ${LIB_DEPS})

llvm_update_compile_flags(daphne)
Expand Down
6 changes: 6 additions & 0 deletions src/api/cli/DaphneUserConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ struct DaphneUserConfig {
bool pinWorkers = false;
bool hyperthreadingEnabled = false;
bool debugMultiThreading = false;
bool use_fpgaopencl = false;

bool debug_llvm = false;
bool explain_kernels = false;
Expand All @@ -65,6 +66,11 @@ struct DaphneUserConfig {
// ToDo: This is an arbitrary default taken from sample code
// int cublas_workspace_size = 1024 * 1024 * 4;
#endif
#ifdef USE_FPGAOPENCL
std::vector<int> fpga_devices;
#endif


std::string libdir;
std::vector<std::string> library_paths;
};
9 changes: 9 additions & 0 deletions src/api/cli/daphne.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ main(int argc, char** argv)
"cuda", cat(daphneOptions),
desc("Use CUDA")
);
opt<bool> fpgaopencl(
"fpgaopencl", cat(daphneOptions),
desc("Use FPGAOPENCL")
);
opt<string> libDir(
"libdir", cat(daphneOptions),
desc("The directory containing kernel libraries")
Expand Down Expand Up @@ -324,6 +328,11 @@ main(int argc, char** argv)
}
}

if(fpgaopencl) {
user_config.use_fpgaopencl = true;
}


// add this after the cli args loop to work around args order
if(!user_config.libdir.empty() && user_config.use_cuda)
user_config.library_paths.push_back(user_config.libdir + "/libCUDAKernels.so");
Expand Down
14 changes: 14 additions & 0 deletions src/compiler/execution/DaphneIrExecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ bool DaphneIrExecutor::runPasses(mlir::ModuleOp module)
pm.addNestedPass<mlir::FuncOp>(mlir::daphne::createMarkCUDAOpsPass(userConfig_));
#endif

#ifdef USE_FPGAOPENCL
if(userConfig_.use_fpgaopencl)
pm.addNestedPass<mlir::FuncOp>(mlir::daphne::createMarkFPGAOPENCLOpsPass(userConfig_));
#endif


if(userConfig_.use_obj_ref_mgnt)
pm.addNestedPass<mlir::FuncOp>(mlir::daphne::createManageObjRefsPass());
if(userConfig_.explain_obj_ref_mgnt)
Expand Down Expand Up @@ -182,6 +188,14 @@ std::unique_ptr<mlir::ExecutionEngine> DaphneIrExecutor::createExecutionEngine(m
}
}
#endif

#ifdef USE_FPGAOPENCL
if(userConfig_.use_fpgaopencl) {
if(userConfig_.libdir.empty()) {
sharedLibRefs.push_back("build/src/runtime/local/kernels/libFPGAOPENCLKernels.so");
}
}
#endif
registerLLVMDialectTranslation(context_);
// module.dump();
auto maybeEngine = mlir::ExecutionEngine::create(
Expand Down
1 change: 1 addition & 0 deletions src/compiler/lowering/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ add_mlir_dialect_library(MLIRDaphneTransforms
DistributeComputationsPass.cpp
DistributePipelinesPass.cpp
MarkCUDAOpsPass.cpp
MarkFPGAOPENCLOpsPass.cpp
InsertDaphneContextPass.cpp
ManageObjRefsPass.cpp
LowerToLLVMPass.cpp
Expand Down
7 changes: 7 additions & 0 deletions src/compiler/lowering/InsertDaphneContextPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ void InsertDaphneContextPass::runOnFunction()
if (user_config.use_distributed){
builder.create<daphne::CreateDistributedContextOp>(loc);
}
#ifdef USE_FPGAOPENCL
if(user_config.use_fpgaopencl) {
builder.create<daphne::CreateFPGAContextOp>(loc);
}
#endif


// Insert a DestroyDaphneContextOp as the last operation in the block, but
// before the block's terminator.
builder.setInsertionPoint(b.getTerminator());
Expand Down
57 changes: 57 additions & 0 deletions src/compiler/lowering/MarkFPGAOPENCLOpsPass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2021 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.
*/
#ifdef USE_FPGAOPENCL
#include "compiler/CompilerUtils.h"
#include "ir/daphneir/Daphne.h"
#include "ir/daphneir/Passes.h"
#include <mlir/IR/BlockAndValueMapping.h>

#include <iostream>

using namespace mlir;

struct MarkFPGAOPENCLOpsPass : public PassWrapper<MarkFPGAOPENCLOpsPass, FunctionPass> {

/**
* @brief User configuration influencing the rewrite pass
*/
const DaphneUserConfig& cfg;

explicit MarkFPGAOPENCLOpsPass(const DaphneUserConfig& cfg) : cfg(cfg) {
}

void runOnFunction() final;

bool checkUseFPGAOPENCL(Operation* op) const {
// std::cout << "checkUseFPGAOPENCL: " << op->getName().getStringRef().str() << std::endl;
return op->hasTrait<mlir::OpTrait::FPGAOPENCLSupport>();
}
};

void MarkFPGAOPENCLOpsPass::runOnFunction() {
getFunction()->walk([&](Operation* op) {
OpBuilder builder(op);
if(checkUseFPGAOPENCL(op)) {
op->setAttr("fpgaopencl_device", builder.getI32IntegerAttr(0));
}
WalkResult::advance();
});
}

std::unique_ptr<Pass> daphne::createMarkFPGAOPENCLOpsPass(const DaphneUserConfig& cfg) {
return std::make_unique<MarkFPGAOPENCLOpsPass>(cfg);
}
#endif
4 changes: 4 additions & 0 deletions src/compiler/lowering/RewriteToCallKernelOpPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ namespace
// else
// std::cout << "attr = null: " << op->getName().getStringRef().str() << std::endl;
}
else if(op->hasAttr("fpgaopencl_device")) {
callee << "FPGAOPENCL";
}


callee << '_' << op->getName().stripDialect().data();

Expand Down
8 changes: 7 additions & 1 deletion src/ir/daphneir/Daphne.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@
#include <utility>
#include <vector>

namespace mlir::OpTrait {
template<class ConcreteOp>
class FPGAOPENCLSupport : public TraitBase<ConcreteOp, FPGAOPENCLSupport> {
};
}

namespace mlir::daphne {
enum class MatrixRepresentation {
Dense = 0,
Expand All @@ -67,4 +73,4 @@ namespace mlir::daphne {
#define GET_OP_CLASSES
#include "ir/daphneir/DaphneOps.h.inc"

#endif //SRC_IR_DAPHNEIR_DAPHNE_H
#endif //SRC_IR_DAPHNEIR_DAPHNE_H
Loading

0 comments on commit b501c59

Please sign in to comment.