Skip to content

Commit

Permalink
Merge pull request #31 from definelicht/subflows
Browse files Browse the repository at this point in the history
Subflows
  • Loading branch information
definelicht authored Mar 30, 2021
2 parents 4adca31 + 74a719f commit 6737ef8
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 28 deletions.
38 changes: 15 additions & 23 deletions include/hlslib/xilinx/Simulation.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
/// @author Johannes de Fine Licht ([email protected])
/// @copyright This software is copyrighted under the BSD 3-Clause License.
/// @copyright This software is copyrighted under the BSD 3-Clause License.

#pragma once

#ifndef HLSLIB_SYNTHESIS
#include <condition_variable>
#include <mutex>
#include <queue>
#include <thread>
#include <vector>
// #include "hlslib/Stream.h"
Expand All @@ -16,9 +19,10 @@
// which will launch them as a C++ thread when running simulation, but will
// fall back on normal function calls when running synthesis.
//
// The macro HLSLIB_DATAFLOW_INIT must be called before adding dataflow
// functions, in order to initialize the local context.
// The macro HLSLIB_DATAFLOW_FINALIZE must be called before returning from the
// top level function to join the dataflow threads.
// HLSLIB_DATAFLOW_INIT currently has no purpose, but is included for symmetry.
//
// TODO: HLSLIB_DATAFLOW_FUNCTION does not work when calling templated functions
// with multiple arguments, as it considers the comma a separator between
Expand All @@ -36,11 +40,11 @@ namespace hlslib {
#else
namespace {
class _Dataflow {

private:
public:
inline _Dataflow() {}
inline ~_Dataflow() { this->Join(); }

private:
template <typename T>
struct non_deducible {
using type = T;
Expand All @@ -60,39 +64,27 @@ class _Dataflow {
}

public:
inline static _Dataflow& Get() { // Singleton pattern
static _Dataflow df;
return df;
}

template <class Ret, typename... Args>
void AddFunction(Ret (*func)(Args...), non_deducible_t<Args>... args) {
threads_.emplace_back(func, passed_by(std::forward<Args>(args),
std::is_reference<Args>{})...);
}

// template <typename T, typename... Args>
// Stream<T>& EmplaceStream(Args&&... args) {
// streams_.emplace_back(std::unique_ptr<Stream<T>>(new Stream<T>(args...)));
// return *static_cast<Stream<T> *>(streams_.back().get());
// }

inline void Join() {
for (auto &t : threads_) {
for (auto& t : threads_) {
t.join();
}
threads_.clear();
}

private:
private:
std::vector<std::thread> threads_{};
// std::vector<std::unique_ptr<_StreamBase>> streams_{};
};
#define HLSLIB_DATAFLOW_INIT()
#define HLSLIB_DATAFLOW_INIT() ::hlslib::_Dataflow __hlslib_dataflow_context;
#define HLSLIB_DATAFLOW_FUNCTION(func, ...) \
::hlslib::_Dataflow::Get().AddFunction(func, __VA_ARGS__)
#define HLSLIB_DATAFLOW_FINALIZE() ::hlslib::_Dataflow::Get().Join();
}
__hlslib_dataflow_context.AddFunction(func, __VA_ARGS__)
#define HLSLIB_DATAFLOW_FINALIZE() __hlslib_dataflow_context.Join();
} // namespace
#endif

} // End namespace hlslib
} // End namespace hlslib
4 changes: 4 additions & 0 deletions xilinx_test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ if(Threads_FOUND)
add_executable(TestShiftRegister test/TestShiftRegister.cpp)
target_link_libraries(TestShiftRegister ${CMAKE_THREAD_LIBS_INIT} catch)
add_test(TestShiftRegister TestShiftRegister)
add_executable(TestSubflow test/TestSubflow.cpp kernels/Subflow.cpp)
target_link_libraries(TestSubflow ${CMAKE_THREAD_LIBS_INIT} catch)
add_test(TestSubflow TestSubflow)
else()
message(WARNING "Threads not found. Disabling multi-PE kernel tests.")
endif()
Expand Down Expand Up @@ -128,3 +131,4 @@ sdaccel_target("AccumulateInt" "-DHLSLIB_COMPILE_ACCUMULATE_INT")
synthesis_target("ShiftRegister" "")
sdaccel_target("ShiftRegister" "")
synthesis_target("StreamAPI" "")
synthesis_target("Subflow" "")
6 changes: 6 additions & 0 deletions xilinx_test/include/Subflow.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once

using Data_t = int;
constexpr int kSize = 128;

extern "C" void Subflow(const Data_t* memIn, Data_t* memOut);
10 changes: 5 additions & 5 deletions xilinx_test/kernels/AccumulateInt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ void AccumulateInt(DataPack_t const *memoryIn, DataPack_t *memoryOut, int size,
// functions with multiple template arguments
#ifndef HLSLIB_SYNTHESIS
HLSLIB_DATAFLOW_INIT();
hlslib::_Dataflow::Get().AddFunction(Read<DataPack_t>, memoryIn, pipeIn,
iterations * size);
hlslib::_Dataflow::Get().AddFunction(
__hlslib_dataflow_context.AddFunction(Read<DataPack_t>, memoryIn, pipeIn,
iterations * size);
__hlslib_dataflow_context.AddFunction(
hlslib::AccumulateSimple<DataPack_t, Operator>, pipeIn, pipeOut,
iterations, size);
hlslib::_Dataflow::Get().AddFunction(Write<DataPack_t>, pipeOut,
memoryOut, iterations);
__hlslib_dataflow_context.AddFunction(Write<DataPack_t>, pipeOut, memoryOut,
iterations);
HLSLIB_DATAFLOW_FINALIZE();
#else
Read<DataPack_t>(memoryIn, pipeIn, iterations * size);
Expand Down
51 changes: 51 additions & 0 deletions xilinx_test/kernels/Subflow.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "Subflow.h"

#include "hlslib/xilinx/Simulation.h"
#include "hlslib/xilinx/Stream.h"

void ReadIn(const Data_t* memIn, hlslib::Stream<Data_t>& inPipe) {
for (unsigned i = 0; i < kSize; ++i) {
#pragma HLS PIPELINE II=1
inPipe.Push(memIn[i]);
}
}

void AddOne(hlslib::Stream<Data_t>& inPipe, hlslib::Stream<Data_t>& internal) {
for (unsigned i = 0; i < kSize; ++i) {
#pragma HLS PIPELINE II=1
internal.Push(inPipe.Pop() + 1);
}
}

void MultiplyByTwo(hlslib::Stream<Data_t>& internal,
hlslib::Stream<Data_t>& outPipe) {
for (unsigned i = 0; i < kSize; ++i) {
#pragma HLS PIPELINE II=1
outPipe.Push(internal.Pop() * 2);
}
}

void Subtask(hlslib::Stream<Data_t>& inPipe, hlslib::Stream<Data_t>& outPipe) {
HLSLIB_DATAFLOW_INIT();
hlslib::Stream<Data_t> internal;
HLSLIB_DATAFLOW_FUNCTION(AddOne, inPipe, internal);
HLSLIB_DATAFLOW_FUNCTION(MultiplyByTwo, internal, outPipe);
HLSLIB_DATAFLOW_FINALIZE();
}

void WriteOut(hlslib::Stream<Data_t>& outPipe, Data_t* memOut) {
for (unsigned i = 0; i < kSize; ++i) {
#pragma HLS PIPELINE II=1
memOut[i] = outPipe.Pop();
}
}

void Subflow(const Data_t* memIn, Data_t* memOut) {
#pragma HLS DATAFLOW
HLSLIB_DATAFLOW_INIT();
hlslib::Stream<Data_t> inPipe, outPipe;
HLSLIB_DATAFLOW_FUNCTION(ReadIn, memIn, inPipe);
HLSLIB_DATAFLOW_FUNCTION(Subtask, inPipe, outPipe);
HLSLIB_DATAFLOW_FUNCTION(WriteOut, outPipe, memOut);
HLSLIB_DATAFLOW_FINALIZE();
}
18 changes: 18 additions & 0 deletions xilinx_test/test/TestSubflow.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include <random>

#include "Subflow.h"
#include "catch.hpp"

TEST_CASE("Subflow", "[Subflow]") {
std::random_device rd;
std::default_random_engine re(rd());
std::uniform_int_distribution<Data_t> dist(10, 1);
std::vector<Data_t> memIn(kSize), memOut(kSize);
for (unsigned i = 0; i < kSize; ++i) {
memIn[i] = dist(re);
}
Subflow(memIn.data(), memOut.data());
for (unsigned i = 0; i < kSize; ++i) {
REQUIRE(memOut[i] == (memIn[i] + 1) * 2);
}
}

0 comments on commit 6737ef8

Please sign in to comment.