├── src ├── dfi │ ├── type │ │ ├── Int.cc │ │ ├── BigInt.cc │ │ ├── Double.cc │ │ ├── TinyInt.cc │ │ ├── UBigInt.cc │ │ ├── Floating.cc │ │ ├── SmallInt.cc │ │ ├── Int.h │ │ ├── BigInt.h │ │ ├── Double.h │ │ ├── TinyInt.h │ │ ├── UBigInt.h │ │ ├── Floating.h │ │ ├── SmallInt.h │ │ ├── TypeId.h │ │ ├── ErrorCodes.h │ │ ├── CMakeLists.txt │ │ ├── Type.h │ │ ├── EnumTypes.h │ │ ├── Type.cc │ │ ├── Value.h │ │ └── Schema.h │ ├── message │ │ ├── DFIFlowBarrierRequest.proto │ │ ├── DFIAppendBufferResponse.proto │ │ ├── DFICreateFlowResponse.proto │ │ ├── DFIFreeSegmentsRequest.proto │ │ ├── DFICreateRingOnBufferRequest.proto │ │ ├── DFIRetrieveFlowHandleRequest.proto │ │ ├── DFIDestroyFlowRequest.proto │ │ ├── DFIFlowBarrierResponse.proto │ │ ├── DFIRetrieveBufferRequest.proto │ │ ├── DFIAllocSegmentsResponse.proto │ │ ├── DFICreateRingOnBufferResponse.proto │ │ ├── DFIAllocSegmentsRequest.proto │ │ ├── DFIRetrieveBufferResponse.proto │ │ ├── DFIAppendBufferRequest.proto │ │ ├── DFIRetrieveFlowHandleResponse.proto │ │ ├── MessageErrors.h │ │ ├── DFICreateFlowRequest.proto │ │ └── CMakeLists.txt │ ├── CMakeLists.txt │ ├── memory │ │ ├── FlowOptimization.h │ │ ├── CMakeLists.txt │ │ ├── NodeServer.cc │ │ ├── BufferWriter.cc │ │ ├── BufferSegment.h │ │ ├── BufferHandle.h │ │ ├── NodeClient.h │ │ ├── MulticastSegmentBuffer.h │ │ └── BufferWriterInterface.h │ ├── flow │ │ ├── CMakeLists.txt │ │ ├── FlowSourceFactory.h │ │ ├── FlowHandle.h │ │ ├── FlowSourceMulticast.h │ │ ├── FlowTarget.h │ │ ├── FlowSourceMulticastBW.h │ │ ├── FlowSourceLat.h │ │ └── FlowSourceInterface.h │ └── registry │ │ ├── CMakeLists.txt │ │ └── RegistryClient.h ├── use-cases │ ├── distributed-replicate-join-flow │ │ ├── README │ │ ├── utils │ │ │ ├── timer.hpp │ │ │ ├── Thread.cc │ │ │ ├── Thread.h │ │ │ ├── ThreadScheduler.h │ │ │ └── ThreadScheduler.cc │ │ ├── Settings.cc │ │ ├── CMakeLists.txt │ │ ├── NetworkReplicatorThread.h │ │ ├── BuildProber.h │ │ ├── NetworkReplicator.h │ │ ├── LocalPartitionerThread.h │ │ ├── Main.cc │ │ ├── LocalDFIPartitioner.h │ │ ├── Settings.h │ │ ├── LocalDFIPartitionerThread.h │ │ ├── Partition.h │ │ ├── LocalPartitioner.h │ │ └── BuildProberThread.h │ ├── distributed-radix-join-flow │ │ ├── README │ │ ├── Settings.cc │ │ ├── CMakeLists.txt │ │ ├── utils │ │ │ ├── Thread.cc │ │ │ ├── Thread.h │ │ │ ├── ThreadScheduler.h │ │ │ └── ThreadScheduler.cc │ │ ├── NetworkPartitioner.h │ │ ├── Main.cc │ │ ├── BuildProber.h │ │ ├── Partition.h │ │ ├── LocalPartitioner.h │ │ └── NetworkPartitionerThread.h │ ├── utils │ │ ├── ThreadUtil.h │ │ └── StringHelper.h │ ├── rsm-paxos │ │ ├── CMakeLists.txt │ │ ├── utils │ │ │ ├── Thread.cc │ │ │ ├── Thread.h │ │ │ ├── ThreadScheduler.h │ │ │ └── ThreadScheduler.cc │ │ ├── Settings.cc │ │ ├── KV_SM.h │ │ ├── Log.h │ │ └── Settings.h │ └── rsm-nopaxos │ │ ├── utils │ │ ├── Thread.cc │ │ ├── Thread.h │ │ ├── ThreadScheduler.h │ │ └── ThreadScheduler.cc │ │ ├── CMakeLists.txt │ │ ├── Settings.cc │ │ ├── KV_SM.h │ │ ├── Log.h │ │ ├── Settings.h │ │ └── benchmark.sh ├── gtest │ ├── examples │ │ ├── shuffle_flow_examples.h │ │ ├── combiner_flow_examples.h │ │ ├── replicate_flow_examples.h │ │ ├── shuffle_flow_examples.cc │ │ └── combiner_flow_examples.cc │ ├── memory │ │ ├── TestConfig.h │ │ ├── TestRegistryClient.h │ │ ├── TestConfig.cc │ │ ├── TestBufferIterator.h │ │ ├── TestRegistryClient.cc │ │ ├── TestBufferWriterLat.h │ │ ├── IntegrationTestsAppend.h │ │ ├── TestBufferWriter.h │ │ └── TestBufferWriterReplicate.h │ ├── flow-api │ │ ├── combiner_flow_tests.h │ │ ├── flow_barrier_tests.h │ │ ├── replicate_flow_tests.h │ │ ├── shuffle_flow_tests.h │ │ └── flow_barrier_tests.cc │ └── CMakeLists.txt ├── utils │ ├── CMakeLists.txt │ ├── StringHelper.h │ ├── Network.h │ ├── Timer.h │ └── Logging.h ├── flow-api │ ├── schema.h │ ├── dfi.h │ ├── registry_server.h │ ├── flow_barrier_init.h │ ├── CMakeLists.txt │ ├── dfi_node.h │ └── flow_barrier.h └── conf │ └── DFI.conf ├── .gitmodules ├── .gitignore ├── cmake └── modules │ ├── FindRdmaCm.cmake │ ├── FindIBVerbs.cmake │ ├── FindNuma.cmake │ ├── FindZMQ.cmake │ ├── FindPackageMessage.cmake │ └── FindSQLite3.cmake ├── CMakeLists.txt └── README.md /src/dfi/type/Int.cc: -------------------------------------------------------------------------------- 1 | #include "Int.h" 2 | 3 | 4 | Int::Int() : Type(TypeId::INT) 5 | { 6 | } -------------------------------------------------------------------------------- /src/dfi/type/BigInt.cc: -------------------------------------------------------------------------------- 1 | #include "BigInt.h" 2 | 3 | 4 | BigInt::BigInt() : Type(TypeId::BIGINT) 5 | { 6 | } -------------------------------------------------------------------------------- /src/dfi/type/Double.cc: -------------------------------------------------------------------------------- 1 | #include "Double.h" 2 | 3 | 4 | Double::Double() : Type(TypeId::DOUBLE) 5 | { 6 | } -------------------------------------------------------------------------------- /src/dfi/type/TinyInt.cc: -------------------------------------------------------------------------------- 1 | #include "TinyInt.h" 2 | 3 | 4 | TinyInt::TinyInt() : Type(TypeId::TINYINT) 5 | { 6 | } -------------------------------------------------------------------------------- /src/dfi/type/UBigInt.cc: -------------------------------------------------------------------------------- 1 | #include "UBigInt.h" 2 | 3 | 4 | UBigInt::UBigInt() : Type(TypeId::BIGUINT) 5 | { 6 | } -------------------------------------------------------------------------------- /src/dfi/type/Floating.cc: -------------------------------------------------------------------------------- 1 | #include "Floating.h" 2 | 3 | 4 | Floating::Floating() : Type(TypeId::FLOAT) 5 | { 6 | } -------------------------------------------------------------------------------- /src/dfi/type/SmallInt.cc: -------------------------------------------------------------------------------- 1 | #include "SmallInt.h" 2 | 3 | 4 | SmallInt::SmallInt() : Type(TypeId::SMALLINT) 5 | { 6 | } -------------------------------------------------------------------------------- /src/dfi/message/DFIFlowBarrierRequest.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dfi; 3 | 4 | message DFIFlowBarrierRequest { 5 | string name = 1; 6 | } 7 | -------------------------------------------------------------------------------- /src/dfi/message/DFIAppendBufferResponse.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dfi; 3 | 4 | message DFIAppendBufferResponse { 5 | uint32 return = 1; 6 | } 7 | -------------------------------------------------------------------------------- /src/dfi/message/DFICreateFlowResponse.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dfi; 3 | 4 | message DFICreateFlowResponse { 5 | uint32 return = 1; 6 | } 7 | -------------------------------------------------------------------------------- /src/dfi/message/DFIFreeSegmentsRequest.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dfi; 3 | 4 | message DFIFreeSegmentsRequest { 5 | string name = 1; 6 | } 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/rdma-manager"] 2 | path = src/rdma-manager 3 | url = https://github.com/DataManagementLab/rdma-manager.git 4 | branch = master -------------------------------------------------------------------------------- /src/dfi/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(memory) 2 | add_subdirectory(flow) 3 | add_subdirectory(type) 4 | add_subdirectory(registry) 5 | add_subdirectory(message) -------------------------------------------------------------------------------- /src/dfi/message/DFICreateRingOnBufferRequest.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dfi; 3 | 4 | message DFICreateRingOnBufferRequest { 5 | string name = 1; 6 | } 7 | -------------------------------------------------------------------------------- /src/dfi/message/DFIRetrieveFlowHandleRequest.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dfi; 3 | 4 | message DFIRetrieveFlowHandleRequest { 5 | string name = 1; 6 | } 7 | -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/README: -------------------------------------------------------------------------------- 1 | Fragment-and-Replicate join 2 | 3 | To run, use runExperiment.py with https://github.com/mjasny/distexprunner -------------------------------------------------------------------------------- /src/dfi/message/DFIDestroyFlowRequest.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dfi; 3 | 4 | message DFIDestroyFlowRequest { 5 | string name = 1; 6 | uint64 targetid = 2; 7 | } 8 | -------------------------------------------------------------------------------- /src/dfi/message/DFIFlowBarrierResponse.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dfi; 3 | 4 | message DFIFlowBarrierResponse { 5 | uint64 offset = 1; 6 | uint32 return = 2; 7 | } 8 | -------------------------------------------------------------------------------- /src/dfi/memory/FlowOptimization.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace dfi 4 | { 5 | 6 | enum FlowOptimization 7 | { 8 | BW, //Bandwidth 9 | LAT, //Latency 10 | MULTICAST_ORDERING, 11 | MULTICAST_BW, 12 | MULTICAST 13 | }; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/dfi/message/DFIRetrieveBufferRequest.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dfi; 3 | 4 | message DFIRetrieveBufferRequest { 5 | string buffername = 1; 6 | string flowname = 2; 7 | bool isSource = 3; 8 | bool isTarget = 4; 9 | uint64 targetid = 5; 10 | } 11 | -------------------------------------------------------------------------------- /src/dfi/message/DFIAllocSegmentsResponse.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dfi; 3 | 4 | 5 | message DFIAllocMultipleSegmentsResponse { 6 | repeated DFIAllocSegmentsResponse responses = 1; 7 | } 8 | 9 | message DFIAllocSegmentsResponse { 10 | uint64 offset = 1; 11 | uint32 return = 2; 12 | } 13 | -------------------------------------------------------------------------------- /src/use-cases/distributed-radix-join-flow/README: -------------------------------------------------------------------------------- 1 | This Distributed Radix Hash Join is an adaption from Claude Barthels' MPI join from https://www.systems.ethz.ch/node/334 . 2 | 3 | Paper: http://www.vldb.org/pvldb/vol10/p517-barthels.pdf 4 | 5 | To run use runExperiment.py with https://github.com/mjasny/distexprunner -------------------------------------------------------------------------------- /src/dfi/type/Int.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Int.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2019-01-14 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../../utils/Config.h" 10 | #include "Type.h" 11 | 12 | namespace dfi 13 | { 14 | class Int : public Type 15 | { 16 | public: 17 | Int(); 18 | protected: 19 | 20 | }; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/dfi/type/BigInt.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BigInt.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2019-01-14 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../../utils/Config.h" 10 | #include "Type.h" 11 | 12 | namespace dfi 13 | { 14 | class BigInt : public Type 15 | { 16 | public: 17 | BigInt(); 18 | protected: 19 | 20 | }; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/dfi/type/Double.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Double.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2019-01-14 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../../utils/Config.h" 10 | #include "Type.h" 11 | 12 | namespace dfi 13 | { 14 | class Double : public Type 15 | { 16 | public: 17 | Double(); 18 | protected: 19 | 20 | }; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/dfi/type/TinyInt.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file TinyInt.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2019-01-14 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../../utils/Config.h" 10 | #include "Type.h" 11 | 12 | namespace dfi 13 | { 14 | class TinyInt : public Type 15 | { 16 | public: 17 | TinyInt(); 18 | protected: 19 | 20 | }; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/dfi/type/UBigInt.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file UBigInt.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2019-01-14 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../../utils/Config.h" 10 | #include "Type.h" 11 | 12 | namespace dfi 13 | { 14 | class UBigInt : public Type 15 | { 16 | public: 17 | UBigInt(); 18 | protected: 19 | 20 | }; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/dfi/type/Floating.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Floating.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2019-01-14 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../../utils/Config.h" 10 | #include "Type.h" 11 | 12 | namespace dfi 13 | { 14 | class Floating : public Type 15 | { 16 | public: 17 | Floating(); 18 | protected: 19 | 20 | }; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/dfi/type/SmallInt.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file SmallInt.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2019-01-14 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../../utils/Config.h" 10 | #include "Type.h" 11 | 12 | namespace dfi 13 | { 14 | class SmallInt : public Type 15 | { 16 | public: 17 | SmallInt(); 18 | protected: 19 | 20 | }; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/dfi/type/TypeId.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file TypeId.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2019-01-14 5 | */ 6 | 7 | #pragma once 8 | 9 | namespace dfi { 10 | enum class TypeId 11 | { 12 | INVALID = 0, 13 | SMALLINT, 14 | INT, 15 | BIGINT, 16 | BIGUINT, 17 | FLOAT, 18 | DOUBLE, 19 | TINYINT 20 | }; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/gtest/examples/shuffle_flow_examples.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ShuffleFlowExamples.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2018-08-17 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../../flow-api/dfi.h" 10 | #include 11 | 12 | 13 | class ShuffleFlowExamples : public testing::Test 14 | { 15 | 16 | public: 17 | void SetUp() override; 18 | void TearDown() override; 19 | }; -------------------------------------------------------------------------------- /src/dfi/message/DFICreateRingOnBufferResponse.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dfi; 3 | 4 | message DFICreateRingOnBufferResponse { 5 | message Segment { 6 | uint64 offset = 1; 7 | uint64 size = 2; 8 | } 9 | string name = 1; 10 | uint64 node_id = 2; 11 | Segment segment = 3; 12 | uint64 segmentsPerWriter = 4; 13 | uint64 segmentSizes = 5; 14 | uint32 return = 6; 15 | } -------------------------------------------------------------------------------- /src/gtest/memory/TestConfig.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file TestConfig.h 3 | * @author lthostrup 4 | * @date 2019-04-16 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include "../../flow-api/dfi.h" 11 | 12 | class TestConfig : public testing::Test 13 | { 14 | 15 | public: 16 | void SetUp() override; 17 | void TearDown() override; 18 | 19 | protected: 20 | std::string program_name = "testconfig"; 21 | }; -------------------------------------------------------------------------------- /src/dfi/message/DFIAllocSegmentsRequest.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dfi; 3 | 4 | 5 | message DFIAllocMultipleSegmentsRequest { 6 | repeated DFIAllocSegmentsRequest allocSegmentRequests = 1; 7 | } 8 | 9 | message DFIAllocSegmentsRequest { 10 | string name = 1; 11 | uint32 segments_count = 2; 12 | uint64 segments_size = 3; //with footer size (full segment size) 13 | uint32 buffer_type = 4; 14 | bool cache_align = 5; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/utils/timer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | template 7 | inline auto time_it(Function function) { 8 | auto start = chrono::high_resolution_clock::now(); 9 | 10 | function(); 11 | 12 | auto end = chrono::high_resolution_clock::now(); 13 | return std::chrono::duration_cast(end - start).count(); 14 | } -------------------------------------------------------------------------------- /src/utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(UTILS_SRC 2 | StringHelper.h 3 | Filehelper.h 4 | Config.h 5 | Logging.h 6 | Config.cc 7 | Timer.h 8 | Network.h 9 | MPMCQueue.h 10 | PerfEvent.h 11 | ) # Adding headers required for portability reasons http://voices.canonical.com/jussi.pakkanen/2013/03/26/a-list-of-common-cmake-antipatterns/ 12 | add_library(utils ${UTILS_SRC}) 13 | target_include_directories(utils PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) 14 | -------------------------------------------------------------------------------- /src/gtest/flow-api/combiner_flow_tests.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../../flow-api/dfi.h" 5 | 6 | using namespace dfi; 7 | 8 | 9 | 10 | class TestCombinerFlow : public testing::Test { 11 | protected: 12 | void SetUp() override; 13 | void TearDown() override; 14 | 15 | std::unique_ptr m_regServer; 16 | std::unique_ptr m_nodeServer; 17 | 18 | std::string flow_name = "test flow"; 19 | }; -------------------------------------------------------------------------------- /src/gtest/flow-api/flow_barrier_tests.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../../flow-api/dfi.h" 5 | 6 | using namespace dfi; 7 | 8 | 9 | 10 | class TestFlowBarrier : public testing::Test { 11 | protected: 12 | void SetUp() override; 13 | void TearDown() override; 14 | 15 | std::unique_ptr m_regServer; 16 | std::unique_ptr m_nodeServer; 17 | 18 | std::string flow_name = "test flow"; 19 | }; -------------------------------------------------------------------------------- /src/gtest/flow-api/replicate_flow_tests.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../../flow-api/dfi.h" 5 | 6 | using namespace dfi; 7 | 8 | class TestReplicateFlow : public testing::Test { 9 | protected: 10 | void SetUp() override; 11 | void TearDown() override; 12 | 13 | 14 | std::unique_ptr m_regServer; 15 | std::unique_ptr m_nodeServer1; 16 | std::unique_ptr m_nodeServer2; 17 | }; 18 | -------------------------------------------------------------------------------- /src/dfi/flow/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(FLOW_SRC 2 | FlowHandle.h 3 | FlowSourceInterface.h 4 | FlowTarget.h 5 | FlowTarget.cc 6 | ) # Adding headers required for portability reasons http://voices.canonical.com/jussi.pakkanen/2013/03/26/a-list-of-common-cmake-antipatterns/ 7 | add_library(flow_dfi ${FLOW_SRC}) 8 | target_include_directories(flow_dfi PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 9 | target_link_libraries(flow_dfi 10 | memory_dfi 11 | registry_dfi 12 | type_dfi 13 | dfi_message 14 | ) -------------------------------------------------------------------------------- /src/gtest/flow-api/shuffle_flow_tests.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../../flow-api/dfi.h" 5 | 6 | using namespace dfi; 7 | 8 | 9 | 10 | class TestShuffleFlow : public testing::Test { 11 | protected: 12 | void SetUp() override; 13 | void TearDown() override; 14 | 15 | std::unique_ptr m_regServer; 16 | std::unique_ptr m_nodeServer1; 17 | std::unique_ptr m_nodeServer2; 18 | 19 | std::string flow_name = "test flow"; 20 | }; -------------------------------------------------------------------------------- /src/dfi/message/DFIRetrieveBufferResponse.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dfi; 3 | 4 | message DFIRetrieveBufferResponse { 5 | message Segment { 6 | uint64 offset = 1; 7 | uint64 size = 2; 8 | } 9 | string name = 1; 10 | uint64 node_id = 2; 11 | repeated Segment segment = 3; 12 | uint64 segmentsPerWriter = 4; 13 | uint64 segmentSizes = 5; 14 | uint32 buffertype = 6; 15 | uint64 local_rdma_ptr = 7; 16 | bool cache_align_data = 8; 17 | uint32 return = 9; 18 | } -------------------------------------------------------------------------------- /src/gtest/memory/TestRegistryClient.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file TestRegistryClient.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2018-08-17 5 | */ 6 | 7 | #pragma once 8 | 9 | 10 | #include 11 | #include "../../flow-api/dfi.h" 12 | 13 | class TestRegistryClient : public testing::Test 14 | { 15 | 16 | 17 | public: 18 | void SetUp() override; 19 | void TearDown() override; 20 | 21 | protected: 22 | RegistryClient *m_regClient; 23 | RegistryServer *m_regServer; 24 | NodeServer *m_nodeServer; 25 | }; -------------------------------------------------------------------------------- /src/dfi/registry/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(REGISTRY_SRC 3 | RegistryClient.h 4 | RegistryClient.cc 5 | RegistryServer.h 6 | RegistryServer.cc 7 | ) # Adding headers required for portability reasons http://voices.canonical.com/jussi.pakkanen/2013/03/26/a-list-of-common-cmake-antipatterns/ 8 | add_library(registry_dfi ${REGISTRY_SRC}) 9 | target_include_directories(registry_dfi PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 10 | target_link_libraries(registry_dfi 11 | utils 12 | rdma_lib 13 | dfi_message 14 | type_dfi 15 | memory_dfi 16 | ) 17 | -------------------------------------------------------------------------------- /src/dfi/type/ErrorCodes.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file err_codes.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2018-08-17 5 | */ 6 | 7 | #pragma once 8 | 9 | #define DFI_SUCCESS 0 10 | #define DFI_FAILURE 1 11 | #define DFI_NOT_INITIALIZED 2 12 | #define DFI_FLOW_FINISHED 3 13 | #define DFI_NULL_PTR 4 14 | // #define DFI_BUFFER_ALREADY_CREATED 4 15 | #define DFI_CREATE_BUFFER_FAILED 5 16 | #define DFI_NODE_CONNECT_FAILED 6 17 | #define DFI_BUFFER_CONSUMER_ALREADY_CREATED 7 18 | #define DFI_BUFFER_CLOSED 8 19 | #define DFI_MESSAGE_LOST 9 20 | #define DFI_NO_TUPLE 10 -------------------------------------------------------------------------------- /src/flow-api/schema.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file schema.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2019-01-30 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../utils/Config.h" 10 | #include "../dfi/type/TypeId.h" 11 | #include "../dfi/type/Schema.h" 12 | 13 | struct DFI_Schema : public dfi::Schema 14 | { 15 | /** 16 | * @brief Construct a new dfi schema object 17 | * 18 | * @param columns Pairs of column names and types 19 | */ 20 | DFI_Schema(std::vector> columns) : dfi::Schema(columns) 21 | {} 22 | }; 23 | -------------------------------------------------------------------------------- /src/dfi/message/DFIAppendBufferRequest.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dfi; 3 | 4 | message DFIAppendBufferRequest { 5 | message Segment { 6 | uint64 offset = 1; 7 | uint64 size = 2; 8 | uint64 threshold = 3; 9 | } 10 | string name = 1; 11 | uint64 node_id = 2; 12 | repeated Segment segment = 3; 13 | uint64 segmentsPerWriter = 4; 14 | bool reuseSegments = 5; 15 | uint64 numberAppenders = 6; 16 | uint64 segmentSizes = 7; 17 | bool register = 8; 18 | uint32 buffertype = 9; 19 | bool cache_align_data = 10; 20 | } 21 | -------------------------------------------------------------------------------- /src/use-cases/distributed-radix-join-flow/Settings.cc: -------------------------------------------------------------------------------- 1 | #include "Settings.h" 2 | 3 | const string Settings::LEFT_REL_FLOW_NAME = "LEFT RELATION FLOW"; 4 | const string Settings::RIGHT_REL_FLOW_NAME = "RIGHT RELATION FLOW"; 5 | 6 | 7 | uint64_t Settings::LEFT_REL_FULL_SIZE = 0; 8 | uint64_t Settings::RIGHT_REL_FULL_SIZE = 0; 9 | 10 | uint64_t Settings::LEFT_REL_SIZE = 0; 11 | uint64_t Settings::RIGHT_REL_SIZE = 0; 12 | 13 | uint32_t Settings::NODE_ID = 0; 14 | uint32_t Settings::NODES_TOTAL = 0; 15 | 16 | uint32_t Settings::THREADS_COUNT = 0; 17 | 18 | bool Settings::RANDOM_ORDER = false; 19 | 20 | -------------------------------------------------------------------------------- /src/flow-api/dfi.h: -------------------------------------------------------------------------------- 1 | #include "schema.h" 2 | #include "shuffle_flow_init.h" 3 | #include "shuffle_flow_source.h" 4 | #include "shuffle_flow_target.h" 5 | #include "combiner_flow_init.h" 6 | #include "combiner_flow_source.h" 7 | #include "combiner_flow_target.h" 8 | #include "replicate_flow_init.h" 9 | #include "replicate_flow_source.h" 10 | #include "replicate_flow_target.h" 11 | #include "flow_barrier_init.h" 12 | #include "flow_barrier.h" 13 | 14 | #include "dfi_node.h" 15 | #include "registry_server.h" 16 | 17 | #include "../dfi/registry/RegistryClient.h" 18 | #include "../dfi/registry/RegistryServer.h" 19 | -------------------------------------------------------------------------------- /src/flow-api/registry_server.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../dfi/registry/RegistryServer.h" 4 | 5 | 6 | class DFI_Registry_server final: public RegistryServer 7 | { 8 | public: 9 | /** 10 | * @brief Construct a new dfi registry server object. Registry Server is a central DFI instance that coordinates flow and stores flow meta data. 11 | * Important: DFI_Registry_server must be constructed before any flows are initialized. 12 | * 13 | * @param mem_size 14 | */ 15 | DFI_Registry_server(size_t mem_size = Config::DFI_REGISTRY_RDMA_MEM) : RegistryServer(mem_size) {} 16 | }; -------------------------------------------------------------------------------- /src/gtest/examples/combiner_flow_examples.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file CombinerFlowExamples.h 3 | * @author lthostrup 4 | * @date 2019-08-01 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include "../../flow-api/dfi.h" 12 | #include "../../dfi/registry/RegistryServer.h" 13 | #include "../../dfi/memory/NodeServer.h" 14 | 15 | class CombinerFlowExamples : public testing::Test 16 | { 17 | 18 | public: 19 | void SetUp() override; 20 | void TearDown() override; 21 | 22 | protected: 23 | 24 | std::unique_ptr m_regServer; 25 | std::unique_ptr m_nodeServer; 26 | }; -------------------------------------------------------------------------------- /src/gtest/examples/replicate_flow_examples.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ReplicateFlowExamples.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2018-08-17 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include "../../flow-api/dfi.h" 12 | #include "../../dfi/registry/RegistryServer.h" 13 | #include "../../dfi/memory/NodeServer.h" 14 | 15 | class ReplicateFlowExamples : public testing::Test 16 | { 17 | 18 | public: 19 | size_t targets = 2; 20 | void SetUp() override; 21 | void TearDown() override; 22 | 23 | protected: 24 | RegistryServer *m_regServer; 25 | vector m_nodeServers; 26 | }; -------------------------------------------------------------------------------- /src/dfi/memory/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(DFI_SRC 3 | NodeClient.h 4 | NodeClient.cc 5 | NodeServer.h 6 | NodeServer.cc 7 | BufferWriter.h 8 | BufferWriter.cc 9 | BufferWriterLocal.h 10 | BufferHandle.h 11 | BufferWriterMulticast.h 12 | ) # Adding headers required for portability reasons http://voices.canonical.com/jussi.pakkanen/2013/03/26/a-list-of-common-cmake-antipatterns/ 13 | add_library(memory_dfi ${DFI_SRC}) 14 | target_include_directories(memory_dfi PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 15 | target_link_libraries(memory_dfi 16 | registry_dfi 17 | rdma_lib 18 | dfi_message 19 | utils 20 | ) 21 | -------------------------------------------------------------------------------- /src/dfi/type/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TYPE_SRC 2 | SmallInt.h 3 | SmallInt.cc 4 | Int.h 5 | Int.cc 6 | BigInt.h 7 | BigInt.cc 8 | UBigInt.h 9 | UBigInt.cc 10 | Floating.h 11 | Floating.cc 12 | Double.h 13 | Double.cc 14 | TinyInt.h 15 | TinyInt.cc 16 | Schema.h 17 | Tuple.h 18 | Type.h 19 | Type.cc 20 | TypeId.h 21 | Value.h 22 | Value.cc 23 | ) # Adding headers required for portability reasons http://voices.canonical.com/jussi.pakkanen/2013/03/26/a-list-of-common-cmake-antipatterns/ 24 | add_library(type_dfi ${TYPE_SRC}) 25 | target_include_directories(type_dfi PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 26 | target_link_libraries(type_dfi 27 | ) -------------------------------------------------------------------------------- /src/use-cases/utils/ThreadUtil.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | static void set_thread_affinity(int threadid) 6 | { 7 | cpu_set_t cpuset; 8 | CPU_ZERO(&cpuset); 9 | CPU_SET(threadid, &cpuset); 10 | sched_setaffinity(0, sizeof(cpuset), &cpuset); 11 | } 12 | 13 | 14 | inline static void busySleep(size_t sleep_us) { 15 | if (sleep_us == 0) 16 | return; 17 | auto start = std::chrono::system_clock::now(); 18 | auto now = start; 19 | while(std::chrono::duration_cast(now - start).count() < (int64_t)sleep_us) 20 | { 21 | now = std::chrono::system_clock::now(); 22 | } 23 | } -------------------------------------------------------------------------------- /src/dfi/memory/NodeServer.cc: -------------------------------------------------------------------------------- 1 | #include "NodeServer.h" 2 | 3 | NodeServer::NodeServer(): NodeServer(rdma::Config::RDMA_MEMSIZE, Config::DFI_NODE_PORT) {} 4 | 5 | NodeServer::NodeServer(uint64_t memsize): NodeServer(memsize, Config::DFI_NODE_PORT) {} 6 | 7 | NodeServer::NodeServer(uint64_t memsize, uint16_t port): NodeServer(memsize, port, (int)rdma::Config::RDMA_NUMAREGION) {} 8 | 9 | NodeServer::NodeServer(uint64_t memsize, uint16_t port, int numaNode) : rdma::RDMAServer("NodeServer", port, memsize, numaNode) { 10 | if (!rdma::RDMAServer::isRunning()) 11 | { 12 | rdma::RDMAServer::startServer(); 13 | } 14 | } -------------------------------------------------------------------------------- /src/dfi/message/DFIRetrieveFlowHandleResponse.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dfi; 3 | 4 | message DFIRetrieveFlowHandleResponse { 5 | string name = 1; 6 | repeated uint64 sources = 2; 7 | repeated uint64 source_nodeids = 3; 8 | repeated uint64 targets = 4; 9 | repeated uint64 target_nodeids = 5; 10 | repeated uint32 schema_column_types = 6; 11 | repeated string schema_column_names = 7; 12 | uint32 grouping_key_index = 8; 13 | uint32 flowType = 9; 14 | uint32 segments_per_ring = 10; 15 | uint64 segment_sizes = 11; 16 | uint32 optimization = 12; 17 | uint32 aggr_func = 13; 18 | string multicast_address = 14; 19 | uint64 global_seq_offset = 15; 20 | uint32 return = 16; 21 | } 22 | -------------------------------------------------------------------------------- /src/use-cases/distributed-radix-join-flow/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(FLOW_RADIX_JOIN_CPP 3 | Settings.h 4 | Settings.cc 5 | utils/Thread.h 6 | utils/Thread.cc 7 | utils/ThreadScheduler.h 8 | utils/ThreadScheduler.cc 9 | ) # Adding headers required for portability reasons http://voices.canonical.com/jussi.pakkanen/2013/03/26/a-list-of-common-cmake-antipatterns/ 10 | add_library(flow_radix_join_use_case ${FLOW_RADIX_JOIN_CPP}) 11 | target_include_directories(flow_radix_join_use_case PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) 12 | 13 | add_executable(distributed_radix_join_flow Main.cc) 14 | 15 | target_link_libraries(distributed_radix_join_flow 16 | flow_api 17 | flow_radix_join_use_case 18 | ) 19 | -------------------------------------------------------------------------------- /src/use-cases/rsm-paxos/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(RSMPAXOS_CPP 2 | PaxosLeader.h 3 | PaxosAcceptor.h 4 | utils/Thread.h 5 | utils/Thread.cc 6 | utils/ThreadScheduler.h 7 | utils/ThreadScheduler.cc 8 | Settings.h 9 | Settings.cc 10 | ) # Adding headers required for portability reasons http://voices.canonical.com/jussi.pakkanen/2013/03/26/a-list-of-common-cmake-antipatterns/ 11 | add_library(rsmpaxos_lib ${RSMPAXOS_CPP}) 12 | target_include_directories(rsmpaxos_lib PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) 13 | set_target_properties(rsmpaxos_lib PROPERTIES LINKER_LANGUAGE CXX) 14 | 15 | add_executable(rsm_paxos Main.cc) 16 | 17 | target_link_libraries(rsm_paxos 18 | flow_api 19 | rsmpaxos_lib 20 | ) -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/Settings.cc: -------------------------------------------------------------------------------- 1 | #include "Settings.h" 2 | 3 | const string Settings::LEFT_REL_FLOW_NAME = "LEFT RELATION FLOW"; 4 | const string Settings::RIGHT_REL_FLOW_NAME = "RIGHT RELATION FLOW"; 5 | 6 | 7 | uint64_t Settings::LEFT_REL_FULL_SIZE = 0; 8 | uint64_t Settings::RIGHT_REL_FULL_SIZE = 0; 9 | 10 | uint64_t Settings::LEFT_REL_SIZE = 0; 11 | uint64_t Settings::RIGHT_REL_SIZE = 0; 12 | 13 | uint32_t Settings::NODE_ID = 0; 14 | uint32_t Settings::NODES_TOTAL = 0; 15 | 16 | uint32_t Settings::PART_THREADS_COUNT = 0; 17 | uint32_t Settings::TOTAL_THREADS_COUNT = 0; 18 | 19 | uint32_t Settings::TUPLE_SEND_COUNT = 1024; 20 | 21 | bool Settings::RANDOM_ORDER = false; 22 | 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | 5 | # Mac files 6 | .DS_Store 7 | 8 | # Compiled Object files 9 | *.slo 10 | *.lo 11 | *.o 12 | *.obj 13 | 14 | # Precompiled Headers 15 | *.gch 16 | *.pch 17 | 18 | # CMake generated install files 19 | install_manifest.txt 20 | CMakeFiles/ 21 | 22 | # Compiled Dynamic libraries 23 | *.so 24 | *.so.* 25 | *.dylib 26 | *.dll 27 | 28 | # Fortran module files 29 | *.mod 30 | *.smod 31 | 32 | # Compiled Static libraries 33 | *.lai 34 | *.la 35 | *.a 36 | *.lib 37 | 38 | # Executables 39 | *.exe 40 | *.out 41 | *.app 42 | 43 | # vscode 44 | .vscode/ 45 | build/ 46 | 47 | 48 | #custom 49 | radix_*_REL_* 50 | histogram_bench_table 51 | output.log 52 | .editorconfig 53 | __pycache__/ -------------------------------------------------------------------------------- /src/use-cases/rsm-nopaxos/utils/Thread.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Thread.cpp 3 | * 4 | * Created on: 06.01.2015 5 | * Author: cbinnig 6 | */ 7 | 8 | #include "Thread.h" 9 | #include "ThreadScheduler.h" 10 | 11 | void utils::Thread::setFinished(bool finished) { 12 | std::unique_lock lck(thread_mutex); 13 | this->finished = finished; 14 | thread_cv.notify_all(); 15 | lck.unlock(); 16 | } 17 | 18 | void utils::Thread::start() { 19 | this->setFinished(0); 20 | ThreadScheduler::push(this); 21 | } 22 | 23 | void utils::Thread::join() { 24 | std::unique_lock lck(thread_mutex); 25 | 26 | if (this->finished){ 27 | lck.unlock(); 28 | return; 29 | } 30 | 31 | thread_cv.wait(lck); 32 | lck.unlock(); 33 | } -------------------------------------------------------------------------------- /src/use-cases/rsm-paxos/utils/Thread.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Thread.cpp 3 | * 4 | * Created on: 06.01.2015 5 | * Author: cbinnig 6 | */ 7 | 8 | #include "Thread.h" 9 | #include "ThreadScheduler.h" 10 | 11 | void utils::Thread::setFinished(bool finished) { 12 | std::unique_lock lck(thread_mutex); 13 | this->finished = finished; 14 | thread_cv.notify_all(); 15 | lck.unlock(); 16 | } 17 | 18 | void utils::Thread::start() { 19 | this->setFinished(0); 20 | ThreadScheduler::push(this); 21 | } 22 | 23 | void utils::Thread::join() { 24 | std::unique_lock lck(thread_mutex); 25 | 26 | if (this->finished){ 27 | lck.unlock(); 28 | return; 29 | } 30 | 31 | thread_cv.wait(lck); 32 | lck.unlock(); 33 | } -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(FLOW_REPLICATE_JOIN_CPP 3 | Settings.h 4 | Settings.cc 5 | utils/Thread.h 6 | utils/Thread.cc 7 | utils/ThreadScheduler.h 8 | utils/ThreadScheduler.cc 9 | ) # Adding headers required for portability reasons http://voices.canonical.com/jussi.pakkanen/2013/03/26/a-list-of-common-cmake-antipatterns/ 10 | add_library(flow_replicate_join_use_case ${FLOW_REPLICATE_JOIN_CPP}) 11 | target_include_directories(flow_replicate_join_use_case PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) 12 | 13 | 14 | add_executable(distributed_replicate_join_flow Main.cc) 15 | target_link_libraries(distributed_replicate_join_flow 16 | flow_api 17 | flow_replicate_join_use_case 18 | ) 19 | -------------------------------------------------------------------------------- /src/use-cases/distributed-radix-join-flow/utils/Thread.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Thread.cpp 3 | * 4 | * Created on: 06.01.2015 5 | * Author: cbinnig 6 | */ 7 | 8 | #include "Thread.h" 9 | #include "ThreadScheduler.h" 10 | 11 | void utils::Thread::setFinished(bool finished) { 12 | std::unique_lock lck(thread_mutex); 13 | this->finished = finished; 14 | thread_cv.notify_all(); 15 | lck.unlock(); 16 | } 17 | 18 | void utils::Thread::start() { 19 | this->setFinished(0); 20 | ThreadScheduler::push(this); 21 | } 22 | 23 | void utils::Thread::join() { 24 | std::unique_lock lck(thread_mutex); 25 | 26 | if (this->finished){ 27 | lck.unlock(); 28 | return; 29 | } 30 | 31 | thread_cv.wait(lck); 32 | lck.unlock(); 33 | } -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/utils/Thread.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Thread.cpp 3 | * 4 | * Created on: 06.01.2015 5 | * Author: cbinnig 6 | */ 7 | 8 | #include "Thread.h" 9 | #include "ThreadScheduler.h" 10 | 11 | void utils::Thread::setFinished(bool finished) { 12 | std::unique_lock lck(thread_mutex); 13 | this->finished = finished; 14 | thread_cv.notify_all(); 15 | lck.unlock(); 16 | } 17 | 18 | void utils::Thread::start() { 19 | this->setFinished(0); 20 | ThreadScheduler::push(this); 21 | } 22 | 23 | void utils::Thread::join() { 24 | std::unique_lock lck(thread_mutex); 25 | 26 | if (this->finished){ 27 | lck.unlock(); 28 | return; 29 | } 30 | 31 | thread_cv.wait(lck); 32 | lck.unlock(); 33 | } -------------------------------------------------------------------------------- /src/flow-api/flow_barrier_init.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file flow_barrier_init.h 3 | * @author lthostrup 4 | * @date 2020-03-01 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../utils/Config.h" 10 | #include "schema.h" 11 | #include "../dfi/registry/RegistryClient.h" 12 | #include "../dfi/type/ErrorCodes.h" 13 | 14 | /** 15 | * @brief DFI_Flow_barrier_init initializes a barrier for a pre-initialized flow. 16 | * 17 | * @param name Unique flow name identifier 18 | * @return int - Return status 19 | */ 20 | inline int DFI_Flow_barrier_init(std::string &name) 21 | { 22 | dfi::RegistryClient regClient; 23 | size_t offset; 24 | if (!regClient.getFlowBarrierOffset(name, offset)) 25 | return DFI_FAILURE; 26 | return DFI_SUCCESS; 27 | }; 28 | -------------------------------------------------------------------------------- /src/use-cases/rsm-nopaxos/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(RSMNOPAXOS_CPP 2 | utils/HashTable.h 3 | utils/Thread.h 4 | utils/Thread.cc 5 | utils/ThreadScheduler.h 6 | utils/ThreadScheduler.cc 7 | NoPaxosAcceptor.h 8 | NoPaxosClient.h 9 | KV_SM.h 10 | Settings.h 11 | Settings.cc 12 | ) # Adding headers required for portability reasons http://voices.canonical.com/jussi.pakkanen/2013/03/26/a-list-of-common-cmake-antipatterns/ 13 | add_library(rsmnopaxos_lib ${RSMNOPAXOS_CPP}) 14 | target_include_directories(rsmnopaxos_lib PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) 15 | set_target_properties(rsmnopaxos_lib PROPERTIES LINKER_LANGUAGE CXX) 16 | 17 | add_executable(rsm_nopaxos Main.cc) 18 | 19 | target_link_libraries(rsm_nopaxos 20 | flow_api 21 | rsmnopaxos_lib 22 | ) -------------------------------------------------------------------------------- /src/use-cases/rsm-paxos/utils/Thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Thread.hpp 3 | * 4 | * Created on: 03.01.2015 5 | * Author: cbinnig 6 | */ 7 | 8 | #ifndef THREAD_RDMA_HPP_ 9 | #define THREAD_RDMA_HPP_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | // #include "../Config.hpp" 17 | namespace utils 18 | { 19 | 20 | class Thread { 21 | private: 22 | bool finished = 0; 23 | std::mutex thread_mutex; 24 | std::condition_variable thread_cv; 25 | 26 | public: 27 | virtual ~Thread(){} 28 | 29 | void start(); 30 | 31 | virtual void run(){}; 32 | 33 | void join(); 34 | 35 | void setFinished(bool finished); 36 | 37 | int tid; 38 | }; 39 | 40 | } 41 | 42 | #endif /* THREAD_RDMA_HPP_ */ 43 | -------------------------------------------------------------------------------- /src/use-cases/rsm-nopaxos/utils/Thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Thread.hpp 3 | * 4 | * Created on: 03.01.2015 5 | * Author: cbinnig 6 | */ 7 | 8 | #ifndef THREAD_RDMA_HPP_ 9 | #define THREAD_RDMA_HPP_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | // #include "../Config.hpp" 17 | namespace utils 18 | { 19 | 20 | class Thread { 21 | private: 22 | bool finished = 0; 23 | std::mutex thread_mutex; 24 | std::condition_variable thread_cv; 25 | 26 | public: 27 | virtual ~Thread(){} 28 | 29 | void start(); 30 | 31 | virtual void run(){}; 32 | 33 | void join(); 34 | 35 | void setFinished(bool finished); 36 | 37 | int tid; 38 | }; 39 | 40 | } 41 | 42 | #endif /* THREAD_RDMA_HPP_ */ 43 | -------------------------------------------------------------------------------- /src/use-cases/distributed-radix-join-flow/utils/Thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Thread.hpp 3 | * 4 | * Created on: 03.01.2015 5 | * Author: cbinnig 6 | */ 7 | 8 | #ifndef THREAD_RDMA_HPP_ 9 | #define THREAD_RDMA_HPP_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | // #include "../Config.hpp" 17 | namespace utils 18 | { 19 | 20 | class Thread { 21 | private: 22 | bool finished = 0; 23 | std::mutex thread_mutex; 24 | std::condition_variable thread_cv; 25 | 26 | public: 27 | virtual ~Thread(){} 28 | 29 | void start(); 30 | 31 | virtual void run(){}; 32 | 33 | void join(); 34 | 35 | void setFinished(bool finished); 36 | 37 | int tid; 38 | }; 39 | 40 | } 41 | 42 | #endif /* THREAD_RDMA_HPP_ */ 43 | -------------------------------------------------------------------------------- /src/gtest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(GTest REQUIRED) 2 | enable_testing() 3 | 4 | MACRO(SUBDIRLIST result curdir) 5 | FILE(GLOB children RELATIVE ${curdir} ${curdir}/*) 6 | SET(dirlist "") 7 | FOREACH(child ${children}) 8 | IF(IS_DIRECTORY ${curdir}/${child}) 9 | LIST(APPEND dirlist ${child}) 10 | ENDIF() 11 | ENDFOREACH() 12 | SET(${result} ${dirlist}) 13 | ENDMACRO() 14 | 15 | SUBDIRLIST(SUBDIRS ".") 16 | 17 | include_directories(${GTEST_INCLUDE_DIRS}) 18 | foreach(subdir ${SUBDIRS}) 19 | include_directories(${subdir}) 20 | endforeach() 21 | 22 | file(GLOB test_SRC ./*/*.cc) 23 | message(${test_SRC}) 24 | 25 | add_executable(gtests ${test_SRC}) 26 | # Standard linking to gtest stuff. 27 | target_link_libraries(gtests GTest::GTest pthread 28 | GTest::Main 29 | flow_api) -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/utils/Thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Thread.hpp 3 | * 4 | * Created on: 03.01.2015 5 | * Author: cbinnig 6 | */ 7 | 8 | #ifndef THREAD_RDMA_HPP_ 9 | #define THREAD_RDMA_HPP_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | // #include "../Config.hpp" 17 | namespace utils 18 | { 19 | 20 | class Thread { 21 | private: 22 | bool finished = 0; 23 | std::mutex thread_mutex; 24 | std::condition_variable thread_cv; 25 | 26 | public: 27 | virtual ~Thread(){} 28 | 29 | void start(); 30 | 31 | virtual void run(){}; 32 | 33 | void join(); 34 | 35 | void setFinished(bool finished); 36 | 37 | int tid; 38 | }; 39 | 40 | } 41 | 42 | #endif /* THREAD_RDMA_HPP_ */ 43 | -------------------------------------------------------------------------------- /src/use-cases/rsm-nopaxos/Settings.cc: -------------------------------------------------------------------------------- 1 | #include "Settings.h" 2 | 3 | string Settings::BENCH_FILE="bench.data"; 4 | 5 | string Settings::FLOWNAME_OUM = "ordered_unreliable_multicast_flow"; 6 | string Settings::FLOWNAME_RESPONSE = "client_response_flow"; 7 | 8 | string Settings::FLOWNAME_GAP_LEADER = "leader_gap_agreement_flow"; 9 | string Settings::FLOWNAME_GAP_FOLLOWER = "follower_gap_agreement_flow"; 10 | 11 | string Settings::FLOWNAME_VERIFICATION = "verification_flow"; 12 | 13 | NodeID Settings::LEADER_ID = 0; 14 | NodeID Settings::NODE_ID = 0; 15 | NodeID Settings::REGISTRY_ID = 0; 16 | NodeID Settings::SEQUENCER_ID = 0; 17 | uint64_t Settings::COMMAND_COUNT = 0; 18 | uint64_t Settings::COMMANDS_PER_SECOND = 0; 19 | size_t Settings::REPLICA_COUNT = 0; 20 | size_t Settings::CLIENT_COUNT = 0; -------------------------------------------------------------------------------- /src/dfi/type/Type.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Type.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2019-01-14 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../../utils/Config.h" 10 | #include "TypeId.h" 11 | 12 | namespace dfi 13 | { 14 | class Type 15 | { 16 | public: 17 | 18 | Type(TypeId typeId) : m_typeId(typeId) {} 19 | 20 | virtual ~Type() {} 21 | 22 | static uint64_t getTypeSize(TypeId typeId); 23 | 24 | inline TypeId getTypeId() const { return m_typeId; } 25 | 26 | inline static Type* getInstance(TypeId typeId) { return m_instTypes[static_cast(typeId)]; } 27 | 28 | protected: 29 | TypeId m_typeId; 30 | 31 | // Singleton instances of the types 32 | static Type* m_instTypes[]; //array size should match size of TypeId enum! 33 | }; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/use-cases/rsm-paxos/Settings.cc: -------------------------------------------------------------------------------- 1 | #include "Settings.h" 2 | 3 | string Settings::FLOWNAME_CLIENT_REQ = "CLIENT REQ FLOW"; 4 | string Settings::FLOWNAME_CLIENT_RESP = "CLIENT RESP FLOW"; 5 | string Settings::FLOWNAME_P1REQ = "PHASE 1 REQUEST FLOW"; 6 | string Settings::FLOWNAME_P2REQ = "PHASE 2 REQUEST FLOW"; 7 | string Settings::FLOWNAME_P1RESP = "PHASE 1 RESPONSE FLOW"; 8 | string Settings::FLOWNAME_P2RESP = "PHASE 2 RESPONSE FLOW"; 9 | string Settings::FLOWNAME_VERIFICATION = "LOG VERIFICATION FLOW"; 10 | 11 | string Settings::BENCH_FILE = "bench.data"; 12 | Mode Settings::MODE = Mode::ASYNCHRONOUS; 13 | NodeID Settings::LEADER_ID = 0; 14 | NodeID Settings::NODE_ID = 0; 15 | uint64_t Settings::COMMAND_COUNT = 0; 16 | uint64_t Settings::COMMANDS_PER_SECOND = 0; 17 | size_t Settings::REPLICA_COUNT = 0; 18 | size_t Settings::CLIENT_COUNT = 0; -------------------------------------------------------------------------------- /src/dfi/message/MessageErrors.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef DFI_MESSAGEERRORS_H_ 4 | #define DFI_MESSAGEERRORS_H_ 5 | 6 | #include "../../utils/Config.h" 7 | 8 | namespace dfi { 9 | 10 | enum MessageErrors 11 | : unsigned int { 12 | 13 | NO_ERROR = 0, 14 | INVALID_MESSAGE, // make use of auto-increment 15 | 16 | DFI_CREATE_RING_ON_BUF_FAILED = 500, 17 | DFI_RTRV_BUFFHANDLE_FAILED = 501, 18 | DFI_APPEND_BUFFHANDLE_FAILED = 502, 19 | DFI_REGISTER_BUFFHANDLE_FAILED = 503, 20 | DFI_JOIN_BUFFER_FAILED = 504, 21 | DFI_NO_BUFFER_FOUND = 505, 22 | DFI_ALLOCATE_SEGMENT_FAILED = 506, 23 | 24 | DFI_CREATE_FLOW_FAILED = 600, 25 | DFI_RTRV_FLOWHANDLE_FAILED = 601, 26 | DFI_NO_FLOW_FOUND = 602, 27 | DFI_CREATE_COMBINER_FLOW_FAILED = 603, 28 | DFI_INSUFFICIENT_MEM = 604, 29 | }; 30 | 31 | } 32 | 33 | #endif /* DFI_MESSAGEERRORS_H_ */ 34 | -------------------------------------------------------------------------------- /src/dfi/message/DFICreateFlowRequest.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dfi; 3 | 4 | message DFICreateFlowRequest { 5 | string name = 1; 6 | repeated uint64 sources = 2; 7 | repeated uint64 source_nodeids = 3; 8 | repeated uint64 targets = 4; 9 | repeated uint64 target_nodeids = 5; 10 | repeated uint32 schema_column_types = 6; 11 | repeated string schema_column_names = 7; 12 | uint32 grouping_key_index = 8; 13 | uint32 flowType = 9; 14 | uint32 segments_per_ring = 10; 15 | uint64 segment_sizes = 11; 16 | uint32 optimization = 12; 17 | uint32 aggr_func = 13; 18 | bool cache_align_segs = 14; 19 | repeated DFITargetOptions target_options = 15; 20 | } 21 | 22 | message DFITargetOptions { 23 | uint64 target = 1; 24 | uint64 full_segment_size = 2; 25 | uint64 segments_per_ring = 3; 26 | uint32 target_placement = 4; 27 | } -------------------------------------------------------------------------------- /src/flow-api/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(FLOW_API_SRC 2 | dfi.h 3 | schema.h 4 | shuffle_flow_init.h 5 | shuffle_flow_source.h 6 | shuffle_flow_target.h 7 | combiner_flow_init.h 8 | combiner_flow_source.h 9 | combiner_flow_target.h 10 | replicate_flow_init.h 11 | replicate_flow_source.h 12 | replicate_flow_target.h 13 | flow_barrier_init.h 14 | flow_barrier.h 15 | dfi_node.h 16 | registry_server.h 17 | ) # Adding headers required for portability reasons http://voices.canonical.com/jussi.pakkanen/2013/03/26/a-list-of-common-cmake-antipatterns/ 18 | add_library(flow_api ${FLOW_API_SRC}) 19 | target_include_directories(flow_api PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 20 | target_link_libraries(flow_api 21 | memory_dfi 22 | flow_dfi 23 | ) 24 | 25 | set_target_properties(flow_api PROPERTIES CUDA_SEPARABLE_COMPILATION ON) 26 | set_target_properties(flow_api PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS ON) -------------------------------------------------------------------------------- /src/dfi/memory/BufferWriter.cc: -------------------------------------------------------------------------------- 1 | #include "BufferWriter.h" 2 | 3 | 4 | #include 5 | 6 | 7 | //BufferWriter must be constructed with cacheAlignedSegments = true, in order to use nontemp!! 8 | bool BufferWriter::add_nontemp64B(void *data, bool forceSignaled = false) 9 | { 10 | // std::cout << "Adding " << ((size_t*)data)[0] << " to " << m_outputBuffer->offset << '\n'; 11 | auto dst = reinterpret_cast(m_curSegment) + m_outputBuffer->offset; 12 | // __m512i s1 = _mm512_loadu_si512(data); 13 | _mm512_stream_si512((__m512i*)dst, *(__m512i*)data); 14 | // memcpy(dst, data, 64); 15 | m_outputBuffer->offset += 64; 16 | assert(m_outputBuffer->offset <= m_handle->segmentSizes); 17 | 18 | if (m_outputBuffer->offset == m_handle->segmentSizes) 19 | { 20 | flush(forceSignaled); 21 | // std::cout << "Flushing " << std::endl; 22 | } 23 | return true; 24 | }; 25 | -------------------------------------------------------------------------------- /src/dfi/type/EnumTypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../utils/Config.h" 4 | 5 | namespace dfi 6 | { 7 | enum FlowType 8 | { 9 | SHUFFLE, 10 | COMBINER, 11 | REPLICATE 12 | }; 13 | enum AggrFunc 14 | { 15 | SUM, 16 | SUB, 17 | MEAN, 18 | MULT, 19 | MAX, 20 | MIN, 21 | NONE 22 | }; 23 | 24 | /** 25 | * @brief Determines when the Consumer proceeds to a new segment-ring. 26 | * If ASYNC: if Consumer encounter an empty segment-ring, it proceeds to next ring to find a consumable segment. 27 | * If SYNC: Consumer will ensure a segment is consumed before advancing to next segment-ring. I.e. a source can not have 2 segments consumed before all others have at least 1 segment consumed. 28 | * 29 | */ 30 | enum ConsumeScheme 31 | { 32 | ASYNC, 33 | SYNC 34 | }; 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/flow-api/dfi_node.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../dfi/memory/NodeServer.h" 4 | 5 | 6 | class DFI_Node final : public NodeServer 7 | { 8 | public: 9 | /** 10 | * @brief Construct a new dfi node object. A DFI_Node is an instance deployed on nodes for (potentially multiple) targets to identify to. 11 | * DFI_Node must be addresseable through DFI_Nodes vector in dfi::Config 12 | * 13 | * @param memsize Size of the internal memory. Must be larger than the needed memory for the flows 14 | * @param port Port listening for out-of-band communication 15 | * @param numaNode Performs all memory allocations on the specified numa node. Parameter takes presedence over the rdma::Config::RDMA_NUMAREGION. 16 | */ 17 | DFI_Node(uint16_t port = dfi::Config::DFI_NODE_PORT, uint64_t memsize = rdma::Config::RDMA_MEMSIZE, int numaNode = rdma::Config::RDMA_NUMAREGION) : NodeServer(memsize, port, numaNode) 18 | {} 19 | }; -------------------------------------------------------------------------------- /src/dfi/memory/BufferSegment.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BufferSegment.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2018-07-06 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../../utils/Config.h" 10 | #include "local_iterators/SegmentIterator.h" 11 | 12 | namespace dfi 13 | { 14 | /** 15 | * @brief BufferSegments are stored in a ring-buffer fashion, with the DFI_SEGMENT_HEADER_t holding a ptr to the next segment in the ring 16 | * 17 | */ 18 | struct BufferSegment 19 | { 20 | size_t offset; 21 | size_t size; //Size of data portion (without header) 22 | 23 | BufferSegment(){}; 24 | BufferSegment(size_t offset, size_t size) : offset(offset), size(size){}; 25 | 26 | 27 | SegmentIterator begin(char *rdmaBuffer, size_t ringSize) 28 | { 29 | return SegmentIterator(offset, size, rdmaBuffer, ringSize); 30 | } 31 | 32 | SegmentIterator end() 33 | { 34 | return SegmentIterator::getEndSegmentIterator(); 35 | } 36 | }; 37 | 38 | } -------------------------------------------------------------------------------- /src/dfi/type/Type.cc: -------------------------------------------------------------------------------- 1 | #include "Type.h" 2 | #include "SmallInt.h" 3 | #include "Int.h" 4 | #include "BigInt.h" 5 | #include "UBigInt.h" 6 | #include "Double.h" 7 | #include "Floating.h" 8 | #include "TinyInt.h" 9 | 10 | Type* Type::m_instTypes[] = { //construct in same order as TypeId! 11 | new Type(TypeId::INVALID), 12 | new SmallInt(), 13 | new Int(), 14 | new BigInt(), 15 | new UBigInt(), 16 | new Floating(), 17 | new Double(), 18 | new TinyInt() 19 | }; 20 | 21 | uint64_t Type::getTypeSize(const TypeId type_id) { 22 | switch (type_id) { 23 | case TypeId::SMALLINT: 24 | return 2; 25 | case TypeId::INT: 26 | return 4; 27 | case TypeId::BIGINT: 28 | return 8; 29 | case TypeId::BIGUINT: 30 | return 8; 31 | case TypeId::FLOAT: 32 | return 4; 33 | case TypeId::DOUBLE: 34 | return 8; 35 | case TypeId::TINYINT: 36 | return 1; 37 | default: 38 | break; 39 | } 40 | return 0; 41 | } -------------------------------------------------------------------------------- /src/conf/DFI.conf: -------------------------------------------------------------------------------- 1 | LOGGING_LEVEL=3 2 | # DFI_NODES = 172.18.94.10:7400,172.18.94.11:7400,172.18.94.20:7400,172.18.94.21:7400 3 | # DFI_NODES = 172.18.94.10:7400,172.18.94.11:7400,172.18.94.20:7400,172.18.94.21:7400,172.18.94.30:7400,172.18.94.31:7400,172.18.94.40:7400,172.18.94.41:7400 4 | DFI_NODES = 172.18.94.11:7400,172.18.94.21:7400,172.18.94.31:7400,172.18.94.41:7400 5 | # DFI_NODES = 172.18.94.10:7400,172.18.94.20:7400,172.18.94.30:7400,172.18.94.40:7400 6 | # 7 | # DFI_NODES = 172.18.94.21:7400 8 | # DFI_NODES = 172.18.94.10:5400,172.18.94.20:5400,172.18.94.30:5400,172.18.94.40:5400,172.18.94.50:5400,172.18.94.60:5400,172.18.94.70:5400,172.18.94.80:5400 9 | # DFI_NODES = 172.18.94.10:5400,172.18.94.20:5400,172.18.94.30:5400,172.18.94.40:5400 10 | # DFI_REGISTRY_SERVER = 172.18.94.21 11 | # DFI_REGISTRY_SERVER = 172.18.94.10 12 | DFI_REGISTRY_SERVER = 172.18.94.11 13 | 14 | # DFI_REGISTRY_PORT = 5300 15 | # DFI_INTERNAL_BUFFER_SIZE = 4194304 16 | # DFI_FULL_SEGMENT_SIZE = 67108888 17 | # DFI_SEGMENTS_PER_RING = 10 -------------------------------------------------------------------------------- /src/dfi/message/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(Protobuf REQUIRED) 2 | include_directories($PROTOBUF_INCLUDE_DIRS}) 3 | file(GLOB PROTO_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.proto") 4 | PROTOBUF_GENERATE_CPP(DFI_PROTO_SRC PROTO_HDRS ${PROTO_FILES}) 5 | set(DFI_MESSAGE_SRC 6 | MessageTypes.h 7 | ) # Adding headers required for portability reasons http://voices.canonical.com/jussi.pakkanen/2013/03/26/a-list-of-common-cmake-antipatterns/ 8 | 9 | 10 | set(DFIProtobufIncludePath ${CMAKE_CURRENT_BINARY_DIR} 11 | CACHE INTERNAL "Path to generated protobuf files.") 12 | 13 | # As the protobuf files are generated by the build process, they will not be found 14 | # when collecting the sources for building the shared library. 15 | set(DFI_PROTO_SRC ${DFI_PROTO_SRC} CACHE INTERNAL "Generated protobuf source files") 16 | 17 | add_library(dfi_message ${DFI_MESSAGE_SRC} ${DFI_PROTO_SRC} ${PROTO_HDRS}) 18 | target_include_directories(dfi_message PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) 19 | target_link_libraries(dfi_message 20 | ${PROTOBUF_LIBRARIES} 21 | ) 22 | -------------------------------------------------------------------------------- /src/use-cases/distributed-radix-join-flow/utils/ThreadScheduler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ThreadScheduler.hpp 3 | * 4 | * Created on: 03.01.2015 5 | * Author: cbinnig 6 | */ 7 | 8 | #ifndef THREADSCHEDULER_HPP_ 9 | #define THREADSCHEDULER_HPP_ 10 | 11 | #ifndef _GNU_SOURCE 12 | #define _GNU_SOURCE 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | // #include "../Config.h" 22 | #include "Thread.h" 23 | namespace utils 24 | { 25 | class ThreadScheduler { 26 | private: 27 | static bool running; 28 | static std::thread* threads; 29 | static size_t numThreads; 30 | 31 | static std::queue pending; 32 | static std::mutex pending_mutex; 33 | static std::condition_variable pending_cv; 34 | 35 | static void doWork(int tid); 36 | 37 | public: 38 | static void start(size_t numThreads); 39 | 40 | static void push(Thread* t); 41 | 42 | static void stop(); 43 | 44 | static bool isRunning(); 45 | }; 46 | } 47 | #endif /* THREADSCHEDULER_HPP_ */ 48 | -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/utils/ThreadScheduler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ThreadScheduler.hpp 3 | * 4 | * Created on: 03.01.2015 5 | * Author: cbinnig 6 | */ 7 | 8 | #ifndef THREADSCHEDULER_HPP_ 9 | #define THREADSCHEDULER_HPP_ 10 | 11 | #ifndef _GNU_SOURCE 12 | #define _GNU_SOURCE 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | // #include "../Config.h" 22 | #include "Thread.h" 23 | namespace utils 24 | { 25 | class ThreadScheduler { 26 | private: 27 | static bool running; 28 | static std::thread* threads; 29 | static size_t numThreads; 30 | 31 | static std::queue pending; 32 | static std::mutex pending_mutex; 33 | static std::condition_variable pending_cv; 34 | 35 | static void doWork(int tid); 36 | 37 | public: 38 | static void start(size_t numThreads); 39 | 40 | static void push(Thread* t); 41 | 42 | static void stop(); 43 | 44 | static bool isRunning(); 45 | }; 46 | } 47 | #endif /* THREADSCHEDULER_HPP_ */ 48 | -------------------------------------------------------------------------------- /src/use-cases/rsm-paxos/KV_SM.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Log.h 3 | * @author jskrzypczak 4 | * Simple state machine of a key-value store. 5 | * @date 2020-06-15 6 | */ 7 | 8 | #pragma once 9 | 10 | #include 11 | #include "Settings.h" 12 | 13 | 14 | using hashtable = HashTable>; //KeyType, Hashmap-Size, Hashing-function 15 | 16 | 17 | class KV_Store 18 | { 19 | private: 20 | hashtable ht; 21 | 22 | public: 23 | KV_Store(); 24 | ~KV_Store(); 25 | bool insert(Command&); 26 | bool lookup(Command&, uint64_t&); 27 | }; 28 | 29 | KV_Store::KV_Store() : ht(HashStd(HT_SIZE-1), HT_SIZE) 30 | { 31 | 32 | } 33 | 34 | KV_Store::~KV_Store() 35 | { 36 | 37 | } 38 | 39 | inline bool KV_Store::insert(Command& cmd) 40 | { 41 | bool success = ht.insert(cmd.key, cmd.value); 42 | return success; 43 | } 44 | 45 | inline bool KV_Store::lookup(Command& cmd, uint64_t& value) 46 | { 47 | bool success = ht.find(cmd.key, value); 48 | return success; 49 | } 50 | -------------------------------------------------------------------------------- /src/use-cases/rsm-nopaxos/KV_SM.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Log.h 3 | * @author jskrzypczak 4 | * Simple state machine of a key-value store. 5 | * @date 2020-06-15 6 | */ 7 | 8 | #pragma once 9 | 10 | #include 11 | #include "Settings.h" 12 | 13 | 14 | using hashtable = HashTable>; //KeyType, Hashmap-Size, Hashing-function 15 | 16 | 17 | class KV_Store 18 | { 19 | private: 20 | hashtable ht; 21 | 22 | public: 23 | KV_Store(); 24 | ~KV_Store(); 25 | bool insert(Command&); 26 | bool lookup(Command&, uint64_t&); 27 | }; 28 | 29 | KV_Store::KV_Store() : ht(HashStd(HT_SIZE-1), HT_SIZE) 30 | { 31 | 32 | } 33 | 34 | KV_Store::~KV_Store() 35 | { 36 | 37 | } 38 | 39 | inline bool KV_Store::insert(Command& cmd) 40 | { 41 | bool success = ht.insert(cmd.key, cmd.value); 42 | return success; 43 | } 44 | 45 | inline bool KV_Store::lookup(Command& cmd, uint64_t& value) 46 | { 47 | bool success = ht.find(cmd.key, value); 48 | return success; 49 | } 50 | -------------------------------------------------------------------------------- /cmake/modules/FindRdmaCm.cmake: -------------------------------------------------------------------------------- 1 | FIND_PATH(RDMACM_INCLUDE_DIR rdma/rdma_verbs.h 2 | PATHS 3 | $ENV{RDMACM_HOME} 4 | NO_DEFAULT_PATH 5 | PATH_SUFFIXES include 6 | ) 7 | 8 | FIND_PATH(RDMACM_INCLUDE_DIR rdma/rdma_verbs.h 9 | PATHS 10 | /usr/local/include 11 | /usr/include 12 | /sw/include # Fink 13 | /opt/local/include # DarwinPorts 14 | /opt/csw/include # Blastwave 15 | /opt/include 16 | ) 17 | 18 | FIND_LIBRARY(RDMACM_LIBRARY 19 | NAMES rdmacm 20 | PATHS $ENV{RDMACM_HOME} 21 | NO_DEFAULT_PATH 22 | PATH_SUFFIXES lib64 lib 23 | ) 24 | 25 | FIND_LIBRARY(RDMACM_LIBRARY 26 | NAMES rdmacm 27 | PATHS 28 | /usr/local 29 | /usr 30 | /sw 31 | /opt/local 32 | /opt/csw 33 | /opt 34 | /usr/freeware 35 | PATH_SUFFIXES lib64 lib 36 | ) 37 | SET(RDMACM_FOUND FALSE) 38 | IF(RDMACM_LIBRARY AND RDMACM_INCLUDE_DIR) 39 | SET(RDMACM_FOUND TRUE) 40 | ENDIF(RDMACM_LIBRARY AND RDMACM_INCLUDE_DIR) 41 | 42 | include(FindPackageHandleStandardArgs) 43 | find_package_handle_standard_args(RdmaCm DEFAULT_MSG RDMACM_LIBRARY RDMACM_INCLUDE_DIR) 44 | 45 | mark_as_advanced(RDMACM_INCLUDE_DIR RDMACM_LIBRARIES) 46 | -------------------------------------------------------------------------------- /cmake/modules/FindIBVerbs.cmake: -------------------------------------------------------------------------------- 1 | FIND_PATH(IBVERBS_INCLUDE_DIR infiniband/verbs.h 2 | PATHS 3 | $ENV{IBVERBS_HOME} 4 | NO_DEFAULT_PATH 5 | PATH_SUFFIXES include 6 | ) 7 | 8 | FIND_PATH(IBVERBS_INCLUDE_DIR infiniband/verbs.h 9 | PATHS 10 | /usr/local/include 11 | /usr/include 12 | /sw/include # Fink 13 | /opt/local/include # DarwinPorts 14 | /opt/csw/include # Blastwave 15 | /opt/include 16 | ) 17 | 18 | FIND_LIBRARY(IBVERBS_LIBRARY 19 | NAMES ibverbs 20 | PATHS $ENV{IBVERBS_HOME} 21 | NO_DEFAULT_PATH 22 | PATH_SUFFIXES lib64 lib 23 | ) 24 | 25 | FIND_LIBRARY(IBVERBS_LIBRARY 26 | NAMES ibverbs 27 | PATHS 28 | /usr/local 29 | /usr 30 | /sw 31 | /opt/local 32 | /opt/csw 33 | /opt 34 | /usr/freeware 35 | PATH_SUFFIXES lib64 lib 36 | ) 37 | SET(IBVERBS_FOUND FALSE) 38 | IF(IBVERBS_LIBRARY AND IBVERBS_INCLUDE_DIR) 39 | SET(IBVERBS_FOUND TRUE) 40 | ENDIF(IBVERBS_LIBRARY AND IBVERBS_INCLUDE_DIR) 41 | 42 | include(FindPackageHandleStandardArgs) 43 | find_package_handle_standard_args(IBVerbs DEFAULT_MSG IBVERBS_LIBRARY IBVERBS_INCLUDE_DIR) 44 | 45 | mark_as_advanced(IBVERBS_INCLUDE_DIR IBVERBS_LIBRARIES) 46 | -------------------------------------------------------------------------------- /src/use-cases/rsm-nopaxos/utils/ThreadScheduler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ThreadScheduler.hpp 3 | * 4 | * Created on: 03.01.2015 5 | * Author: cbinnig 6 | */ 7 | 8 | #ifndef THREADSCHEDULER_HPP_ 9 | #define THREADSCHEDULER_HPP_ 10 | 11 | #ifndef _GNU_SOURCE 12 | #define _GNU_SOURCE 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | // #include "../Config.h" 22 | #include "Thread.h" 23 | namespace utils 24 | { 25 | class ThreadScheduler { 26 | private: 27 | const static int cpus[]; // = {10,11,12,13,14,15,16,17,18,19,30,31,32,33,34,35,36,37,38,39,0,1,2,3,4,5,6,7,8,9,20,21,22,23,24,25,26,27,28,29}; 28 | static bool running; 29 | static std::thread* threads; 30 | static size_t numThreads; 31 | 32 | static std::queue pending; 33 | static std::mutex pending_mutex; 34 | static std::condition_variable pending_cv; 35 | 36 | static void doWork(int tid); 37 | 38 | public: 39 | static void start(size_t numThreads); 40 | 41 | static void push(Thread* t); 42 | 43 | static void stop(); 44 | 45 | static bool isRunning(); 46 | }; 47 | } 48 | #endif /* THREADSCHEDULER_HPP_ */ 49 | -------------------------------------------------------------------------------- /src/use-cases/rsm-paxos/utils/ThreadScheduler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ThreadScheduler.hpp 3 | * 4 | * Created on: 03.01.2015 5 | * Author: cbinnig 6 | */ 7 | 8 | #ifndef THREADSCHEDULER_HPP_ 9 | #define THREADSCHEDULER_HPP_ 10 | 11 | #ifndef _GNU_SOURCE 12 | #define _GNU_SOURCE 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | // #include "../Config.h" 22 | #include "Thread.h" 23 | namespace utils 24 | { 25 | class ThreadScheduler { 26 | private: 27 | const static int cpus[]; // = {10,11,12,13,14,15,16,17,18,19,30,31,32,33,34,35,36,37,38,39,0,1,2,3,4,5,6,7,8,9,20,21,22,23,24,25,26,27,28,29}; 28 | static bool running; 29 | static std::thread* threads; 30 | static size_t numThreads; 31 | 32 | static std::queue pending; 33 | static std::mutex pending_mutex; 34 | static std::condition_variable pending_cv; 35 | 36 | static void doWork(int tid); 37 | 38 | public: 39 | static void start(size_t numThreads); 40 | 41 | static void push(Thread* t); 42 | 43 | static void stop(); 44 | 45 | static bool isRunning(); 46 | }; 47 | } 48 | #endif /* THREADSCHEDULER_HPP_ */ 49 | -------------------------------------------------------------------------------- /src/use-cases/rsm-paxos/Log.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Log.h 3 | * @author jskrzypczak 4 | * Quick-and-dirty represnatation of a command log. It is kept in-memory. 5 | * @date 2020-07-01 6 | */ 7 | 8 | #pragma once 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "Settings.h" 15 | 16 | class Log 17 | { 18 | private: 19 | size_t committed = 0; 20 | size_t highest_set = 0; 21 | size_t gapless_until = 0; 22 | 23 | std::vector log; 24 | public: 25 | Log(size_t); 26 | ~Log(); 27 | void set_slot(size_t, Command); 28 | Command get_slot(size_t); 29 | void set_committed(size_t); 30 | }; 31 | 32 | Log::Log(size_t logsize) : log(logsize, EMPTY_CMD) 33 | { 34 | } 35 | 36 | Log::~Log() 37 | { 38 | } 39 | 40 | void Log::set_slot(size_t slotid, Command cmd) 41 | { 42 | log[slotid] = cmd; 43 | while (log[gapless_until+1].operation != Operation::EMPTY) 44 | { 45 | gapless_until++; 46 | } 47 | highest_set = std::max(slotid, highest_set); 48 | } 49 | 50 | Command Log::get_slot(size_t slotid) 51 | { 52 | return log[slotid]; 53 | } 54 | 55 | void Log::set_committed(size_t pos) { 56 | committed = std::max(pos, committed); 57 | } 58 | -------------------------------------------------------------------------------- /src/use-cases/utils/StringHelper.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file StringHelper.h 3 | * @author cbinnig, tziegler 4 | * @date 2018-08-17 5 | */ 6 | 7 | #ifndef DFI_SRC_UTILS_STRINGHELPER_H_ 8 | #define DFI_SRC_UTILS_STRINGHELPER_H_ 9 | 10 | #include 11 | #include 12 | 13 | 14 | class StringHelper { 15 | public: 16 | static std::vector split(string value, string sep = ",") { 17 | std::vector values; 18 | char* cvalue = new char[value.length() + 1]; 19 | strcpy(cvalue, value.c_str()); 20 | char* token = strtok(cvalue, sep.c_str()); 21 | 22 | while (token) { 23 | values.push_back(token); 24 | token = strtok(nullptr, sep.c_str()); 25 | } 26 | 27 | delete[] cvalue; 28 | return values; 29 | } 30 | 31 | 32 | static void splitPerf(const string& value, std::vector& retValues ,string sep = ",") { 33 | char* cvalue = new char[value.length() + 1]; 34 | strcpy(cvalue, value.c_str()); 35 | char* token = strtok(cvalue, sep.c_str()); 36 | 37 | while (token) { 38 | retValues.emplace_back(token); 39 | token = strtok(nullptr, sep.c_str()); 40 | } 41 | delete[] cvalue; 42 | } 43 | 44 | }; 45 | 46 | #endif /* DFI_SRC_UTILS_STRINGHELPER_H_ */ 47 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.9) 2 | 3 | project(dfi) 4 | 5 | set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) 6 | set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) 7 | 8 | set(CMAKE_INSTALL_PREFIX "/usr/local/" CACHE PATH 9 | "Install path prefix, prepended onto install directories." FORCE) 10 | 11 | 12 | # for GDB debugging 13 | # set(CMAKE_BUILD_TYPE RelWithDebInfo) 14 | 15 | # Compiler Options 16 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLINUX -DHUGEPAGE -std=c++17 -pthread -Wall -Wextra -mavx -mavx2 -mavx512f -mavx512dq -mavx512cd -mavx512bw -fmax-errors=1")# -Werror") 17 | 18 | if (CMAKE_BUILD_TYPE STREQUAL "Debug") 19 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEBUG") #-fsanitize=address 20 | endif() 21 | 22 | if (CMAKE_BUILD_TYPE STREQUAL "Release") 23 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -flto") 24 | endif() 25 | 26 | if (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") 27 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -g") 28 | endif() 29 | 30 | 31 | # the compiler flags for compiling C++ sources 32 | MESSAGE( STATUS "CMAKE_CXX_FLAGS: " ${CMAKE_CXX_FLAGS} ) 33 | 34 | add_subdirectory(src) 35 | 36 | file(COPY 37 | ${CMAKE_CURRENT_SOURCE_DIR}/src/conf/DFI.conf 38 | DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/bin/conf/ 39 | ) 40 | -------------------------------------------------------------------------------- /src/use-cases/rsm-nopaxos/Log.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Log.h 3 | * @author jskrzypczak 4 | * Quick-and-dirty representation of a command log. It is kept in-memory. 5 | * @date 2020-07-01 6 | */ 7 | 8 | #pragma once 9 | 10 | #include "Settings.h" 11 | 12 | #include 13 | 14 | class Log 15 | { 16 | private: 17 | volatile uint64_t last_slot_filled = 0; 18 | 19 | std::vector log; 20 | public: 21 | Log(uint64_t); 22 | ~Log(); 23 | 24 | void append_command(Command); 25 | void set_command(uint64_t, Command); 26 | Command get_command(uint64_t); 27 | uint64_t get_next_slot_index(); 28 | 29 | }; 30 | 31 | Log::Log(uint64_t logsize) : log(logsize) 32 | { 33 | log[0] = NOOP_CMD; // just to fill first slot 34 | } 35 | 36 | Log::~Log() 37 | { 38 | } 39 | 40 | inline void Log::append_command(Command command) 41 | { 42 | log[last_slot_filled + 1] = command; 43 | last_slot_filled++; // slot must incremented AFTER command is set 44 | } 45 | 46 | inline void Log::set_command(uint64_t slot, Command command) 47 | { 48 | log[slot] = command; 49 | } 50 | 51 | inline Command Log::get_command(uint64_t slot) 52 | { 53 | return log[slot]; 54 | } 55 | 56 | inline uint64_t Log::get_next_slot_index() 57 | { 58 | return last_slot_filled + 1; 59 | } 60 | -------------------------------------------------------------------------------- /src/utils/StringHelper.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file StringHelper.h 3 | * @author cbinnig, tziegler 4 | * @date 2018-08-17 5 | */ 6 | 7 | #ifndef DFI_SRC_UTILS_STRINGHELPER_H_ 8 | #define DFI_SRC_UTILS_STRINGHELPER_H_ 9 | 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | namespace dfi { 16 | 17 | class StringHelper { 18 | public: 19 | static vector split(string value, string sep = ",") { 20 | vector values; 21 | char* cvalue = new char[value.length() + 1]; 22 | strcpy(cvalue, value.c_str()); 23 | char* token = strtok(cvalue, sep.c_str()); 24 | 25 | while (token) { 26 | values.push_back(token); 27 | token = strtok(nullptr, sep.c_str()); 28 | } 29 | 30 | delete[] cvalue; 31 | return values; 32 | } 33 | 34 | 35 | static void splitPerf(const string& value, std::vector& retValues ,string sep = ",") { 36 | char* cvalue = new char[value.length() + 1]; 37 | strcpy(cvalue, value.c_str()); 38 | char* token = strtok(cvalue, sep.c_str()); 39 | 40 | while (token) { 41 | retValues.emplace_back(token); 42 | token = strtok(nullptr, sep.c_str()); 43 | } 44 | delete[] cvalue; 45 | } 46 | 47 | }; 48 | } 49 | 50 | #endif /* DFI_SRC_UTILS_STRINGHELPER_H_ */ 51 | -------------------------------------------------------------------------------- /cmake/modules/FindNuma.cmake: -------------------------------------------------------------------------------- 1 | # SOURCE https://github.com/videolan/x265/blob/master/source/cmake/FindNuma.cmake 2 | # Module for locating libnuma 3 | # 4 | # Read-only variables: 5 | # NUMA_FOUND 6 | # Indicates that the library has been found. 7 | # 8 | # NUMA_INCLUDE_DIR 9 | # Points to the libnuma include directory. 10 | # 11 | # NUMA_LIBRARY_DIR 12 | # Points to the directory that contains the libraries. 13 | # The content of this variable can be passed to link_directories. 14 | # 15 | # NUMA_LIBRARY 16 | # Points to the libnuma that can be passed to target_link_libararies. 17 | # 18 | # Copyright (c) 2015 Steve Borho 19 | 20 | include(FindPackageHandleStandardArgs) 21 | 22 | find_path(NUMA_ROOT_DIR 23 | NAMES include/numa.h 24 | PATHS ENV NUMA_ROOT 25 | DOC "NUMA root directory") 26 | 27 | find_path(NUMA_INCLUDE_DIR 28 | NAMES numa.h 29 | HINTS ${NUMA_ROOT_DIR} 30 | PATH_SUFFIXES include 31 | DOC "NUMA include directory") 32 | 33 | find_library(NUMA_LIBRARY 34 | NAMES numa 35 | HINTS ${NUMA_ROOT_DIR} 36 | DOC "NUMA library") 37 | 38 | if (NUMA_LIBRARY) 39 | get_filename_component(NUMA_LIBRARY_DIR ${NUMA_LIBRARY} PATH) 40 | endif() 41 | 42 | mark_as_advanced(NUMA_INCLUDE_DIR NUMA_LIBRARY_DIR NUMA_LIBRARY) 43 | 44 | find_package_handle_standard_args(NUMA REQUIRED_VARS NUMA_ROOT_DIR NUMA_INCLUDE_DIR NUMA_LIBRARY) 45 | -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/NetworkReplicatorThread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Settings.h" 4 | #include "Relation.h" 5 | #include "../../flow-api/dfi.h" 6 | #include "utils/Thread.h" 7 | 8 | 9 | 10 | class NetworkReplicatorThread : public utils::Thread 11 | { 12 | public: 13 | NetworkReplicatorThread(Relation &relation, std::string flow_name, SourceID source_id, size_t from, size_t to); 14 | void run() override; 15 | 16 | private: 17 | Relation &relation; 18 | DFI_Replicate_flow_source flow_source; 19 | size_t from; 20 | size_t to; 21 | public: 22 | size_t processed_tuples = 0; 23 | }; 24 | 25 | NetworkReplicatorThread::NetworkReplicatorThread(Relation &relation, std::string flow_name, SourceID source_id, size_t from, size_t to) : relation(relation), 26 | flow_source(flow_name, source_id), from(from), to(to) 27 | { 28 | } 29 | 30 | 31 | void NetworkReplicatorThread::run() 32 | { 33 | for (size_t i = from; i <= to; ++i) { 34 | #ifdef USE_COMPRESSION 35 | CompressedTuple_t tuple(relation.get_tuple(i)->key, relation.get_tuple(i)->value); 36 | flow_source.push(&tuple); 37 | #else 38 | flow_source.push(relation.get_tuple(i)); 39 | #endif 40 | // std::cout << "pushing tuple key=" + std::to_string(relation.get_tuple(i)->key) + '\n'; 41 | ++processed_tuples; 42 | } 43 | flow_source.close(); 44 | } -------------------------------------------------------------------------------- /src/dfi/type/Value.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Value.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2019-01-14 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../../utils/Config.h" 10 | #include "../../utils/Logging.h" 11 | #include "TypeId.h" 12 | 13 | namespace dfi 14 | { 15 | class Value 16 | { 17 | friend class Tuple; 18 | public: 19 | 20 | // Value(const TypeId type) : m_typeId(type) {}; 21 | Value() = default; 22 | Value(TypeId typeId, void* i); 23 | 24 | Value operator+ (const Value &rhs) const; 25 | Value operator- (const Value &rhs) const; 26 | Value operator* (const Value &rhs) const; 27 | Value operator/ (const Value &rhs) const; 28 | static Value min(const Value &lhs, const Value &rhs); 29 | static Value max(const Value &lhs, const Value &rhs); 30 | 31 | Value operator+ (const int rhs) const; 32 | Value operator- (const int rhs) const; 33 | Value operator* (const int rhs) const; 34 | Value operator/ (const int rhs) const; 35 | 36 | // Creates a dfi::Value with default value for given TypeId 37 | static Value getDefaultValue(TypeId typeId); 38 | 39 | protected: 40 | // Value item 41 | union { 42 | int8_t boolean; 43 | int8_t tinyint; 44 | int16_t smallint; 45 | int32_t integer; 46 | int64_t bigint; 47 | uint64_t ubigint; 48 | float smalldecimal; 49 | double decimal; 50 | } m_value; 51 | 52 | // Data type 53 | TypeId m_typeId; 54 | }; 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/utils/Network.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Network.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2018-08-17 5 | */ 6 | 7 | 8 | 9 | #ifndef DFI_NETWORK_H_ 10 | #define DFI_NETWORK_H_ 11 | 12 | #include "./Config.h" 13 | #include 14 | 15 | namespace dfi { 16 | 17 | class Network { 18 | public: 19 | 20 | static inline uint64_t bigEndianToHost(uint64_t be) { 21 | return be64toh(be); 22 | } 23 | ; 24 | 25 | static bool isConnection(const string& region) { 26 | size_t found = region.find(":"); 27 | if (found != std::string::npos) { 28 | return true; 29 | } 30 | return false; 31 | } 32 | 33 | static string getConnection(const string& address, const int& port) { 34 | stringstream ss; 35 | ss << address; 36 | ss << ":"; 37 | ss << port; 38 | return ss.str(); 39 | } 40 | 41 | static string getAddressOfConnection(const string& conn) { 42 | size_t found = conn.find(":"); 43 | if (found != std::string::npos) { 44 | return conn.substr(0, found); 45 | } 46 | throw invalid_argument("Connection has bad format"); 47 | } 48 | 49 | static size_t getPortOfConnection(const string& conn) { 50 | size_t found = conn.find(":"); 51 | if (found != std::string::npos) { 52 | found++; 53 | size_t length = conn.length() - found; 54 | string portStr = conn.substr(found, length); 55 | return stoi(portStr); 56 | } 57 | throw invalid_argument("Connection has bad format"); 58 | } 59 | }; 60 | 61 | } 62 | 63 | #endif /* DFI_NETWORK_H_ */ 64 | -------------------------------------------------------------------------------- /src/dfi/flow/FlowSourceFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "FlowHandle.h" 5 | #include "FlowSourceInterface.h" 6 | #include "FlowSourceBW.h" 7 | #include "FlowSourceBWReplicate.h" 8 | #include "FlowSourceLat.h" 9 | #include "FlowSourceMulticast.h" 10 | #include "FlowSourceMulticastBW.h" 11 | 12 | namespace dfi 13 | { 14 | 15 | class FlowSourceFactory { 16 | public: 17 | static std::unique_ptr create(FlowHandle &flowHandle, size_t sourceSegmentCount, SourceID sourceId = 0, bool nonTempSupport = false) 18 | { 19 | switch (flowHandle.optimization) 20 | { 21 | case FlowOptimization::BW: 22 | { 23 | if (flowHandle.flowtype == FlowType::REPLICATE) 24 | { 25 | return std::make_unique(flowHandle, sourceSegmentCount); 26 | } 27 | return std::make_unique(flowHandle, sourceSegmentCount, nonTempSupport); 28 | } 29 | case FlowOptimization::LAT: 30 | return std::make_unique(flowHandle); 31 | case FlowOptimization::MULTICAST_ORDERING: 32 | return std::make_unique>(flowHandle, sourceId); 33 | case FlowOptimization::MULTICAST: 34 | return std::make_unique>(flowHandle, sourceId); 35 | case FlowOptimization::MULTICAST_BW: 36 | return std::make_unique(flowHandle, sourceId); 37 | } 38 | 39 | throw std::invalid_argument{"Invalid flowHandle.optimization"}; 40 | } 41 | }; 42 | 43 | } //dfi namespace end 44 | -------------------------------------------------------------------------------- /cmake/modules/FindZMQ.cmake: -------------------------------------------------------------------------------- 1 | # SOURCE)s://github.com/watchedit/CMakeModules/blob/master/FindZMQ.cmakei 2 | # - Try to find ZMQ 3 | # Once done this will define 4 | # 5 | # ZMQ_FOUND - system has ZMQ 6 | # ZMQ_INCLUDE_DIRS - the ZMQ include directory 7 | # ZMQ_LIBRARIES - Link these to use ZMQ 8 | # ZMQ_DEFINITIONS - Compiler switches required for using ZMQ 9 | # 10 | # Copyright (c) 2011 Lee Hambley 11 | # 12 | # Redistribution and use is allowed according to the terms of the New 13 | # BSD license. 14 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 15 | # 16 | 17 | if (ZMQ_LIBRARIES AND ZMQ_INCLUDE_DIRS) 18 | # in cache already 19 | set(ZMQ_FOUND TRUE) 20 | else (ZMQ_LIBRARIES AND ZMQ_INCLUDE_DIRS) 21 | 22 | find_path(ZMQ_INCLUDE_DIR 23 | NAMES 24 | zmq.h 25 | PATHS 26 | /usr/include 27 | /usr/local/include 28 | /opt/local/include 29 | /sw/include 30 | ) 31 | 32 | find_library(ZMQ_LIBRARY 33 | NAMES 34 | zmq 35 | PATHS 36 | /usr/lib 37 | /usr/local/lib 38 | /opt/local/lib 39 | /sw/lib 40 | ) 41 | 42 | set(ZMQ_INCLUDE_DIRS 43 | ${ZMQ_INCLUDE_DIR} 44 | ) 45 | 46 | if (ZMQ_LIBRARY) 47 | set(ZMQ_LIBRARIES 48 | ${ZMQ_LIBRARIES} 49 | ${ZMQ_LIBRARY} 50 | ) 51 | endif (ZMQ_LIBRARY) 52 | 53 | include(FindPackageHandleStandardArgs) 54 | find_package_handle_standard_args(ZMQ DEFAULT_MSG ZMQ_LIBRARIES ZMQ_INCLUDE_DIRS) 55 | 56 | # show the ZMQ_INCLUDE_DIRS and ZMQ_LIBRARIES variables only in the advanced view 57 | mark_as_advanced(ZMQ_INCLUDE_DIRS ZMQ_LIBRARIES) 58 | 59 | endif (ZMQ_LIBRARIES AND ZMQ_INCLUDE_DIRS) -------------------------------------------------------------------------------- /src/dfi/flow/FlowHandle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../utils/Config.h" 4 | #include "../type/Schema.h" 5 | #include "../../dfi/type/EnumTypes.h" 6 | #include "../memory/BufferHandle.h" 7 | #include "../memory/FlowOptimization.h" 8 | 9 | namespace dfi 10 | { 11 | 12 | struct FlowHandle 13 | { 14 | string name; //Used to identify the flow 15 | std::vector sources; //Logical FlowSourceID mapping to (potential) NodeID. Note: not all flows requires an addressable NodeServer and therefore NodeID can be 0. 16 | std::vector targets; //Logical FlowTargetID mapping to NodeID 17 | Schema schema; 18 | int groupKeyIndex; 19 | FlowType flowtype; 20 | uint32_t segmentsPerRing = Config::DFI_SEGMENTS_PER_RING; 21 | uint64_t segmentSizes = Config::DFI_FULL_SEGMENT_SIZE - sizeof(DFI_SEGMENT_FOOTER_t); 22 | FlowOptimization optimization = FlowOptimization::BW; 23 | AggrFunc aggrFunc = AggrFunc::NONE; 24 | std::string multicastAddress; 25 | uint64_t globalSeqNoOffset; 26 | std::vector targetSpecificOptions; 27 | 28 | FlowHandle() {} 29 | FlowHandle(string name) : name(name) {} 30 | FlowHandle(string name, std::vector targets, Schema schema, size_t numberOfSources, uint32_t groupKeyIndex, FlowType flowtype, FlowOptimization opti): 31 | FlowHandle{name, std::vector(numberOfSources), targets, schema, groupKeyIndex, flowtype, opti} { 32 | } 33 | 34 | FlowHandle(string name, std::vector sources, std::vector targets, Schema schema, uint32_t groupKeyIndex, FlowType flowtype, FlowOptimization opti) 35 | : name(name), sources(sources), targets(targets), schema(schema), groupKeyIndex(groupKeyIndex), flowtype(flowtype), optimization(opti) { 36 | } 37 | }; 38 | 39 | }//dfi namespace end 40 | -------------------------------------------------------------------------------- /src/utils/Timer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Timer.h 3 | * @author cbinnig, tziegler 4 | * @date 2018-08-17 5 | */ 6 | 7 | 8 | 9 | #ifndef DFI_SRC_UTILS_TIMER_H_ 10 | #define DFI_SRC_UTILS_TIMER_H_ 11 | 12 | #include "../utils/Config.h" 13 | 14 | #include 15 | #include 16 | namespace dfi { 17 | 18 | class Timer { 19 | 20 | public: 21 | inline static uint128_t timestamp() { 22 | struct timespec ts; 23 | 24 | clock_gettime(CLOCK_MONOTONIC, &ts); 25 | 26 | return ts.tv_sec * 1e9 + ts.tv_nsec; 27 | } 28 | 29 | inline static uint128_t diff(uint128_t last) { 30 | uint128_t now = timestamp(); 31 | return now - last; 32 | } 33 | 34 | void addTime(string step, uint128_t time) { 35 | if (m_stats.find(step) != m_stats.end()) { 36 | m_stats[step] += time; 37 | } else { 38 | m_stats[step] = time; 39 | } 40 | } 41 | 42 | void addTimer(Timer* timer) { 43 | if (timer == nullptr) 44 | return; 45 | 46 | for (unordered_map::iterator it = 47 | timer->m_stats.begin(); it != timer->m_stats.end(); ++it) { 48 | if (m_stats.find(it->first) != m_stats.end()) { 49 | m_stats[it->first] += it->second; 50 | } else { 51 | m_stats[it->first] = it->second; 52 | } 53 | } 54 | } 55 | 56 | unordered_map getStats() { 57 | return m_stats; 58 | } 59 | 60 | inline static void busySleep(size_t sleep_us) { 61 | auto start = std::chrono::system_clock::now(); 62 | auto now = start; 63 | while(std::chrono::duration_cast(now - start).count() < (int64_t)sleep_us) 64 | { 65 | now = std::chrono::system_clock::now(); 66 | } 67 | } 68 | 69 | private: 70 | unordered_map m_stats; 71 | }; 72 | 73 | } 74 | 75 | #endif /* DFI_SRC_UTILS_TIMER_H_ */ 76 | -------------------------------------------------------------------------------- /src/utils/Logging.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Logging.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2018-08-17 5 | */ 6 | 7 | 8 | 9 | #ifndef DFI_LOGGING_HPP_ 10 | #define DFI_LOGGING_HPP_ 11 | 12 | #include "./Config.h" 13 | 14 | #include 15 | #include 16 | 17 | namespace dfi { 18 | 19 | class Logging { 20 | public: 21 | static void debug(string filename, int line, string msg) { 22 | //avoid unused variable warning 23 | (void) filename; 24 | (void) line; 25 | (void) msg; 26 | #ifdef DEBUG 27 | if(Config::LOGGING_LEVEL<=1) 28 | log("[DEBUG]: ", filename, line, msg); 29 | #endif 30 | } 31 | 32 | static void error(string filename, int line, string msg) { 33 | if (Config::LOGGING_LEVEL <= 4) 34 | log("[ERROR]: ", filename, line, msg); 35 | } 36 | 37 | static void errorNo(string filename, int line, char* errorMsg, int errNo) { 38 | if (Config::LOGGING_LEVEL <= 4) 39 | cerr << "[ERROR NO]" << filename << " at " << line << " (" << errorMsg 40 | << ": " << errNo << ")" << endl; 41 | } 42 | 43 | static void fatal(string filename, int line, string msg) { 44 | if (Config::LOGGING_LEVEL <= 5) 45 | log("[FATAL]: ", filename, line, msg); 46 | exit(1); 47 | } 48 | 49 | static void info(string msg) { 50 | if (Config::LOGGING_LEVEL <= 2) 51 | log("[INFO]: ", msg); 52 | } 53 | 54 | static void warn(string msg) { 55 | if (Config::LOGGING_LEVEL <= 3) 56 | log("[WARN]: ", msg); 57 | } 58 | private: 59 | static void log(string type, string filename, int line, string msg) { 60 | cerr << type << filename << " at " << line << " (" << msg << ")" << endl; 61 | } 62 | 63 | static void log(string type, string msg) { 64 | cerr << type << msg << endl; 65 | } 66 | }; 67 | 68 | } // end namespace dfi 69 | 70 | #endif /* DFI_LOGGING_HPP_ */ 71 | -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/BuildProber.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Relation.h" 4 | #include "Settings.h" 5 | #include "Partition.h" 6 | #include "BuildProberThread.h" 7 | 8 | class BuildProber 9 | { 10 | public: 11 | BuildProber(PartitionHolder **left_partitions, PartitionHolder **right_partitions); 12 | ~BuildProber(); 13 | void run(); 14 | void join(); 15 | private: 16 | std::vector builder_threads; 17 | size_t processed_tuples_cnt = 0; 18 | PartitionHolder **left_partitions; 19 | PartitionHolder **right_partitions; 20 | public: 21 | size_t joined_tuples_cnt = 0; 22 | size_t non_matched_tuples = 0; 23 | }; 24 | 25 | 26 | BuildProber::BuildProber(PartitionHolder **left_partitions, PartitionHolder **right_partitions) : left_partitions(left_partitions), right_partitions(right_partitions) 27 | { 28 | 29 | std::cout << "Creating " << Settings::LOCAL_PARTITION_COUNT << " BuildProberThreads" << '\n'; 30 | builder_threads.reserve(Settings::LOCAL_PARTITION_COUNT); 31 | for(size_t i = 0; i < Settings::LOCAL_PARTITION_COUNT; i++) { 32 | BuildProberThread *thread = new BuildProberThread(i, left_partitions, right_partitions); 33 | builder_threads.push_back(thread); 34 | } 35 | } 36 | 37 | BuildProber::~BuildProber() 38 | { 39 | for(auto &thread : builder_threads) { 40 | delete thread; 41 | } 42 | } 43 | 44 | void BuildProber::run() 45 | { 46 | for(auto &thread : builder_threads) { 47 | thread->start(); 48 | } 49 | } 50 | 51 | void BuildProber::join() 52 | { 53 | for(auto &thread : builder_threads) { 54 | thread->join(); 55 | joined_tuples_cnt += thread->joined_tuples_cnt; 56 | non_matched_tuples += thread->non_matched_tuples; 57 | } 58 | 59 | std::cout << "sum_join_count=" << joined_tuples_cnt << std::endl; 60 | } -------------------------------------------------------------------------------- /src/dfi/flow/FlowSourceMulticast.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "FlowSourceInterface.h" 4 | #include "../memory/BufferWriterMulticast.h" 5 | 6 | namespace dfi 7 | { 8 | 9 | template 10 | class FlowSourceMulticast final : public FlowSourceInterface { 11 | SourceID m_sourceId; 12 | std::unique_ptr> m_bufferWriter; 13 | size_t m_tupleSize = 0; 14 | public: 15 | FlowSourceMulticast(FlowHandle flowHandle, SourceID sourceId) : 16 | FlowSourceInterface(flowHandle), m_sourceId{sourceId} { 17 | 18 | if (m_flowHandle.optimization != FlowOptimization::MULTICAST && m_flowHandle.optimization != FlowOptimization::MULTICAST_ORDERING) { 19 | throw new invalid_argument("FlowSourceBW ctor: FlowOptimization not Multicast (FlowOptimization::MULTICAST)"); 20 | } 21 | 22 | m_bufferWriter = std::make_unique>(m_flowHandle, sourceId); 23 | 24 | m_tupleSize = flowHandle.schema.getTupleSize(); 25 | 26 | Logging::debug(__FILE__, __LINE__, "BufferWriterMulticast created for flow: " + flowHandle.name); 27 | } 28 | 29 | ~FlowSourceMulticast() { 30 | close(); 31 | } 32 | 33 | inline bool pushToAll(Tuple const &tuple, bool forceSignaled = false) override 34 | { 35 | m_bufferWriter->add(tuple.getDataPtr(), m_tupleSize, forceSignaled); 36 | return m_bufferWriter->flush(forceSignaled, false); 37 | } 38 | 39 | inline bool flush(TargetID) override 40 | { 41 | //Nothing to do? -> Yes 42 | return true; 43 | } 44 | 45 | void close() override 46 | { 47 | if (!m_isClosed) { 48 | m_bufferWriter->close(); 49 | } 50 | m_isClosed = true; 51 | } 52 | private: 53 | // don't call this 54 | bool push(Tuple const &, TargetID, bool) { 55 | return false; 56 | }; 57 | }; 58 | 59 | 60 | 61 | } -------------------------------------------------------------------------------- /cmake/modules/FindPackageMessage.cmake: -------------------------------------------------------------------------------- 1 | # https://github.com/Kitware/CMake 2 | 3 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 4 | # file Copyright.txt or https://cmake.org/licensing for details. 5 | 6 | #[=======================================================================[.rst: 7 | FindPackageMessage 8 | ------------------ 9 | 10 | .. code-block:: cmake 11 | 12 | find_package_message( "message for user" "find result details") 13 | 14 | This function is intended to be used in FindXXX.cmake modules files. 15 | It will print a message once for each unique find result. This is 16 | useful for telling the user where a package was found. The first 17 | argument specifies the name (XXX) of the package. The second argument 18 | specifies the message to display. The third argument lists details 19 | about the find result so that if they change the message will be 20 | displayed again. The macro also obeys the QUIET argument to the 21 | find_package command. 22 | 23 | Example: 24 | 25 | .. code-block:: cmake 26 | 27 | if(X11_FOUND) 28 | find_package_message(X11 "Found X11: ${X11_X11_LIB}" 29 | "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]") 30 | else() 31 | ... 32 | endif() 33 | #]=======================================================================] 34 | 35 | function(find_package_message pkg msg details) 36 | # Avoid printing a message repeatedly for the same find result. 37 | if(NOT ${pkg}_FIND_QUIETLY) 38 | string(REPLACE "\n" "" details "${details}") 39 | set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg}) 40 | if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}") 41 | # The message has not yet been printed. 42 | message(STATUS "${msg}") 43 | 44 | # Save the find details in the cache to avoid printing the same 45 | # message again. 46 | set("${DETAILS_VAR}" "${details}" 47 | CACHE INTERNAL "Details about finding ${pkg}") 48 | endif() 49 | endif() 50 | endfunction() -------------------------------------------------------------------------------- /src/use-cases/distributed-radix-join-flow/NetworkPartitioner.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Relation.h" 4 | #include "Settings.h" 5 | #include "NetworkPartitionerThread.h" 6 | 7 | class NetworkPartitioner 8 | { 9 | public: 10 | NetworkPartitioner(Relation &relation); 11 | ~NetworkPartitioner(); 12 | void partition(); 13 | void join(); 14 | private: 15 | Relation &relation; 16 | NetworkPartitionerThread **partitioner_threads; 17 | }; 18 | 19 | 20 | NetworkPartitioner::NetworkPartitioner(Relation &relation) : relation(relation) 21 | { 22 | partitioner_threads = new NetworkPartitionerThread*[Settings::THREADS_COUNT]; 23 | for(size_t i = 0; i < Settings::THREADS_COUNT; i++) 24 | { 25 | size_t from = i * (relation.get_size() / Settings::THREADS_COUNT); 26 | size_t to = (i + 1) * (relation.get_size() / Settings::THREADS_COUNT) - 1; 27 | if (i == Settings::THREADS_COUNT-1) 28 | { 29 | to = relation.get_size() - 1; 30 | } 31 | std::cout << "Creating NetworkPartitionerThread, range: " << from << " -> " << to << '\n'; 32 | partitioner_threads[i] = new NetworkPartitionerThread(relation, from, to); 33 | } 34 | } 35 | 36 | NetworkPartitioner::~NetworkPartitioner() 37 | { 38 | for(size_t i = 0; i < Settings::THREADS_COUNT; i++) 39 | { 40 | delete partitioner_threads[i]; 41 | } 42 | delete[] partitioner_threads; 43 | } 44 | 45 | void NetworkPartitioner::partition() 46 | { 47 | for(size_t i = 0; i < Settings::THREADS_COUNT; i++) 48 | { 49 | partitioner_threads[i]->start(); 50 | } 51 | } 52 | 53 | void NetworkPartitioner::join() 54 | { 55 | size_t processed_tuples = 0; 56 | for(size_t i = 0; i < Settings::THREADS_COUNT; i++) 57 | { 58 | partitioner_threads[i]->join(); 59 | processed_tuples += partitioner_threads[i]->get_processed_tuples(); 60 | } 61 | std::cout << "Partitioner processed " << processed_tuples << " tuples." << '\n'; 62 | } -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/NetworkReplicator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Relation.h" 4 | #include "Settings.h" 5 | #include "NetworkReplicatorThread.h" 6 | 7 | class NetworkReplicator 8 | { 9 | public: 10 | NetworkReplicator(Relation &relation); 11 | ~NetworkReplicator(); 12 | void start_threads(); 13 | void join_threads(); 14 | private: 15 | Relation &relation; 16 | NetworkReplicatorThread **replicator_threads; 17 | }; 18 | 19 | 20 | NetworkReplicator::NetworkReplicator(Relation &relation) : relation(relation) 21 | { 22 | replicator_threads = new NetworkReplicatorThread*[Settings::PART_THREADS_COUNT]; 23 | for(size_t i = 0; i < Settings::PART_THREADS_COUNT; i++) 24 | { 25 | size_t from = i * (relation.get_size() / Settings::PART_THREADS_COUNT); 26 | size_t to = (i + 1) * (relation.get_size() / Settings::PART_THREADS_COUNT) - 1; 27 | if (i == Settings::PART_THREADS_COUNT-1) { 28 | to = relation.get_size() - 1; 29 | } 30 | std::string flow_name = Settings::LEFT_REL_FLOW_NAME+to_string(i); 31 | // std::cout << "Creating NetworkReplicatorThread, range: " << from << " -> " << to << " flow: " << flow_name << '\n'; 32 | replicator_threads[i] = new NetworkReplicatorThread(relation, flow_name, Settings::NODE_ID+1, from, to); // because cli arg starts with 0 33 | } 34 | } 35 | 36 | NetworkReplicator::~NetworkReplicator() 37 | { 38 | for(size_t i = 0; i < Settings::PART_THREADS_COUNT; i++) { 39 | delete replicator_threads[i]; 40 | } 41 | delete[] replicator_threads; 42 | } 43 | 44 | void NetworkReplicator::start_threads() 45 | { 46 | for(size_t i = 0; i < Settings::PART_THREADS_COUNT; i++) { 47 | replicator_threads[i]->start(); 48 | } 49 | } 50 | 51 | void NetworkReplicator::join_threads() 52 | { 53 | size_t processed_tuples = 0; 54 | for(size_t i = 0; i < Settings::PART_THREADS_COUNT; i++) { 55 | replicator_threads[i]->join(); 56 | processed_tuples += replicator_threads[i]->processed_tuples; 57 | } 58 | std::cout << "Replicator processed " << processed_tuples << " tuples." << '\n'; 59 | } -------------------------------------------------------------------------------- /src/use-cases/distributed-radix-join-flow/Main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../../utils/Config.h" 5 | #include "Settings.h" 6 | #include "DistributedRadixJoin.h" 7 | #include "utils/ThreadScheduler.h" 8 | 9 | void usage(char* argv[]) { 10 | cout << "Usage: " << argv[0] << " nodeid total_nodes thread_count full_left_relation_size full_right_relation_size random_order(t/f) numa_node(0/1)" << endl; 11 | } 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | if (argc <= 6) { 16 | usage(argv); 17 | return -1; 18 | } 19 | 20 | rdma::Config rdmaConf(argv[0]); 21 | dfi::Config conf(argv[0]); 22 | 23 | Settings::NODE_ID = atoi(argv[1]); 24 | Settings::NODES_TOTAL = atoi(argv[2]); 25 | Settings::THREADS_COUNT = atoi(argv[3]); 26 | Settings::LEFT_REL_FULL_SIZE = strtoul(argv[4], NULL, 0); 27 | Settings::RIGHT_REL_FULL_SIZE = strtoul(argv[5], NULL, 0); 28 | 29 | if (argc >= 7) { 30 | std::string random_order(argv[6]); 31 | Settings::RANDOM_ORDER = (random_order == "t"); 32 | if (Settings::RANDOM_ORDER) std::cout << "Random tuple order!" << '\n'; 33 | } 34 | if (argc >= 8) { 35 | rdma::Config::RDMA_NUMAREGION = atoi(argv[7]); 36 | rdma::Config::RDMA_INTERFACE = "ib"+to_string(rdma::Config::RDMA_NUMAREGION); 37 | } 38 | 39 | if (dfi::Config::DFI_NODES.size() != Settings::NODES_TOTAL) 40 | { 41 | std::cout << "Config was initialized with " << dfi::Config::DFI_NODES.size() << " nodes. Does not match passed number of nodes: " << Settings::NODES_TOTAL << std::endl; 42 | exit(1); 43 | } 44 | 45 | cpu_set_t cpuset; 46 | CPU_ZERO(&cpuset); 47 | CPU_SET(rdma::Config::NUMA_THREAD_CPUS[rdma::Config::RDMA_NUMAREGION][0], &cpuset); 48 | sched_setaffinity(0, sizeof(cpuset), &cpuset); 49 | 50 | DistributedRadixJoin join; 51 | 52 | utils::ThreadScheduler::start(Settings::THREADS_COUNT); 53 | 54 | std::cout << "Generating test data... full left: " << Settings::LEFT_REL_FULL_SIZE << " full right: " << Settings::RIGHT_REL_FULL_SIZE << '\n'; 55 | join.generate_test_data(); 56 | 57 | join.initialize_dfi(); 58 | 59 | join.run(); 60 | 61 | utils::ThreadScheduler::stop(); 62 | } 63 | -------------------------------------------------------------------------------- /src/gtest/examples/shuffle_flow_examples.cc: -------------------------------------------------------------------------------- 1 | #include "shuffle_flow_examples.h" 2 | 3 | void ShuffleFlowExamples::SetUp() 4 | { 5 | //Setup Test DFI 6 | rdma::Config::RDMA_MEMSIZE = 1024ul * 1024 * 1; 7 | Config::DFI_SOURCE_SEGMENT_COUNT = 8; 8 | Config::DFI_REGISTRY_SERVER = rdma::Config::getIP(rdma::Config::RDMA_INTERFACE); 9 | Config::DFI_REGISTRY_PORT = 5300; 10 | Config::DFI_FULL_SEGMENT_SIZE = (512 + sizeof(DFI_SEGMENT_FOOTER_t)); 11 | Config::DFI_SEGMENTS_PER_RING = 5; 12 | rdma::Config::SEQUENCER_IP = rdma::Config::getIP(rdma::Config::RDMA_INTERFACE); 13 | Config::LOGGING_LEVEL = 1; 14 | rdma::Config::LOGGING_LEVEL = 1; 15 | uint16_t server1Port = 5400; 16 | uint16_t server2Port = 5401; 17 | dfi::Config::DFI_NODES = {rdma::Config::getIP(rdma::Config::RDMA_INTERFACE) + ":" + to_string(server1Port), 18 | rdma::Config::getIP(rdma::Config::RDMA_INTERFACE) + ":" + to_string(server2Port)}; 19 | 20 | } 21 | 22 | void ShuffleFlowExamples::TearDown() 23 | { 24 | 25 | } 26 | 27 | TEST_F(ShuffleFlowExamples, simpleShuffle) 28 | { 29 | //Registry and node setup 30 | RegistryServer registry; 31 | DFI_Node node1(5400); 32 | DFI_Node node2(5401); 33 | 34 | //Flow initialization 35 | std::string flow_name = "Shuffle-example"; 36 | size_t source_count = 1; 37 | std::vector targets{{1,1}, {2,2}}; // target id 1 --> node1 && target id 2 --> node 2 38 | DFI_Schema schema({{"key", TypeId::INT},{"value", TypeId::INT}}); 39 | DFI_Shuffle_flow_init(flow_name, source_count, targets, schema, 0); 40 | 41 | //Flow execution 42 | DFI_Shuffle_flow_source source(flow_name); 43 | DFI_Shuffle_flow_target target1(flow_name, 1); 44 | DFI_Shuffle_flow_target target2(flow_name, 2); 45 | 46 | std::pair data; 47 | data = {3,10}; 48 | source.push(&data); 49 | data = {8,20}; 50 | source.push(&data); 51 | source.close(); 52 | 53 | dfi::Tuple tuple1; 54 | target1.consume(tuple1); 55 | 56 | dfi::Tuple tuple2; 57 | target2.consume(tuple2); 58 | 59 | std::cout << "Target 1 got tuple (" << tuple1.getAs("key") << "," << tuple1.getAs("value") << ")" << std::endl; 60 | std::cout << "Target 2 got tuple (" << tuple2.getAs("key") << "," << tuple2.getAs("value") << ")" << std::endl; 61 | } 62 | -------------------------------------------------------------------------------- /src/gtest/memory/TestConfig.cc: -------------------------------------------------------------------------------- 1 | #include "TestConfig.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void TestConfig::SetUp() 8 | { 9 | //Create new test config file 10 | if (mkdir(program_name.c_str(), 0777) == -1) 11 | { 12 | std::cerr << "Could not create test directory!" << '\n'; 13 | std::cerr << "Error: " << strerror(errno) << std::endl; 14 | } 15 | string subdir = program_name + "/conf"; 16 | if (mkdir(subdir.c_str(), 0777) == -1) 17 | { 18 | std::cerr << "Could not create test directory!" << '\n'; 19 | std::cerr << "Error: " << strerror(errno) << std::endl; 20 | } 21 | 22 | std::ofstream confFile (program_name + "/conf/DFI.conf", std::ofstream::out); 23 | 24 | confFile << "LOGGING_LEVEL=1 \n\ 25 | RDMA_MEMSIZE = 1234567 \n\ 26 | DFI_REGISTRY_SERVER = 10.116.60.16 \n\ 27 | DFI_REGISTRY_PORT = 5300 \n\ 28 | THREAD_CPUS = 10,11,12,13, 14,15,16, 17,18,19 \n\ 29 | DFI_NODES = 10.116.60.16:1234,10.116.60.7:1234 \n\ 30 | CACHELINE_SIZE = 64 \n\ 31 | DFI_INTERNAL_BUFFER_SIZE = 654321 \n\ 32 | DFI_FULL_SEGMENT_SIZE = 234567 \n\ 33 | DFI_SEGMENTS_PER_RING = 99 \n\ 34 | " << std::endl; 35 | 36 | confFile.close(); 37 | } 38 | 39 | void TestConfig::TearDown() 40 | { 41 | // REMOVE FILE AND FOLDERS 42 | string filename = program_name + "/conf/DFI.conf"; 43 | std::remove(filename.c_str()); 44 | string subfolder = program_name + "/conf"; 45 | rmdir(subfolder.c_str()); 46 | rmdir(program_name.c_str()); 47 | 48 | //Reload the normal test config 49 | static Config conf(""); 50 | } 51 | 52 | 53 | TEST_F(TestConfig, loadConfigFile) 54 | { 55 | static Config conf(program_name+"/"); 56 | 57 | ASSERT_TRUE( Config::LOGGING_LEVEL == 1) << "LOGGING_LEVEL"; 58 | ASSERT_TRUE( Config::DFI_REGISTRY_SERVER == "10.116.60.16") << "DFI_REGISTRY_SERVER"; 59 | ASSERT_TRUE( Config::DFI_NODES[0] == "10.116.60.16:1234") << "DFI_NODES"; 60 | ASSERT_TRUE( Config::DFI_NODES[1] == "10.116.60.7:1234") << "DFI_NODES"; 61 | ASSERT_TRUE( Config::CACHELINE_SIZE == 64) << "CACHELINE_SIZE"; 62 | ASSERT_TRUE( Config::DFI_SOURCE_SEGMENT_COUNT == 654321) << "DFI_INTERNAL_BUFFER_SIZE"; 63 | ASSERT_TRUE( Config::DFI_FULL_SEGMENT_SIZE == 234567) << "DFI_FULL_SEGMENT_SIZE"; 64 | ASSERT_TRUE( Config::DFI_SEGMENTS_PER_RING == 99) << "DFI_SEGMENTS_PER_RING"; 65 | 66 | } 67 | 68 | -------------------------------------------------------------------------------- /src/dfi/registry/RegistryClient.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file RegistryClient.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2018-07-06 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../../utils/Config.h" 10 | 11 | #include "../../rdma-manager/src/proto/ProtoClient.h" 12 | #include "../message/MessageTypes.h" 13 | #include "../message/MessageErrors.h" 14 | #include "../../utils/Logging.h" 15 | 16 | 17 | #include "../memory/BufferHandle.h" 18 | #include "../flow/FlowHandle.h" 19 | 20 | namespace dfi 21 | { 22 | 23 | class RegistryClient: public rdma::ProtoClient 24 | { 25 | 26 | public: 27 | RegistryClient(); 28 | virtual ~RegistryClient(); 29 | 30 | // virtual BufferHandle *createBuffer(string &name, NodeID node_id, size_t size, size_t threshold); 31 | 32 | /** 33 | * @brief Registers the buffer at the RegistryServer --> creates a mapping from name to BufferHandle 34 | * 35 | * @param handle - BufferHandle containing meta buffer data 36 | * @return true - if Buffer was registered 37 | * @return false - if Buffer was not registered 38 | */ 39 | virtual bool registerBuffer(BufferHandle *handle); 40 | 41 | /** 42 | * @brief retrieves the BufferHandle identified by name. 43 | * 44 | * @param name of buffer 45 | * @return BufferHandle* - BufferHandle will contain a full list of all entry-segments into all rings 46 | */ 47 | virtual std::unique_ptr retrieveBuffer(string &buffername, string flowname = ""); 48 | 49 | virtual std::unique_ptr targetJoinBuffer(string &buffername, string &flowname, TargetID targetid); 50 | 51 | /** 52 | * @brief joins a BufferHandle for appending, identified by name. 53 | * 54 | * @param name of buffer 55 | * @return BufferHandle* - BufferHandle will contain a full list of all entry-segments into all rings 56 | */ 57 | virtual std::unique_ptr sourceJoinBuffer(std::string &buffername, string flowname = ""); 58 | 59 | bool createFlow(FlowHandle &handle, bool cacheAlignSegments = false); 60 | 61 | bool destroyFlow(FlowHandle &handle); 62 | 63 | std::unique_ptr retrieveFlowHandle(string name); 64 | 65 | bool getFlowBarrierOffset(std::string &name, size_t &offset); 66 | private: 67 | bool appendOrRetrieveSegment(Any* sendAny); 68 | std::unique_ptr retrieveOrJoinBuffer(Any* sendAny, std::string &name); 69 | std::string registry_ipPort; 70 | }; 71 | 72 | } // namespace dfi -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/LocalPartitionerThread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Settings.h" 3 | #include "Relation.h" 4 | #include "../../flow-api/dfi.h" 5 | #include "utils/Thread.h" 6 | #include 7 | #include 8 | 9 | 10 | class LocalPartitionerThread : public utils::Thread 11 | { 12 | 13 | public: 14 | LocalPartitionerThread(Relation &relation, size_t from, size_t to, PartitionHolder *local_partitions); 15 | void run(); 16 | size_t get_processed_tuples() { return processed_tuples; }; 17 | long long execution_time = 0; 18 | long long execution_part_time = 0; 19 | private: 20 | Relation &relation; 21 | size_t processed_tuples = 0; 22 | PartitionHolder *local_partitions; 23 | size_t from; 24 | size_t to; 25 | }; 26 | 27 | LocalPartitionerThread::LocalPartitionerThread(Relation &relation, size_t from, size_t to, PartitionHolder *local_partitions) : 28 | relation(relation), local_partitions(local_partitions), from(from), to(to) 29 | { 30 | } 31 | 32 | //NOTE: Partitioning code partly taken from Claude Barthels' MPI join from https://www.systems.ethz.ch/node/334 33 | void LocalPartitionerThread::run() { 34 | struct timeval tv_start; 35 | struct timeval tv_end; 36 | 37 | gettimeofday(&tv_start, NULL); 38 | 39 | constexpr auto MASK = Settings::LOCAL_PARTITION_COUNT - 1; 40 | cacheline_t cacheline_buffer[Settings::LOCAL_PARTITION_COUNT] __attribute__((aligned(Settings::CACHELINE_SIZE))); 41 | 42 | for (size_t i = from; i <= to; ++i) { 43 | #ifdef USE_COMPRESSION 44 | CompressedTuple_t tuple{relation.get_tuple(i)->key, relation.get_tuple(i)->value}; 45 | #else 46 | Tuple_t tuple = *relation.get_tuple(i); 47 | #endif 48 | 49 | uint32_t partition_id = tuple.key & MASK; 50 | 51 | cacheline_t *cacheline = cacheline_buffer + partition_id; 52 | bool is_full = cacheline->add_tuple(tuple); 53 | 54 | if (is_full) { 55 | local_partitions->partitions[partition_id]->add_cacheline(cacheline); 56 | cacheline->clear(); 57 | } 58 | 59 | ++processed_tuples; 60 | } 61 | 62 | for (uint32_t i = 0; i < Settings::LOCAL_PARTITION_COUNT; ++i) { 63 | cacheline_t *cacheline = cacheline_buffer + i; 64 | if (cacheline->size() > 0) { 65 | local_partitions->partitions[i]->add_cacheline(cacheline, cacheline->size()); 66 | } 67 | } 68 | 69 | 70 | gettimeofday(&tv_end, NULL); 71 | execution_part_time = get_time_diff(tv_start, tv_end); 72 | } -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/Main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../../utils/Config.h" 5 | #include "Settings.h" 6 | #include "DistributedReplicateJoin.h" 7 | #include "utils/ThreadScheduler.h" 8 | 9 | void usage(char* argv[]) { 10 | cout << "Usage: " << argv[0] << " nodeid total_nodes total_thread_count full_left_relation_size full_right_relation_size random_order(t/f) numa_node(0/1)" << endl; 11 | } 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | std::cout << "sizeof(CompressedTuple_t)="<< sizeof(CompressedTuple_t) << std::endl; 16 | if (argc <= 6) { 17 | usage(argv); 18 | return -1; 19 | } 20 | 21 | rdma::Config rdmaConf(argv[0]); 22 | dfi::Config conf(argv[0]); 23 | 24 | Settings::NODE_ID = atoi(argv[1]); 25 | Settings::NODES_TOTAL = atoi(argv[2]); 26 | Settings::TOTAL_THREADS_COUNT = atoi(argv[3]); 27 | Settings::LEFT_REL_FULL_SIZE = strtoul(argv[4], NULL, 0); 28 | Settings::RIGHT_REL_FULL_SIZE = strtoul(argv[5], NULL, 0); 29 | 30 | if (argc >= 7) { 31 | std::string random_order(argv[6]); 32 | Settings::RANDOM_ORDER = (random_order == "t"); 33 | if (Settings::RANDOM_ORDER) 34 | std::cout << "Random tuple order!" << '\n'; 35 | } 36 | if (argc >= 8) { 37 | rdma::Config::RDMA_NUMAREGION = atoi(argv[7]); 38 | rdma::Config::RDMA_INTERFACE = "ib"+to_string(rdma::Config::RDMA_NUMAREGION); 39 | } 40 | 41 | #ifdef USE_MULTICAST 42 | Settings::PART_THREADS_COUNT = Settings::TOTAL_THREADS_COUNT / 2; 43 | #else 44 | Settings::PART_THREADS_COUNT = Settings::TOTAL_THREADS_COUNT; 45 | #endif 46 | 47 | if (dfi::Config::DFI_NODES.size() != Settings::NODES_TOTAL) { 48 | std::cout << "Config was initialized with " << dfi::Config::DFI_NODES.size() << " nodes. Does not match passed number of nodes: " << Settings::NODES_TOTAL << std::endl; 49 | exit(1); 50 | } 51 | 52 | cpu_set_t cpuset; 53 | CPU_ZERO(&cpuset); 54 | CPU_SET(rdma::Config::NUMA_THREAD_CPUS[rdma::Config::RDMA_NUMAREGION][0], &cpuset); 55 | sched_setaffinity(0, sizeof(cpuset), &cpuset); 56 | 57 | DistributedReplicateJoin join; 58 | 59 | utils::ThreadScheduler::start(Settings::TOTAL_THREADS_COUNT); 60 | 61 | std::cout << "Generating test data... full left: " << Settings::LEFT_REL_FULL_SIZE << " full right: " << Settings::RIGHT_REL_FULL_SIZE << '\n'; 62 | join.generate_test_data(); 63 | 64 | join.initialize_dfi(); 65 | 66 | join.run(); 67 | 68 | utils::ThreadScheduler::stop(); 69 | } 70 | -------------------------------------------------------------------------------- /src/dfi/flow/FlowTarget.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../utils/Config.h" 4 | #include "../memory/local_iterators/BufferIterator.h" 5 | #include "../memory/NodeClient.h" 6 | #include "../registry/RegistryClient.h" 7 | #include "../type/Schema.h" 8 | #include "../type/Tuple.h" 9 | #include "FlowHandle.h" 10 | 11 | namespace dfi 12 | { 13 | 14 | class FlowTarget 15 | { 16 | public: 17 | //FlowTarget and NodeServer must run in the same process! 18 | FlowTarget(TargetID targetID, FlowHandle flowHandle); 19 | 20 | ~FlowTarget(); 21 | 22 | /** 23 | * @brief initializeConsume pulls internal data from RegistryServer about Flow. I.e., Flow must be initialized before initializeConsume is called! 24 | */ 25 | bool initializeConsume(); 26 | 27 | /** 28 | * @brief Consumes tuples from the Flow. Function will block until either a tuple is consumable, tuple is lost or flow has finished. 29 | * 30 | * @param returnedTuples - Count of tuples consumed, sat by FlowTarget 31 | * @param tuple - Tuple with ptr to memory, sat by FlowTarget 32 | * @param freeLastTuples - (to be impl.) If true: next consume call will free the last returned tuples. If false: tuples will not be freed (make sure Buffer is initialized with sufficient memory) 33 | * @return bool - True if tuple(s) were correctly consumed, (i.e. tuple ptr has been sat), false if buffer is closed 34 | */ 35 | bool consume(size_t &returnedTuples, Tuple &tuple, bool freeLastTuples = true); 36 | 37 | /** 38 | * @brief Consumes tuples from the Flow. Function will not block. If no tuples are consumable, returnedTuples will be 0 and true returned. 39 | * 40 | * @param returnedTuples - Count of tuples consumed, sat by FlowTarget 41 | * @param tuple - Tuple with ptr to memory, sat by FlowTarget 42 | * @param freeLastTuples - (to be impl.) If true: next consume call will free the last returned tuples. If false: tuples will not be freed (make sure Buffer is initialized with sufficient memory) 43 | * @return bool - True if tuple(s) were correctly consumed, or no tuples are consumable - false if buffer is closed 44 | */ 45 | bool consumeAsync(size_t &returnedTuples, Tuple &tuple, bool freeLastTuples = true); 46 | 47 | private: 48 | 49 | void closeFlow(); 50 | std::unique_ptr m_bufferHandle; 51 | TargetID targetID; 52 | FlowHandle m_flowHandle; 53 | Schema *m_schema = nullptr; 54 | BufferIteratorInterface *bufferIterator = nullptr; 55 | bool m_flowActive = false; 56 | }; 57 | 58 | } //dfi namespace end 59 | -------------------------------------------------------------------------------- /src/use-cases/distributed-radix-join-flow/utils/ThreadScheduler.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * ThreadScheduler.cpp 3 | * 4 | * Created on: 03.01.2015 5 | * Author: cbinnig 6 | */ 7 | 8 | #include 9 | #include 10 | #include "../Settings.h" 11 | #include "ThreadScheduler.h" 12 | 13 | bool utils::ThreadScheduler::running = 0; 14 | size_t utils::ThreadScheduler::numThreads; 15 | std::thread* utils::ThreadScheduler::threads; 16 | 17 | std::queue utils::ThreadScheduler::pending; 18 | std::mutex utils::ThreadScheduler::pending_mutex; 19 | std::condition_variable utils::ThreadScheduler::pending_cv; 20 | 21 | void utils::ThreadScheduler::doWork(int tid) { 22 | int cpu = rdma::Config::NUMA_THREAD_CPUS[rdma::Config::RDMA_NUMAREGION][tid]; 23 | cpu_set_t cpuset; 24 | CPU_ZERO(&cpuset); 25 | CPU_SET(cpu, &cpuset); 26 | sched_setaffinity(0, sizeof(cpuset), &cpuset); 27 | // std::cout << "Created worker thread, pinned to cpu: " << cpu << '\n'; 28 | 29 | // execute functions in pending queue 30 | while (ThreadScheduler::running) { 31 | std::unique_lock lck(pending_mutex); 32 | while (pending.size() == 0 && ThreadScheduler::running != 0) { 33 | pending_cv.wait(lck); 34 | } 35 | 36 | if (!ThreadScheduler::running) { 37 | lck.unlock(); 38 | return; 39 | } 40 | 41 | //cout << "ThreadScheduler: Thread " <tid = tid; 48 | 49 | //execute thread 50 | t->run(); 51 | t->setFinished(1); 52 | } 53 | } 54 | 55 | void utils::ThreadScheduler::start(size_t numThreads) { 56 | utils::ThreadScheduler::running = 1; 57 | 58 | //size_t numThreads = (size_t) ceil(thread::hardware_concurrency() / CLIENTS_SIZE); 59 | threads = new std::thread[numThreads]; 60 | 61 | std::cout << "Starting " << numThreads << " threads in utils::ThreadScheduler!" << "\n"; 62 | for (size_t i = 0; i < numThreads; ++i) { 63 | threads[i] = std::thread(utils::ThreadScheduler::doWork, i); 64 | } 65 | } 66 | 67 | void utils::ThreadScheduler::push(utils::Thread* t) { 68 | if (utils::ThreadScheduler::running) { 69 | std::unique_lock lck(pending_mutex); 70 | pending.push(t); 71 | pending_cv.notify_one(); 72 | lck.unlock(); 73 | } 74 | } 75 | 76 | void utils::ThreadScheduler::stop() { 77 | utils::ThreadScheduler::running = 0; 78 | pending_cv.notify_all(); 79 | for (size_t i = 0; i < numThreads; ++i) { 80 | threads[i].join(); 81 | } 82 | } 83 | 84 | bool utils::ThreadScheduler::isRunning() { 85 | return running; 86 | } -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/utils/ThreadScheduler.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * ThreadScheduler.cpp 3 | * 4 | * Created on: 03.01.2015 5 | * Author: cbinnig 6 | */ 7 | 8 | #include 9 | #include 10 | #include "../Settings.h" 11 | #include "ThreadScheduler.h" 12 | 13 | bool utils::ThreadScheduler::running = 0; 14 | size_t utils::ThreadScheduler::numThreads; 15 | std::thread* utils::ThreadScheduler::threads; 16 | 17 | std::queue utils::ThreadScheduler::pending; 18 | std::mutex utils::ThreadScheduler::pending_mutex; 19 | std::condition_variable utils::ThreadScheduler::pending_cv; 20 | 21 | void utils::ThreadScheduler::doWork(int tid) { 22 | int cpu = rdma::Config::NUMA_THREAD_CPUS[rdma::Config::RDMA_NUMAREGION][tid]; 23 | cpu_set_t cpuset; 24 | CPU_ZERO(&cpuset); 25 | CPU_SET(cpu, &cpuset); 26 | sched_setaffinity(0, sizeof(cpuset), &cpuset); 27 | // std::cout << "Created worker thread, pinned to cpu: " + std::to_string(cpu) + '\n'; 28 | 29 | // execute functions in pending queue 30 | while (ThreadScheduler::running) { 31 | std::unique_lock lck(pending_mutex); 32 | while (pending.size() == 0 && ThreadScheduler::running != 0) { 33 | pending_cv.wait(lck); 34 | } 35 | 36 | if (!ThreadScheduler::running) { 37 | lck.unlock(); 38 | return; 39 | } 40 | 41 | //cout << "ThreadScheduler: Thread " <tid = tid; 48 | 49 | //execute thread 50 | t->run(); 51 | t->setFinished(1); 52 | } 53 | } 54 | 55 | void utils::ThreadScheduler::start(size_t numThreads) { 56 | utils::ThreadScheduler::running = 1; 57 | 58 | //size_t numThreads = (size_t) ceil(thread::hardware_concurrency() / CLIENTS_SIZE); 59 | threads = new std::thread[numThreads]; 60 | 61 | std::cout << "Starting " << numThreads << " threads in utils::ThreadScheduler!" << "\n"; 62 | for (size_t i = 0; i < numThreads; ++i) { 63 | threads[i] = std::thread(utils::ThreadScheduler::doWork, i); 64 | } 65 | } 66 | 67 | void utils::ThreadScheduler::push(utils::Thread* t) { 68 | if (utils::ThreadScheduler::running) { 69 | std::unique_lock lck(pending_mutex); 70 | pending.push(t); 71 | pending_cv.notify_one(); 72 | lck.unlock(); 73 | } 74 | } 75 | 76 | void utils::ThreadScheduler::stop() { 77 | utils::ThreadScheduler::running = 0; 78 | pending_cv.notify_all(); 79 | for (size_t i = 0; i < numThreads; ++i) { 80 | threads[i].join(); 81 | } 82 | } 83 | 84 | bool utils::ThreadScheduler::isRunning() { 85 | return running; 86 | } -------------------------------------------------------------------------------- /src/use-cases/distributed-radix-join-flow/BuildProber.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Relation.h" 4 | #include "Settings.h" 5 | #include "Partition.h" 6 | #include "BuildProberThread.h" 7 | 8 | class BuildProber 9 | { 10 | public: 11 | BuildProber(PartitionHolder **left_partitions, PartitionHolder **right_partitions); 12 | ~BuildProber(); 13 | size_t get_joined_tuples_cnt() { return joined_tuples_cnt; }; 14 | void run(); 15 | void join(); 16 | private: 17 | std::vector builder_threads; 18 | size_t processed_tuples_cnt = 0; 19 | PartitionHolder **left_partitions; 20 | PartitionHolder **right_partitions; 21 | size_t partition_count; 22 | size_t joined_tuples_cnt = 0; 23 | size_t consumed_tuples_cnt = 0; 24 | }; 25 | 26 | 27 | BuildProber::BuildProber(PartitionHolder **left_partitions, PartitionHolder **right_partitions) : left_partitions(left_partitions), right_partitions(right_partitions) 28 | { 29 | auto network_parts = Settings::get_partitions(Settings::NODE_ID, Settings::NETWORK_PARTITION_COUNT).size(); 30 | 31 | partition_count = Settings::LOCAL_PARTITION_COUNT * Settings::get_partitions(Settings::NODE_ID, Settings::NETWORK_PARTITION_COUNT).size(); 32 | 33 | std::cout << "Creating " << partition_count << " BuildProberThreads" << '\n'; 34 | 35 | builder_threads.reserve(partition_count); 36 | for(size_t i = 0; i < network_parts; i++) { 37 | for(size_t j = 0; j < Settings::LOCAL_PARTITION_COUNT; j++) 38 | { 39 | BuildProberThread *thread = new BuildProberThread(*left_partitions[i]->partitions[j], *right_partitions[i]->partitions[j]); 40 | builder_threads.push_back(thread); 41 | } 42 | } 43 | 44 | 45 | // if (count != partition_count) 46 | // { 47 | // std::cout << "Threads created: " << count << " did not match expected " << partition_count << '\n'; 48 | // exit(1); 49 | // } 50 | 51 | 52 | } 53 | 54 | BuildProber::~BuildProber() 55 | { 56 | for(auto &thread : builder_threads) { 57 | delete thread; 58 | } 59 | } 60 | 61 | void BuildProber::run() 62 | { 63 | for(auto &thread : builder_threads) { 64 | thread->start(); 65 | } 66 | } 67 | 68 | void BuildProber::join() 69 | { 70 | for(auto &thread : builder_threads) { 71 | thread->join(); 72 | joined_tuples_cnt += thread->get_joined_tuples_cnt(); 73 | consumed_tuples_cnt += thread->get_processed_left_tuples() + thread->get_processed_right_tuples(); 74 | } 75 | std::cout << "sum_consume_count=" << consumed_tuples_cnt << std::endl; 76 | std::cout << "sum_join_count=" << joined_tuples_cnt << std::endl; 77 | } -------------------------------------------------------------------------------- /src/dfi/memory/BufferHandle.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BufferHandle.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2018-07-06 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../../utils/Config.h" 10 | #include "../../utils/Logging.h" 11 | #include "local_iterators/SegmentIterator.h" 12 | #include "local_iterators/BufferIterator.h" 13 | #include "BufferSegment.h" 14 | #include "FlowOptimization.h" 15 | 16 | namespace dfi 17 | { 18 | 19 | struct BufferHandle 20 | { 21 | enum Placement { 22 | CPU, 23 | GPU_DEVICE_TGT, //Buffer is on GPU and consumed from through device functions (i.e. gpu kernel) 24 | GPU_HOST_TGT, //Buffer is on GPU and consumed from through host functions (i.e. cpu) 25 | }; 26 | 27 | string name; 28 | NodeID node_id; //Node id of where buffer resides 29 | std::vector entrySegments; //Each entry in the vector corresponds to one ring for a writer 30 | size_t segmentsPerWriter; //Number of segments in ring that will be created for each writer when createSegmentRingOnBuffer() is called 31 | size_t numberOfWriters; 32 | size_t segmentSizes; //in bytes (excluding header!) 33 | FlowOptimization buffertype; 34 | bool dataCacheAligned = false; 35 | char* localRdmaPtr = nullptr; //Pointer to start of rdma memory region on node where buffer resides. 36 | Placement placement = Placement::CPU; 37 | 38 | BufferHandle(){}; 39 | BufferHandle(string name, NodeID node_id, size_t segmentsPerWriter, size_t numberOfWriters, size_t segmentSizes, 40 | FlowOptimization buffertype = FlowOptimization::BW, bool dataCacheAligned = false) 41 | : name(name), node_id(node_id), segmentsPerWriter(segmentsPerWriter), numberOfWriters(numberOfWriters), segmentSizes(segmentSizes), buffertype(buffertype), dataCacheAligned(dataCacheAligned){}; 42 | 43 | //Returns BufferIteratorBW. Works only on local buffers! 44 | BufferIterator *getNewIterator(ConsumeScheme consumeScheme = ConsumeScheme::ASYNC) 45 | { 46 | switch(buffertype) { 47 | case FlowOptimization::BW: 48 | case FlowOptimization::LAT: 49 | return new BufferIterator(this->localRdmaPtr, entrySegments, consumeScheme, segmentsPerWriter); 50 | default: 51 | Logging::error(__FILE__, __LINE__, "getNewIterator on buffer: " + name + ", node-id: " + to_string(node_id) + ". BufferType not supported."); 52 | return nullptr; 53 | } 54 | } 55 | private: 56 | }; 57 | 58 | 59 | struct TargetOptions 60 | { 61 | TargetID targetId; 62 | size_t full_segment_size; 63 | size_t segments_per_ring; 64 | BufferHandle::Placement target_placement; 65 | //# sources?? 66 | }; 67 | 68 | 69 | } // namespace dfi 70 | -------------------------------------------------------------------------------- /src/use-cases/rsm-nopaxos/utils/ThreadScheduler.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * ThreadScheduler.cpp 3 | * 4 | * Created on: 03.01.2015 5 | * Author: cbinnig 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "../../../rdma-manager/src/utils/Config.h" 13 | #include "ThreadScheduler.h" 14 | 15 | const int utils::ThreadScheduler::cpus[] = {0, 1, 2, 3, 4, 5, 6, 7}; 16 | bool utils::ThreadScheduler::running = 0; 17 | size_t utils::ThreadScheduler::numThreads; 18 | std::thread* utils::ThreadScheduler::threads; 19 | 20 | std::queue utils::ThreadScheduler::pending; 21 | std::mutex utils::ThreadScheduler::pending_mutex; 22 | std::condition_variable utils::ThreadScheduler::pending_cv; 23 | 24 | void utils::ThreadScheduler::doWork(int tid) { 25 | 26 | std::vector cpus = rdma::Config::NUMA_THREAD_CPUS[rdma::Config::RDMA_NUMAREGION]; 27 | int cpu = cpus[tid]; 28 | 29 | std::cout << "Starting thread on cpu: " << cpu << std::endl; 30 | cpu_set_t cpuset; 31 | CPU_ZERO(&cpuset); 32 | CPU_SET(cpu, &cpuset); 33 | sched_setaffinity(0, sizeof(cpuset), &cpuset); 34 | 35 | // execute functions in pending queue 36 | while (ThreadScheduler::running) { 37 | std::unique_lock lck(pending_mutex); 38 | while (pending.size() == 0 && ThreadScheduler::running != 0) { 39 | pending_cv.wait(lck); 40 | } 41 | 42 | if (!ThreadScheduler::running) { 43 | lck.unlock(); 44 | return; 45 | } 46 | 47 | //cout << "ThreadScheduler: Thread " <tid = tid; 54 | 55 | //execute thread 56 | t->run(); 57 | t->setFinished(1); 58 | } 59 | } 60 | 61 | void utils::ThreadScheduler::start(size_t numThreads) { 62 | utils::ThreadScheduler::running = 1; 63 | 64 | //size_t numThreads = (size_t) ceil(thread::hardware_concurrency() / CLIENTS_SIZE); 65 | threads = new std::thread[numThreads]; 66 | 67 | std::cout << "Starting " << numThreads << " threads in utils::ThreadScheduler!" << "\n"; 68 | for (size_t i = 0; i < numThreads; ++i) { 69 | threads[i] = std::thread(utils::ThreadScheduler::doWork, i); 70 | } 71 | } 72 | 73 | void utils::ThreadScheduler::push(utils::Thread* t) { 74 | if (utils::ThreadScheduler::running) { 75 | std::unique_lock lck(pending_mutex); 76 | pending.push(t); 77 | pending_cv.notify_one(); 78 | lck.unlock(); 79 | } 80 | } 81 | 82 | void utils::ThreadScheduler::stop() { 83 | utils::ThreadScheduler::running = 0; 84 | pending_cv.notify_all(); 85 | for (size_t i = 0; i < numThreads; ++i) { 86 | threads[i].join(); 87 | } 88 | } 89 | 90 | bool utils::ThreadScheduler::isRunning() { 91 | return running; 92 | } 93 | 94 | -------------------------------------------------------------------------------- /src/use-cases/rsm-paxos/utils/ThreadScheduler.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * ThreadScheduler.cpp 3 | * 4 | * Created on: 03.01.2015 5 | * Author: cbinnig 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "../../../rdma-manager/src/utils/Config.h" 13 | #include "ThreadScheduler.h" 14 | 15 | const int utils::ThreadScheduler::cpus[] = {0, 1, 2, 3, 4, 5, 6, 7}; 16 | bool utils::ThreadScheduler::running = 0; 17 | size_t utils::ThreadScheduler::numThreads; 18 | std::thread* utils::ThreadScheduler::threads; 19 | 20 | std::queue utils::ThreadScheduler::pending; 21 | std::mutex utils::ThreadScheduler::pending_mutex; 22 | std::condition_variable utils::ThreadScheduler::pending_cv; 23 | 24 | void utils::ThreadScheduler::doWork(int tid) { 25 | 26 | std::vector cpus = rdma::Config::NUMA_THREAD_CPUS[rdma::Config::RDMA_NUMAREGION]; 27 | int cpu = cpus[tid]; 28 | 29 | std::cout << "Starting thread on cpu: " << cpu << std::endl; 30 | cpu_set_t cpuset; 31 | CPU_ZERO(&cpuset); 32 | CPU_SET(cpu, &cpuset); 33 | sched_setaffinity(0, sizeof(cpuset), &cpuset); 34 | 35 | // execute functions in pending queue 36 | while (ThreadScheduler::running) { 37 | std::unique_lock lck(pending_mutex); 38 | while (pending.size() == 0 && ThreadScheduler::running != 0) { 39 | pending_cv.wait(lck); 40 | } 41 | 42 | if (!ThreadScheduler::running) { 43 | lck.unlock(); 44 | return; 45 | } 46 | 47 | //cout << "ThreadScheduler: Thread " <tid = tid; 54 | 55 | //execute thread 56 | t->run(); 57 | t->setFinished(1); 58 | } 59 | } 60 | 61 | void utils::ThreadScheduler::start(size_t numThreads) { 62 | utils::ThreadScheduler::running = 1; 63 | 64 | //size_t numThreads = (size_t) ceil(thread::hardware_concurrency() / CLIENTS_SIZE); 65 | threads = new std::thread[numThreads]; 66 | 67 | std::cout << "Starting " << numThreads << " threads in utils::ThreadScheduler!" << "\n"; 68 | for (size_t i = 0; i < numThreads; ++i) { 69 | threads[i] = std::thread(utils::ThreadScheduler::doWork, i); 70 | } 71 | } 72 | 73 | void utils::ThreadScheduler::push(utils::Thread* t) { 74 | if (utils::ThreadScheduler::running) { 75 | std::unique_lock lck(pending_mutex); 76 | pending.push(t); 77 | pending_cv.notify_one(); 78 | lck.unlock(); 79 | } 80 | } 81 | 82 | void utils::ThreadScheduler::stop() { 83 | utils::ThreadScheduler::running = 0; 84 | pending_cv.notify_all(); 85 | for (size_t i = 0; i < numThreads; ++i) { 86 | threads[i].join(); 87 | } 88 | } 89 | 90 | bool utils::ThreadScheduler::isRunning() { 91 | return running; 92 | } 93 | 94 | -------------------------------------------------------------------------------- /src/dfi/flow/FlowSourceMulticastBW.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "FlowSourceInterface.h" 4 | #include "../memory/BufferWriterMulticast.h" 5 | 6 | namespace dfi 7 | { 8 | 9 | class FlowSourceMulticastBW final : public FlowSourceInterface { 10 | SourceID m_sourceId; 11 | std::unique_ptr> m_bufferWriter; 12 | size_t m_tupleSize = 0; 13 | size_t max_tuples_in_segment; 14 | size_t cur_tuples_in_segment = 0; 15 | public: 16 | FlowSourceMulticastBW(FlowHandle flowHandle, SourceID sourceId) : 17 | FlowSourceInterface(flowHandle), m_sourceId{sourceId} { 18 | 19 | if (m_flowHandle.optimization != FlowOptimization::MULTICAST && m_flowHandle.optimization != FlowOptimization::MULTICAST_BW) { 20 | throw new invalid_argument("FlowSourceMulticastBW ctor: FlowOptimization not MulticastBW (FlowOptimization::MULTICAST)"); 21 | } 22 | 23 | size_t max_segment_size = rdma::Config::RDMA_UD_MTU - sizeof(DFI_MULTICAST_SEGMENT_HEADER_t); //MTU minus header size 24 | max_tuples_in_segment = max_segment_size / m_flowHandle.schema.getTupleSize(); 25 | 26 | if (max_tuples_in_segment < 1) 27 | throw new invalid_argument("FlowSourceMulticastBW ctor: Tuple sizes are bigger than MTU (minus header)!"); 28 | 29 | size_t segment_size = max_tuples_in_segment * m_flowHandle.schema.getTupleSize(); 30 | 31 | m_bufferWriter = std::make_unique>(m_flowHandle, sourceId, segment_size); 32 | 33 | m_tupleSize = flowHandle.schema.getTupleSize(); 34 | 35 | Logging::debug(__FILE__, __LINE__, "FlowSourceMulticastBW created for flow: " + flowHandle.name); 36 | } 37 | 38 | ~FlowSourceMulticastBW() { 39 | close(); 40 | } 41 | 42 | inline bool pushToAll(Tuple const &tuple, bool forceSignaled=false) override 43 | { 44 | m_bufferWriter->add(tuple.getDataPtr(), m_tupleSize, forceSignaled); 45 | ++cur_tuples_in_segment; 46 | if (cur_tuples_in_segment == max_tuples_in_segment) 47 | { 48 | m_bufferWriter->flush(forceSignaled); 49 | cur_tuples_in_segment = 0; 50 | } 51 | return true; 52 | } 53 | 54 | inline bool flush(TargetID) override 55 | { 56 | if (cur_tuples_in_segment > 0) 57 | { 58 | m_bufferWriter->flush(); 59 | cur_tuples_in_segment = 0; 60 | } 61 | return true; 62 | } 63 | 64 | void close() override 65 | { 66 | if (!m_isClosed) { 67 | m_bufferWriter->close(); 68 | } 69 | m_isClosed = true; 70 | } 71 | private: 72 | // don't call this 73 | bool push(Tuple const &, TargetID, bool) { 74 | return false; 75 | }; 76 | }; 77 | 78 | 79 | 80 | } -------------------------------------------------------------------------------- /cmake/modules/FindSQLite3.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find Sqlite3 2 | # Once done this will define 3 | # 4 | # SQLITE3_FOUND - system has Sqlite3 5 | # SQLITE3_INCLUDE_DIRS - the Sqlite3 include directory 6 | # SQLITE3_LIBRARIES - Link these to use Sqlite3 7 | # SQLITE3_DEFINITIONS - Compiler switches required for using Sqlite3 8 | # 9 | # Copyright (c) 2008 Andreas Schneider 10 | # 11 | # Redistribution and use is allowed according to the terms of the New 12 | # BSD license. 13 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 14 | # 15 | 16 | if (SQLITE3_LIBRARIES AND SQLITE3_INCLUDE_DIRS) 17 | # in cache already 18 | set(SQLITE3_FOUND TRUE) 19 | else (SQLITE3_LIBRARIES AND SQLITE3_INCLUDE_DIRS) 20 | # use pkg-config to get the directories and then use these values 21 | # in the FIND_PATH() and FIND_LIBRARY() calls 22 | if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) 23 | include(UsePkgConfig) 24 | pkgconfig(sqlite3 _SQLITE3_INCLUDEDIR _SQLITE3_LIBDIR _SQLITE3_LDFLAGS _SQLITE3_CFLAGS) 25 | else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) 26 | find_package(PkgConfig) 27 | if (PKG_CONFIG_FOUND) 28 | pkg_check_modules(_SQLITE3 sqlite3) 29 | endif (PKG_CONFIG_FOUND) 30 | endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) 31 | find_path(SQLITE3_INCLUDE_DIR 32 | NAMES 33 | sqlite3.h 34 | PATHS 35 | ${_SQLITE3_INCLUDEDIR} 36 | /usr/include 37 | /usr/local/include 38 | /opt/local/include 39 | /sw/include 40 | ) 41 | 42 | find_library(SQLITE3_LIBRARY 43 | NAMES 44 | sqlite3 45 | PATHS 46 | ${_SQLITE3_LIBDIR} 47 | /usr/lib 48 | /usr/local/lib 49 | /opt/local/lib 50 | /sw/lib 51 | ) 52 | 53 | if (SQLITE3_LIBRARY) 54 | set(SQLITE3_FOUND TRUE) 55 | endif (SQLITE3_LIBRARY) 56 | 57 | set(SQLITE3_INCLUDE_DIRS 58 | ${SQLITE3_INCLUDE_DIR} 59 | ) 60 | 61 | if (SQLITE3_FOUND) 62 | set(SQLITE3_LIBRARIES 63 | ${SQLITE3_LIBRARIES} 64 | ${SQLITE3_LIBRARY} 65 | ) 66 | endif (SQLITE3_FOUND) 67 | 68 | if (SQLITE3_INCLUDE_DIRS AND SQLITE3_LIBRARIES) 69 | set(SQLITE3_FOUND TRUE) 70 | endif (SQLITE3_INCLUDE_DIRS AND SQLITE3_LIBRARIES) 71 | 72 | if (SQLITE3_FOUND) 73 | if (NOT Sqlite3_FIND_QUIETLY) 74 | message(STATUS "Found Sqlite3: ${SQLITE3_LIBRARIES}") 75 | endif (NOT Sqlite3_FIND_QUIETLY) 76 | else (SQLITE3_FOUND) 77 | if (Sqlite3_FIND_REQUIRED) 78 | message(FATAL_ERROR "Could not find Sqlite3") 79 | endif (Sqlite3_FIND_REQUIRED) 80 | endif (SQLITE3_FOUND) 81 | 82 | # show the SQLITE3_INCLUDE_DIRS and SQLITE3_LIBRARIES variables only in the advanced view 83 | mark_as_advanced(SQLITE3_INCLUDE_DIRS SQLITE3_LIBRARIES) 84 | 85 | endif (SQLITE3_LIBRARIES AND SQLITE3_INCLUDE_DIRS) 86 | -------------------------------------------------------------------------------- /src/dfi/memory/NodeClient.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file NodeClient.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2018-07-06 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../../utils/Config.h" 10 | #include "../../utils/Logging.h" 11 | #include "../../rdma-manager/src/rdma/RDMAClient.h" 12 | #include "FlowOptimization.h" 13 | #include "../message/MessageTypes.h" 14 | #include "../message/MessageErrors.h" 15 | 16 | namespace dfi 17 | { 18 | 19 | class NodeClient : public rdma::RDMAClient 20 | { 21 | typedef rdma::RDMAClient RDMAClient; 22 | public: 23 | NodeClient(/* args */); 24 | NodeClient(size_t memsize); 25 | ~NodeClient(); 26 | 27 | bool remoteAllocSegments(const string& connection, const NodeID nodeID, const string& bufferName, const size_t segmentsCount, 28 | const size_t fullSegmentSize, FlowOptimization buffertype, bool cacheAlign, std::vector& offsets, size_t count); 29 | bool remoteFreeSegments(const string& connection, const NodeID nodeID, const string& bufferName); 30 | 31 | uint64_t getStartRdmaAddrForNode(NodeID nodeid); 32 | 33 | bool connect(const string& ipPort, NodeID DFINodeID) { 34 | NodeID retServerNodeID = 0; 35 | bool ret = RDMAClient::connect(ipPort, retServerNodeID); 36 | if (DFINodeIDToRDMANodeID.size() < DFINodeID + 1) { 37 | DFINodeIDToRDMANodeID.resize(DFINodeID + 1); 38 | } 39 | DFINodeIDToRDMANodeID[DFINodeID] = retServerNodeID; 40 | return ret; 41 | } 42 | void write(const NodeID nodeID, size_t offset, const void* memAddr, 43 | size_t size, bool signaled) 44 | { 45 | RDMAClient::write(DFINodeIDToRDMANodeID[nodeID], offset, memAddr, size, signaled); 46 | 47 | } 48 | void read(const NodeID nodeID, size_t offset, const void* memAddr, 49 | size_t size, bool signaled) 50 | { 51 | RDMAClient::read(DFINodeIDToRDMANodeID[nodeID], offset, memAddr, size, signaled); 52 | 53 | } 54 | void send(const NodeID nodeID, const void* memAddr, size_t size, 55 | bool signaled) 56 | { 57 | RDMAClient::send(DFINodeIDToRDMANodeID[nodeID], memAddr, size, signaled); 58 | } 59 | void receive(const NodeID nodeID, const void* memAddr, 60 | size_t size) 61 | { 62 | RDMAClient::receive(DFINodeIDToRDMANodeID[nodeID], memAddr, size); 63 | } 64 | private: 65 | std::vector DFINodeIDToRDMANodeID; 66 | 67 | using RDMAClient::send; //Make private 68 | using RDMAClient::receive; //Make private 69 | using RDMAClient::write; //Make private 70 | using RDMAClient::read; //Make private 71 | using RDMAClient::remoteAlloc; 72 | using RDMAClient::remoteFree; 73 | using RDMAClient::setRemoteConnData; 74 | 75 | 76 | }; 77 | } // namespace dfi 78 | -------------------------------------------------------------------------------- /src/dfi/memory/MulticastSegmentBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../flow/FlowHandle.h" 4 | 5 | namespace dfi 6 | { 7 | 8 | struct MulticastACK 9 | { 10 | TargetID target_id; 11 | seq_no_t seq_no; 12 | uint16_t budget_increment; 13 | }; 14 | 15 | class MulticastACKArray 16 | { 17 | uint8_t *ptr; 18 | size_t size; 19 | 20 | public: 21 | MulticastACKArray() = default; 22 | MulticastACKArray(MulticastACK *ptr, size_t size) : ptr(reinterpret_cast(ptr)), size(size) {} 23 | 24 | //index operator overload to handle UD Header offset 25 | MulticastACK &operator[] (size_t i) 26 | { 27 | uint8_t *ret_ptr = ptr + (sizeof(MulticastACK) + rdma::Config::RDMA_UD_OFFSET) * i + rdma::Config::RDMA_UD_OFFSET; 28 | if ((size_t)(ret_ptr - ptr) > size) 29 | throw out_of_range("Out of bounds exception"); 30 | return *reinterpret_cast(ret_ptr); 31 | } 32 | }; 33 | struct MulticastSegmentBuffer 34 | { 35 | void *buffer; 36 | size_t segments; 37 | size_t segment_size; 38 | size_t current_idx = 0; 39 | 40 | MulticastSegmentBuffer(FlowHandle &flowHandle, size_t segmentSizes) : segments{flowHandle.segmentsPerRing}, segment_size{segmentSizes != 0 ? segmentSizes + sizeof(DFI_MULTICAST_SEGMENT_HEADER_t) : flowHandle.segmentSizes + sizeof(DFI_MULTICAST_SEGMENT_HEADER_t)} 41 | { 42 | } 43 | 44 | size_t size() 45 | { 46 | return segments * (segment_size + rdma::Config::RDMA_UD_OFFSET); 47 | } 48 | 49 | // return current segment, increase index 50 | void *next() 51 | { 52 | void *segment = get(current_idx); 53 | current_idx = ((current_idx + 1) == segments) ? 0 : current_idx + 1; 54 | return segment; 55 | } 56 | 57 | // return current segment wihtout setting header, increase index 58 | void *next_data() { 59 | return reinterpret_cast(next()) + sizeof(DFI_MULTICAST_SEGMENT_HEADER_t); 60 | } 61 | 62 | // return current segment with set header, increase index 63 | void *next(seq_no_t segment_idx, bool is_last, SourceID sourceId) 64 | { 65 | void *segment = next(); 66 | new (segment) DFI_MULTICAST_SEGMENT_HEADER_t{segment_idx, is_last, sourceId}; 67 | return segment; 68 | } 69 | 70 | void *get(size_t idx) 71 | { 72 | return reinterpret_cast(buffer) + idx * (segment_size + rdma::Config::RDMA_UD_OFFSET) + rdma::Config::RDMA_UD_OFFSET; 73 | } 74 | 75 | void *get_prev() 76 | { 77 | const uint32_t prev_idx = (current_idx == 0) ? segments - 1 : current_idx - 1; 78 | return get(prev_idx); 79 | } 80 | 81 | DFI_MULTICAST_SEGMENT_HEADER_t *get_header() 82 | { 83 | void *segment = get(current_idx); 84 | return reinterpret_cast(segment); 85 | } 86 | }; 87 | } // namespace dfi -------------------------------------------------------------------------------- /src/use-cases/rsm-nopaxos/Settings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../utils/Config.h" 4 | #include "utils/HashTable.h" 5 | 6 | #include 7 | 8 | #define UNUSED ((uint64_t) 0) 9 | #define HT_SIZE 4194304 10 | 11 | #define CMD_SIZE 64 12 | #define NOOP_CMD {.operation = Operation::NOOP, .key = 0, .value = 0, .padding = {0}} 13 | 14 | #define PADDING_SIZE (CMD_SIZE - 24) 15 | typedef uint64_t Padding[PADDING_SIZE / 8]; 16 | 17 | enum Operation { 18 | EMPTY = 0, 19 | READ = 1, 20 | WRITE = 2, 21 | NOOP = 3, 22 | }; 23 | 24 | // Commands send to the RSM. We artificailly inflate the commands to emulate CMD_SIZE byte commands. 25 | struct Command { 26 | uint64_t operation; 27 | uint64_t key; 28 | uint64_t value; 29 | Padding padding; 30 | } __attribute__((packed)); 31 | 32 | enum Return 33 | { 34 | SUCCESS = 0, 35 | FAILED = 1, 36 | NOOP_RET = 2 37 | }; 38 | 39 | struct ClientRequest 40 | { 41 | int8_t clientid; 42 | Command cmd; 43 | uint64_t reqid; 44 | } __attribute__((packed)); 45 | 46 | struct ClientResponse 47 | { 48 | int8_t clientid; // used for key of shuffle flow 49 | uint64_t viewid; 50 | uint64_t log_slot_num; 51 | uint64_t reqid; 52 | 53 | int8_t leader_reply; 54 | int8_t return_code; 55 | uint64_t result; 56 | } __attribute__((packed)); 57 | 58 | struct GapLeaderMsg 59 | { 60 | int8_t replicaid; // recipient 61 | uint64_t log_slot_num; 62 | } __attribute__((packed)); 63 | 64 | struct GapFollowerMsg 65 | { 66 | int8_t receiver; // recipient 67 | int8_t sender; // sender 68 | uint64_t log_slot_num; 69 | Command cmd; // not needed for most msg, but simplifies implementation 70 | } __attribute__((packed)); 71 | 72 | struct VerificationMsg 73 | { 74 | uint64_t log_slot_num; 75 | Command cmd; 76 | } __attribute__((packed)); 77 | 78 | struct Settings 79 | { 80 | static string BENCH_FILE; 81 | 82 | static string FLOWNAME_OUM; 83 | static string FLOWNAME_RESPONSE; 84 | static string FLOWNAME_GAP_LEADER; 85 | static string FLOWNAME_GAP_FOLLOWER; 86 | static string FLOWNAME_VERIFICATION; 87 | 88 | static NodeID LEADER_ID; 89 | static NodeID REGISTRY_ID; 90 | static NodeID SEQUENCER_ID; 91 | static NodeID NODE_ID; 92 | 93 | static uint64_t COMMAND_COUNT; // total number of commands send during run 94 | static uint64_t COMMANDS_PER_SECOND; // total number of commands send during run 95 | static size_t REPLICA_COUNT; 96 | static size_t CLIENT_COUNT; 97 | }; 98 | 99 | inline uint64_t rand_val() 100 | { 101 | return (rand() % 100000000); 102 | } 103 | 104 | inline bool commands_equal(const Command& a, const Command& b) 105 | { 106 | return a.operation == b.operation && a.key == b.key && a.value == b.value; 107 | } -------------------------------------------------------------------------------- /src/dfi/type/Schema.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Schema.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2019-01-14 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../../utils/Config.h" 10 | #include "Type.h" 11 | 12 | namespace dfi 13 | { 14 | 15 | class Schema 16 | { 17 | 18 | struct Column 19 | { 20 | std::string name; 21 | TypeId typeId; 22 | uint32_t offset; 23 | Column(std::string &name, TypeId typeId, uint32_t offset) : name(name), typeId(typeId), offset(offset) {}; 24 | Column(){}; 25 | }; 26 | 27 | public: 28 | Schema() {} 29 | 30 | Schema(std::vector> columns) 31 | { 32 | m_columnCount = columns.size(); 33 | m_columns.resize(m_columnCount); 34 | uint32_t offset = 0; 35 | size_t i = 0; 36 | for (auto &column : columns) 37 | { 38 | auto colName = column.first; 39 | auto colType = column.second; 40 | m_columns[i] = Column(colName, colType, offset); 41 | offset += Type::getTypeSize(colType); 42 | ++i; 43 | } 44 | m_tupleSize = offset; 45 | } 46 | 47 | // Schema& operator=(const Schema& other) 48 | // { 49 | // this->m_columns = other.m_columns; 50 | // this->m_columnCount = other.m_columnCount; 51 | // this->m_tupleSize = other.m_tupleSize; 52 | // return *this; 53 | // } 54 | 55 | uint32_t getColumnCount() { return m_columnCount; }; 56 | 57 | TypeId getTypeForColumn(uint32_t index) //0-based 58 | { 59 | return m_columns[index].typeId; 60 | } 61 | 62 | string getNameForColumn(uint32_t index) 63 | { 64 | return m_columns[index].name; 65 | } 66 | 67 | uint32_t getOffsetForColumn(uint32_t index) //0-based 68 | { 69 | if (index >= m_columnCount) 70 | throw std::runtime_error("Index out of range"); 71 | return m_columns[index].offset; 72 | }; 73 | 74 | 75 | uint32_t getOffsetForColumn(std::string const &name) 76 | { 77 | return m_columns[this->getIndexForColumn(name)].offset; 78 | }; 79 | 80 | 81 | //If column not found, max uint32_t size returned 82 | uint32_t getIndexForColumn(std::string const &name) 83 | { 84 | for (size_t i = 0; i < m_columnCount; i++) { 85 | if (m_columns[i].name.compare(name) == 0) { 86 | return i; 87 | } 88 | } 89 | throw std::runtime_error("Could not find index for column name: " + name); 90 | }; 91 | 92 | //Size of each tuple in bytes 93 | uint32_t getTupleSize() 94 | { 95 | return m_tupleSize; 96 | }; 97 | 98 | private: 99 | uint32_t m_columnCount; 100 | uint32_t m_tupleSize; 101 | std::vector m_columns; 102 | }; 103 | 104 | 105 | } -------------------------------------------------------------------------------- /src/gtest/memory/TestBufferIterator.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file IntegrationTestsAppend.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2018-08-17 5 | */ 6 | 7 | #pragma once 8 | #include 9 | 10 | #include "../../utils/Config.h" 11 | 12 | #include "../../dfi/registry/RegistryClient.h" 13 | #include "../../dfi/registry/RegistryServer.h" 14 | #include "../../dfi/memory/BufferHandle.h" 15 | #include "../../dfi/memory/NodeServer.h" 16 | #include "../../dfi/memory/NodeClient.h" 17 | #include "../../dfi/memory/BufferWriter.h" 18 | #include "../../dfi/memory/BufferWriter.h" 19 | 20 | #include 21 | 22 | 23 | class TestBufferIterator : public testing::Test 24 | { 25 | 26 | public: 27 | void SetUp() override; 28 | void TearDown() override; 29 | 30 | 31 | static std::atomic bar; // Counter of threads, faced barrier. 32 | static std::atomic passed; // Number of barriers, passed by all threads. 33 | 34 | protected: 35 | RegistryClient *m_regClient; 36 | RegistryServer *m_regServer; 37 | NodeServer *m_nodeServer; 38 | NodeClient *m_nodeClient; 39 | 40 | 41 | 42 | template 43 | class BufferWriterClient : public rdma::Thread 44 | { 45 | BufferHandle* buffHandle = nullptr; 46 | string& bufferName = ""; 47 | std::vector *dataToWrite = nullptr; //tuple 48 | 49 | public: 50 | 51 | BufferWriterClient(string& bufferName, std::vector *dataToWrite, int numThread = 4) : 52 | Thread(), bufferName(bufferName), dataToWrite(dataToWrite), NUMBER_THREADS(numThread) {} 53 | 54 | int NUMBER_THREADS; 55 | 56 | void run() 57 | { 58 | //ARRANGE 59 | RegistryClient registry_client; 60 | BufferWriter buffWriter(bufferName, registry_client, Config::DFI_SOURCE_SEGMENT_COUNT); 61 | 62 | barrier_wait(); //Use barrier to simulate concurrent appends between BufferWriters 63 | 64 | //ACT 65 | for(size_t i = 0; i < dataToWrite->size(); i++) 66 | { 67 | buffWriter.add(&dataToWrite->operator[](i), sizeof(DataType)); 68 | } 69 | 70 | buffWriter.close(); 71 | } 72 | 73 | void barrier_wait() 74 | { 75 | // std::cout << "Enter Barrier" << '\n'; 76 | int passed_old = passed.load(std::memory_order_relaxed); 77 | 78 | if (bar.fetch_add(1) == (NUMBER_THREADS - 1)) 79 | { 80 | // The last thread, faced barrier. 81 | bar = 0; 82 | // Synchronize and store in one operation. 83 | passed.store(passed_old + 1, std::memory_order_release); 84 | } 85 | else 86 | { 87 | // Not the last thread. Wait others. 88 | while (passed.load(std::memory_order_relaxed) == passed_old) 89 | { 90 | }; 91 | // Need to synchronize cache with other threads, passed barrier. 92 | std::atomic_thread_fence(std::memory_order_acquire); 93 | } 94 | } 95 | }; 96 | 97 | }; -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/LocalDFIPartitioner.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Partition.h" 4 | #include "Settings.h" 5 | #include "LocalDFIPartitionerThread.h" 6 | 7 | class LocalDFIPartitioner 8 | { 9 | public: 10 | LocalDFIPartitioner(Relation::Type relation_type); 11 | ~LocalDFIPartitioner(); 12 | void start_threads(); 13 | void join_threads(); 14 | PartitionHolder **get_end_partitions() { 15 | return end_partitions.data(); 16 | }; 17 | 18 | private: 19 | std::vector partitioner_threads; 20 | std::vector end_partitions; 21 | }; 22 | 23 | 24 | LocalDFIPartitioner::LocalDFIPartitioner(Relation::Type relation_type) 25 | { 26 | size_t end_partition_size = 1.5 * (Settings::LEFT_REL_FULL_SIZE / Settings::LOCAL_PARTITION_COUNT / Settings::PART_THREADS_COUNT); 27 | 28 | partitioner_threads.reserve(Settings::PART_THREADS_COUNT); 29 | end_partitions.reserve(Settings::PART_THREADS_COUNT); 30 | 31 | for(size_t i = 0; i < Settings::PART_THREADS_COUNT; i++) { 32 | PartitionHolder *partition_holder = new PartitionHolder{end_partition_size}; 33 | end_partitions.push_back(partition_holder); 34 | 35 | std::string flow_name = Settings::LEFT_REL_FLOW_NAME+std::to_string(i); 36 | partitioner_threads.push_back(new LocalDFIPartitionerThread(flow_name, Settings::NODE_ID+1, relation_type, partition_holder)); 37 | } 38 | 39 | } 40 | 41 | LocalDFIPartitioner::~LocalDFIPartitioner() { 42 | for(size_t i = 0; i < Settings::PART_THREADS_COUNT; i++) { 43 | delete partitioner_threads[i]; 44 | delete end_partitions[i]; 45 | } 46 | } 47 | 48 | void LocalDFIPartitioner::start_threads() { 49 | for (auto &thread : partitioner_threads) { 50 | thread->start(); 51 | } 52 | } 53 | 54 | void LocalDFIPartitioner::join_threads() { 55 | size_t processed_tuples = 0; 56 | 57 | long long avg_exec_time = 0; 58 | long long longest_exec_time = 0; 59 | 60 | for (auto &thread : partitioner_threads) { 61 | thread->join(); 62 | 63 | processed_tuples += thread->get_processed_tuples(); 64 | // std::cout << "Local partitioner for network partition " << node_partitions[i] << " processed " << thread->get_processed_tuples() << " tuples." << '\n'; 65 | // std::cout << "(" << thread->execution_part_time << " " << thread->execution_time << " " << thread->get_processed_tuples()/1000 << ") "; 66 | avg_exec_time += thread->execution_part_time + thread->execution_time; 67 | if (thread->execution_part_time > longest_exec_time) 68 | longest_exec_time = thread->execution_part_time; 69 | } 70 | 71 | 72 | std::cout << "Local DFI Partitioner processed total " << processed_tuples << " tuples." << '\n'; 73 | std::cout << "Average execution time: " << avg_exec_time/partitioner_threads.size()/1000 << " ms. Longest: " << longest_exec_time/1000 << " ms" << '\n'; 74 | } -------------------------------------------------------------------------------- /src/use-cases/distributed-radix-join-flow/Partition.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Settings.h" 8 | 9 | 10 | 11 | union cacheline_t { 12 | cacheline_t() { 13 | data.size = 0; 14 | }; 15 | 16 | struct { 17 | tuple_type tuples[TUPLES_PER_CACHELINE]; 18 | } tuples; 19 | 20 | struct { 21 | tuple_type tuples[TUPLES_PER_CACHELINE - 1]; 22 | uint32_t size; 23 | } data; 24 | 25 | inline bool add_tuple(tuple_type &tuple) { // return true if full after adding 26 | uint32_t size_before = data.size++; 27 | tuples.tuples[size_before] = tuple; 28 | return (size_before == TUPLES_PER_CACHELINE - 1); 29 | } 30 | 31 | inline void clear() { 32 | data.size = 0; 33 | } 34 | 35 | inline uint32_t size() { 36 | return data.size; 37 | } 38 | }; 39 | 40 | 41 | 42 | struct Partition { 43 | Partition(size_t max_tuples): max_tuples(max_tuples) { 44 | tuples = reinterpret_cast(aligned_alloc(64, max_tuples*sizeof(tuple_type))); 45 | #ifdef COMPRESSED_TUPLES 46 | std::fill_n(tuples, max_tuples, CompressedTuple_t{1}); 47 | #else 48 | std::fill_n(tuples, max_tuples, Tuple_t{1,1}); 49 | #endif 50 | } 51 | 52 | inline void add_cacheline(const cacheline_t *cacheline) { 53 | __m512i *dest = (__m512i *) &tuples[size]; 54 | __m512i src = *((__m512i *) cacheline); 55 | 56 | _mm512_stream_si512(dest, src); 57 | size += TUPLES_PER_CACHELINE; 58 | 59 | #ifdef DEBUG 60 | if (size > max_tuples) { 61 | std::cout << "size: " << size << " max tuples: " << max_tuples << std::endl; 62 | throw std::runtime_error("partition overflow!"); 63 | } 64 | #endif 65 | } 66 | 67 | inline void add_cacheline(const cacheline_t *cacheline, const size_t num_tuples) { 68 | __m512i *dest = (__m512i *) &tuples[size]; 69 | __m512i src = *((__m512i *) cacheline); 70 | 71 | _mm512_stream_si512(dest, src); 72 | size += num_tuples; 73 | 74 | #ifdef DEBUG 75 | if (size > max_tuples) { 76 | throw std::runtime_error("partition overflow!"); 77 | } 78 | #endif 79 | } 80 | 81 | const size_t max_tuples; 82 | size_t size = 0; 83 | tuple_type *tuples; 84 | }; 85 | 86 | 87 | struct PartitionHolder { 88 | PartitionHolder(size_t partition_size) { 89 | for (auto &partition : partitions) { 90 | partition = new Partition{partition_size}; 91 | } 92 | } 93 | 94 | ~PartitionHolder() { 95 | for (auto &partition : partitions) { 96 | delete partition; 97 | } 98 | } 99 | 100 | std::array partitions; 101 | }; 102 | -------------------------------------------------------------------------------- /src/gtest/flow-api/flow_barrier_tests.cc: -------------------------------------------------------------------------------- 1 | #include "flow_barrier_tests.h" 2 | 3 | void TestFlowBarrier::SetUp() 4 | { 5 | //Setup Test DFI 6 | rdma::Config::RDMA_MEMSIZE = 1024ul * 1024 * 1; //8MB 7 | Config::DFI_SOURCE_SEGMENT_COUNT = 8; 8 | Config::DFI_REGISTRY_SERVER = rdma::Config::getIP(rdma::Config::RDMA_INTERFACE); 9 | Config::DFI_REGISTRY_PORT = 5300; 10 | Config::DFI_FULL_SEGMENT_SIZE = (512 + sizeof(DFI_SEGMENT_FOOTER_t)); 11 | Config::DFI_SEGMENTS_PER_RING = 5; 12 | // Config::LOGGING_LEVEL = 1; 13 | // rdma::Config::LOGGING_LEVEL = 1; 14 | rdma::Config::SEQUENCER_IP = rdma::Config::getIP(rdma::Config::RDMA_INTERFACE); 15 | Config::DFI_NODES.clear(); 16 | Config::DFI_NODES.push_back(rdma::Config::getIP(rdma::Config::RDMA_INTERFACE) + ":" + to_string(Config::DFI_NODE_PORT)); 17 | 18 | m_regServer = std::make_unique(); 19 | 20 | m_nodeServer = std::make_unique(rdma::Config::RDMA_MEMSIZE, Config::DFI_NODE_PORT); 21 | 22 | DFI_Schema schema({{"value", dfi::TypeId::BIGINT}}); 23 | 24 | std::vector targets = {{1, 1}, {2, 1}}; 25 | if (DFI_Shuffle_flow_init(flow_name, 3, targets, schema, 0) != DFI_SUCCESS) 26 | { 27 | FAIL() << "TestFlowBarrier::SetUp could not initialize shuffle flow!"; 28 | } 29 | } 30 | 31 | void TestFlowBarrier::TearDown() 32 | { 33 | 34 | } 35 | 36 | 37 | TEST_F(TestFlowBarrier, testSyncThreeSources) 38 | { 39 | DFI_Flow_barrier_init(flow_name); 40 | 41 | bool firstSourceArrived = false; 42 | bool secondSourceArrived = false; 43 | bool thirdSourceArrived = false; 44 | 45 | std::thread source_thread1([&]() { 46 | DFI_Flow_barrier barrier(flow_name); 47 | firstSourceArrived = true; 48 | barrier.arriveWaitSources(); 49 | 50 | ASSERT_TRUE(secondSourceArrived); 51 | ASSERT_TRUE(thirdSourceArrived); 52 | }); 53 | 54 | std::thread source_thread2([&]() { 55 | DFI_Flow_barrier barrier(flow_name); 56 | thirdSourceArrived = true; 57 | barrier.arriveWaitSources(); 58 | 59 | ASSERT_TRUE(firstSourceArrived); 60 | ASSERT_TRUE(thirdSourceArrived); 61 | }); 62 | 63 | usleep(100000); 64 | DFI_Flow_barrier barrier(flow_name); 65 | secondSourceArrived = true; 66 | 67 | barrier.arriveWaitSources(); 68 | ASSERT_TRUE(firstSourceArrived); 69 | ASSERT_TRUE(secondSourceArrived); 70 | 71 | source_thread1.join(); 72 | source_thread2.join(); 73 | std::cout << "joining" << std::endl; 74 | } 75 | 76 | TEST_F(TestFlowBarrier, testSyncTwoTargets) 77 | { 78 | DFI_Flow_barrier_init(flow_name); 79 | 80 | bool firstTargetArrived = false; 81 | bool secondTargetArrived = false; 82 | 83 | std::thread target_thread1([&]() { 84 | DFI_Flow_barrier barrier(flow_name); 85 | firstTargetArrived = true; 86 | barrier.arriveWaitTargets(); 87 | 88 | ASSERT_TRUE(secondTargetArrived); 89 | }); 90 | 91 | usleep(100000); 92 | DFI_Flow_barrier barrier(flow_name); 93 | secondTargetArrived = true; 94 | 95 | barrier.arriveWaitTargets(); 96 | ASSERT_TRUE(firstTargetArrived); 97 | 98 | target_thread1.join(); 99 | } -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/Settings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../utils/Config.h" 3 | #include 4 | 5 | #define RAND_RANGE(N) (((double) rand() / ((double) RAND_MAX + 1)) * (N)) 6 | 7 | 8 | #define USE_COMPRESSION 9 | 10 | //#define USE_MULTICAST 11 | 12 | struct Tuple_t 13 | { 14 | uint64_t key; 15 | uint64_t value; 16 | Tuple_t() {}; 17 | Tuple_t(uint64_t key, uint64_t value) : key(key), value(value) {}; 18 | }; 19 | 20 | union CompressedTuple_t { 21 | uint64_t data; 22 | 23 | struct { 24 | uint32_t key; 25 | uint32_t value; 26 | }; 27 | 28 | CompressedTuple_t() {}; 29 | // CompressedTuple_t(uint64_t key, uint64_t value) : key(key), value(value) {}; 30 | CompressedTuple_t(uint64_t key, uint64_t value) : data(key<<32 | value) {}; 31 | }; 32 | 33 | struct Settings 34 | { 35 | static const string LEFT_REL_FLOW_NAME; 36 | static const string RIGHT_REL_FLOW_NAME; 37 | 38 | static uint64_t LEFT_REL_FULL_SIZE; 39 | static uint64_t RIGHT_REL_FULL_SIZE; 40 | 41 | static uint64_t LEFT_REL_SIZE; 42 | static uint64_t RIGHT_REL_SIZE; 43 | 44 | static uint32_t NODE_ID; 45 | static uint32_t NODES_TOTAL; 46 | 47 | static uint32_t PART_THREADS_COUNT; 48 | static uint32_t TOTAL_THREADS_COUNT; 49 | 50 | static uint32_t TUPLE_SEND_COUNT; 51 | 52 | static bool RANDOM_ORDER; 53 | 54 | static const uint64_t LOCAL_PARTITION_BITS = 9; //LOCAL PARTITIONS PER NETWORK PARTITION. Total partition count = PARTITION_COUNT * LOCAL_PARTITION_COUNT 55 | 56 | static const uint64_t LOCAL_PARTITION_COUNT = (1 << LOCAL_PARTITION_BITS); //LOCAL PARTITIONS PER NETWORK PARTITION. Total partition count = PARTITION_COUNT * LOCAL_PARTITION_COUNT 57 | 58 | static const uint32_t CACHELINE_SIZE = 64; 59 | 60 | static const uint32_t PAYLOAD_BITS = 27; 61 | }; 62 | 63 | 64 | #define TOTAL_PARTITION_COUNT (1ul << Settings::LOCAL_PARTITION_BITS) 65 | 66 | // #define TUPLES_PER_CACHELINE (Settings::CACHELINE_SIZE / sizeof(Tuple_t)) 67 | #define COMPRESSED_TUPLES_PER_CACHELINE (Settings::CACHELINE_SIZE / sizeof(CompressedTuple_t)) 68 | 69 | #define TUPLES_PER_CACHELINE (Settings::CACHELINE_SIZE / sizeof(Tuple_t)) 70 | 71 | 72 | /* RADIX STUFF */ 73 | #define HASH_BIT_MODULO(K, MASK, NBITS) (((K) & (MASK)) >> NBITS) //Shifting the network bits, causes the network partitioning to start by filling one partition at a time, meaning remote writes will be spread out 74 | 75 | #define NEXT_POW_2(V) \ 76 | do \ 77 | { \ 78 | V--; \ 79 | V |= V >> 1; \ 80 | V |= V >> 2; \ 81 | V |= V >> 4; \ 82 | V |= V >> 8; \ 83 | V |= V >> 16; \ 84 | V++; \ 85 | } while (0) 86 | 87 | 88 | static inline long long get_time_diff(timeval& tv_start, timeval& tv_end) { 89 | long long start_us = (tv_start.tv_sec % 86400) * 1000000 90 | + tv_start.tv_usec; 91 | long long end_us = (tv_end.tv_sec % 86400) * 1000000 + tv_end.tv_usec; 92 | return (end_us - start_us); 93 | }; -------------------------------------------------------------------------------- /src/use-cases/distributed-radix-join-flow/LocalPartitioner.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Relation.h" 4 | #include "Settings.h" 5 | #include "Partition.h" 6 | #include "LocalPartitionerThread.h" 7 | 8 | class LocalPartitioner 9 | { 10 | public: 11 | LocalPartitioner(Relation::Type relation_type); 12 | ~LocalPartitioner(); 13 | void partition(); 14 | void join(); 15 | PartitionHolder **get_end_partitions() { 16 | return end_partitions.data(); 17 | }; 18 | 19 | private: 20 | std::vector partitioner_threads; 21 | std::vector end_partitions; 22 | vector node_partitions; 23 | }; 24 | 25 | 26 | LocalPartitioner::LocalPartitioner(Relation::Type relation_type) 27 | { 28 | size_t end_partition_tuples = 1.5 * ((relation_type == Relation::Type::LEFT) ? Settings::LEFT_REL_FULL_SIZE : Settings::RIGHT_REL_FULL_SIZE) / TOTAL_PARTITION_COUNT; 29 | 30 | node_partitions = Settings::get_partitions(Settings::NODE_ID, Settings::NETWORK_PARTITION_COUNT); 31 | std::cout << "Creating " << node_partitions.size() << " LocalPartitionerThreads. " << end_partition_tuples << std::endl; 32 | partitioner_threads.reserve(node_partitions.size()); 33 | end_partitions.reserve(node_partitions.size()); 34 | for(size_t i = 0; i < node_partitions.size(); i++) 35 | { 36 | PartitionHolder *partition_holder = new PartitionHolder{end_partition_tuples}; 37 | end_partitions.push_back(partition_holder); 38 | 39 | partitioner_threads.push_back(new LocalPartitionerThread(node_partitions[i], relation_type, partition_holder)); 40 | } 41 | } 42 | 43 | LocalPartitioner::~LocalPartitioner() 44 | { 45 | for(size_t i = 0; i < node_partitions.size(); i++) 46 | { 47 | delete partitioner_threads[i]; 48 | delete end_partitions[i]; 49 | } 50 | } 51 | 52 | void LocalPartitioner::partition() 53 | { 54 | for (auto &thread : partitioner_threads) { 55 | thread->start(); 56 | } 57 | } 58 | 59 | void LocalPartitioner::join() 60 | { 61 | size_t processed_tuples = 0; 62 | 63 | long long avg_exec_time = 0; 64 | long long longest_exec_time = 0; 65 | for (auto &thread : partitioner_threads) { 66 | thread->join(); 67 | processed_tuples += thread->get_processed_tuples(); 68 | // std::cout << "Local partitioner for network partition " << node_partitions[i] << " processed " << thread->get_processed_tuples() << " tuples." << '\n'; 69 | // std::cout << "(" << thread->execution_part_time << " " << thread->execution_time << " " << thread->get_processed_tuples()/1000 << ") "; 70 | avg_exec_time += thread->execution_part_time + thread->execution_time; 71 | if (thread->execution_part_time > longest_exec_time) 72 | longest_exec_time = thread->execution_part_time; 73 | } 74 | std::cout << "Local Partitioner processed total " << processed_tuples << " tuples." << '\n'; 75 | std::cout << "Average execution time: " << avg_exec_time/node_partitions.size()/1000 << " ms. Longest: " << longest_exec_time/1000 << " ms" << '\n'; 76 | } -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/LocalDFIPartitionerThread.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file LocalDFIPartitionerThread.h 3 | * @author Lasse Thostrup 4 | * @brief Adaption of Claude Barthels' MPI join from https://www.systems.ethz.ch/node/334 5 | * Paper: http://www.vldb.org/pvldb/vol10/p517-barthels.pdf 6 | * @date 2020-06-09 7 | * 8 | */ 9 | 10 | #pragma once 11 | #include "Settings.h" 12 | #include "Relation.h" 13 | #include "../../flow-api/dfi.h" 14 | #include "utils/Thread.h" 15 | #include 16 | #include 17 | 18 | 19 | class LocalDFIPartitionerThread : public utils::Thread 20 | { 21 | 22 | public: 23 | LocalDFIPartitionerThread(std::string flow_name, TargetID target_id, Relation::Type relation_type, PartitionHolder *local_partitions); 24 | void run(); 25 | size_t get_processed_tuples() { return processed_tuples; }; 26 | long long execution_time = 0; 27 | long long execution_part_time = 0; 28 | private: 29 | DFI_Replicate_flow_target flow_target; 30 | size_t processed_tuples = 0; 31 | 32 | PartitionHolder *local_partitions; 33 | }; 34 | 35 | LocalDFIPartitionerThread::LocalDFIPartitionerThread(std::string flow_name, TargetID target_id, Relation::Type, PartitionHolder *local_partitions) : 36 | flow_target(flow_name, target_id), local_partitions(local_partitions) 37 | { 38 | } 39 | 40 | //NOTE: Partitioning code partly taken from Claude Barthels' MPI join from https://www.systems.ethz.ch/node/334 41 | void LocalDFIPartitionerThread::run() { 42 | struct timeval tv_start; 43 | struct timeval tv_end; 44 | 45 | gettimeofday(&tv_start, NULL); 46 | 47 | constexpr auto MASK = Settings::LOCAL_PARTITION_COUNT - 1; 48 | cacheline_t cacheline_buffer[Settings::LOCAL_PARTITION_COUNT] __attribute__((aligned(Settings::CACHELINE_SIZE))); 49 | 50 | dfi::Tuple dfi_tuple; 51 | size_t tuple_count = 0; 52 | while(flow_target.consume(dfi_tuple, tuple_count) != DFI_FLOW_FINISHED) { 53 | #ifdef USE_COMPRESSION 54 | CompressedTuple_t* tuple = (CompressedTuple_t*) dfi_tuple.getDataPtr(); 55 | #else 56 | Tuple_t* tuple = (Tuple_t*) dfi_tuple.getDataPtr(); 57 | #endif 58 | 59 | for(size_t i = 0; i < tuple_count; ++i) { 60 | uint32_t partition_id = tuple[i].key & MASK; 61 | 62 | cacheline_t *cacheline = cacheline_buffer + partition_id; 63 | bool is_full = cacheline->add_tuple(tuple[i]); 64 | 65 | if (is_full) { 66 | local_partitions->partitions[partition_id]->add_cacheline(cacheline); 67 | cacheline->clear(); 68 | } 69 | 70 | ++processed_tuples; 71 | } 72 | } 73 | 74 | 75 | for (uint32_t i = 0; i < Settings::LOCAL_PARTITION_COUNT; ++i) { 76 | cacheline_t *cacheline = cacheline_buffer + i; 77 | if (cacheline->size() > 0) { 78 | local_partitions->partitions[i]->add_cacheline(cacheline, cacheline->size()); 79 | } 80 | } 81 | 82 | 83 | gettimeofday(&tv_end, NULL); 84 | execution_part_time = get_time_diff(tv_start, tv_end); 85 | } -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/Partition.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Settings.h" 8 | 9 | #ifdef USE_COMPRESSION 10 | #define Tuple_t CompressedTuple_t 11 | #endif 12 | 13 | #define TUPLES_PER_CACHELINE (Settings::CACHELINE_SIZE / sizeof(Tuple_t)) 14 | 15 | 16 | union cacheline_t { 17 | cacheline_t() { 18 | data.size = 0; 19 | }; 20 | 21 | struct { 22 | Tuple_t tuples[TUPLES_PER_CACHELINE]; 23 | } tuples; 24 | 25 | struct { 26 | Tuple_t tuples[TUPLES_PER_CACHELINE - 1]; 27 | uint32_t size; 28 | } data; 29 | 30 | inline bool add_tuple(Tuple_t &tuple) { // return true if full after adding 31 | uint32_t size_before = data.size++; 32 | tuples.tuples[size_before] = tuple; 33 | return (size_before == TUPLES_PER_CACHELINE - 1); 34 | } 35 | 36 | inline void clear() { 37 | data.size = 0; 38 | } 39 | 40 | inline uint32_t size() { 41 | return data.size; 42 | } 43 | }; 44 | 45 | 46 | 47 | struct Partition { 48 | Partition(size_t max_tuples): max_tuples(max_tuples) { 49 | tuples = reinterpret_cast(aligned_alloc(64, max_tuples*sizeof(Tuple_t))); 50 | std::fill_n(tuples, max_tuples, Tuple_t{1,1}); 51 | } 52 | 53 | inline void add_cacheline(const cacheline_t *cacheline) { 54 | __m512i *dest = (__m512i *) &tuples[size]; 55 | __m512i src = *((__m512i *) cacheline); 56 | 57 | _mm512_stream_si512(dest, src); 58 | size += TUPLES_PER_CACHELINE; 59 | 60 | #ifdef DEBUG 61 | if (size > max_tuples) { 62 | std::cout << "size: " << size << " max tuples: " << max_tuples << std::endl; 63 | throw std::runtime_error("partition overflow!"); 64 | } 65 | #endif 66 | } 67 | 68 | inline void add_cacheline(const cacheline_t *cacheline, const size_t num_tuples) { 69 | __m512i *dest = (__m512i *) &tuples[size]; 70 | __m512i src = *((__m512i *) cacheline); 71 | 72 | _mm512_stream_si512(dest, src); 73 | size += num_tuples; 74 | 75 | #ifdef DEBUG 76 | if (size > max_tuples) { 77 | std::cout << "add partion cacheline: size: " << size << " max tuples: " << max_tuples << std::endl; 78 | throw std::runtime_error("partition overflow!"); 79 | } 80 | #endif 81 | } 82 | 83 | const size_t max_tuples; 84 | size_t size = 0; 85 | Tuple_t *tuples; 86 | }; 87 | 88 | 89 | struct PartitionHolder { 90 | PartitionHolder(size_t partition_size) { 91 | for (auto &partition : partitions) { 92 | partition = new Partition{partition_size}; 93 | } 94 | } 95 | 96 | ~PartitionHolder() { 97 | for (auto &partition : partitions) { 98 | delete partition; 99 | } 100 | } 101 | 102 | std::array partitions; 103 | }; 104 | 105 | #ifdef Tuple_t 106 | #undef Tuple_t 107 | #endif -------------------------------------------------------------------------------- /src/gtest/memory/TestRegistryClient.cc: -------------------------------------------------------------------------------- 1 | #include "TestRegistryClient.h" 2 | 3 | void TestRegistryClient::SetUp() 4 | { 5 | rdma::Config::RDMA_MEMSIZE = 1024ul * 1024 * 1; //1MB 6 | Config::DFI_FULL_SEGMENT_SIZE = (2048 + sizeof(DFI_SEGMENT_FOOTER_t)); 7 | Config::DFI_SOURCE_SEGMENT_COUNT = 8; 8 | Config::DFI_REGISTRY_SERVER = rdma::Config::getIP(rdma::Config::RDMA_INTERFACE); 9 | rdma::Config::SEQUENCER_IP = rdma::Config::getIP(rdma::Config::RDMA_INTERFACE); 10 | Config::DFI_NODES.clear(); 11 | string dfiTestNode = rdma::Config::getIP(rdma::Config::RDMA_INTERFACE) + ":" + to_string(Config::DFI_NODE_PORT); 12 | Config::DFI_NODES.push_back(dfiTestNode); 13 | m_regServer = new RegistryServer(); 14 | std::cout << "Start RegServer" << '\n'; 15 | m_nodeServer = new NodeServer(); 16 | std::cout << "Start NodeServer" << '\n'; 17 | 18 | m_regClient = new RegistryClient(); 19 | std::cout << "Start RegClient" << '\n'; 20 | } 21 | 22 | void TestRegistryClient::TearDown() 23 | { 24 | if (m_regServer != nullptr) 25 | { 26 | m_regServer->stopServer(); 27 | delete m_regServer; 28 | m_regServer = nullptr; 29 | } 30 | if (m_nodeServer != nullptr) 31 | { 32 | m_nodeServer->stopServer(); 33 | delete m_nodeServer; 34 | m_nodeServer = nullptr; 35 | } 36 | if (m_regClient != nullptr) 37 | { 38 | delete m_regClient; 39 | m_regClient = nullptr; 40 | } 41 | } 42 | 43 | TEST_F(TestRegistryClient, testRetrieveBuffer) 44 | { 45 | string name = "buffer2"; 46 | ASSERT_TRUE(m_regClient->registerBuffer(new BufferHandle(name, 1, 1, 2, 1024))); 47 | 48 | auto buffHandle = m_regClient->retrieveBuffer(name); 49 | ASSERT_TRUE(buffHandle != nullptr); 50 | ASSERT_EQ(buffHandle->name, name); 51 | 52 | ASSERT_EQ(2, ((int)buffHandle->entrySegments.size())); 53 | }; 54 | 55 | TEST_F(TestRegistryClient, testRegisterBuffer) 56 | { 57 | string name = "buffer1"; 58 | BufferHandle *buffHandle = new BufferHandle(name, 1, 1, 2, Config::DFI_FULL_SEGMENT_SIZE - sizeof(DFI_SEGMENT_FOOTER_t)); 59 | ASSERT_TRUE(m_regClient->registerBuffer(buffHandle)); 60 | 61 | std::unique_ptr handle_ret = m_regClient->retrieveBuffer(name); 62 | ASSERT_TRUE(handle_ret != nullptr); 63 | ASSERT_EQ(handle_ret->name, name); 64 | ASSERT_EQ(2, ((int)handle_ret->entrySegments.size())); 65 | }; 66 | 67 | TEST_F(TestRegistryClient, testJoinBuffer) 68 | { 69 | string name = "buffer1"; 70 | BufferHandle *buffHandle = new BufferHandle(name, 1, 1, 2, Config::DFI_FULL_SEGMENT_SIZE - sizeof(DFI_SEGMENT_FOOTER_t)); 71 | ASSERT_TRUE(m_regClient->registerBuffer(buffHandle)); 72 | { 73 | auto handle_ret = m_regClient->sourceJoinBuffer(name); 74 | ASSERT_TRUE(handle_ret != nullptr); 75 | ASSERT_EQ(handle_ret->name, name); 76 | ASSERT_EQ(1, ((int)handle_ret->entrySegments.size())); 77 | ASSERT_EQ(1, ((int)handle_ret->node_id)); 78 | } 79 | { 80 | auto handle_ret = m_regClient->sourceJoinBuffer(name); 81 | ASSERT_TRUE(handle_ret != nullptr); 82 | ASSERT_EQ(handle_ret->name, name); 83 | ASSERT_EQ(1, ((int)handle_ret->entrySegments.size())); 84 | ASSERT_EQ(1, ((int)handle_ret->node_id)); 85 | } 86 | 87 | }; 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DFI: The Data Flow Interface for High-Speed Networks 2 | ## Paper Abstract 3 | In this paper, we propose the Data Flow Interface (DFI) as a way to 4 | make it easier for data-processing systems to exploit high-speed 5 | networks without the need to deal with the complexity of RDMA. 6 | By lifting the level of abstraction, DFI factors out much of the 7 | complexity of network communication and makes it easier for 8 | developers to declaratively express how data should be efficiently 9 | routed to accomplish a given distributed data processing task. As 10 | we show in our experiment, DFI is able to support a wide variety of 11 | data-centric applications with high performance at a low complexity 12 | for the applications. 13 | 14 | Link: https://doi.org/10.1145/3448016.3452816 15 | 16 | ## Cloning repository 17 | The DFI repository includes another repository (rdma-manager) as a submodule. Therefore, after cloning the repository run: 18 | ``` 19 | git submodule init 20 | git submodule update 21 | ``` 22 | 23 | ## Dependencies 24 | RDMA capable NIC (tested with ConnectX-5) 25 | Mellanox OFED (tested with 5.1) 26 | Protobuf (tested with 3.10.1) 27 | ZeroMQ (tested with 4.2.5-1) 28 | GNU Make (tested with 4.1) 29 | CMake (tested with 3.10) 30 | 31 | ## Examples 32 | Examples can be found in the `src/gtest/examples/` folder. 33 | 34 | Simple example of a shuffle flow: 35 | ```cpp 36 | //Registry and node setup 37 | RegistryServer registry; 38 | DFI_Node node1(5400); 39 | DFI_Node node2(5401); 40 | 41 | //Flow initialization 42 | std::string flow_name = "Shuffle-example"; 43 | size_t source_count = 1; 44 | std::vector targets{{1,1}, {2,2}}; // target id 1 --> node1 && target id 2 --> node 2 45 | DFI_Schema schema({{"key", TypeId::INT},{"value", TypeId::INT}}); 46 | DFI_Shuffle_flow_init(flow_name, source_count, targets, schema, 0); 47 | 48 | //Flow execution 49 | DFI_Shuffle_flow_source source(flow_name); 50 | DFI_Shuffle_flow_target target1(flow_name, 1); 51 | DFI_Shuffle_flow_target target2(flow_name, 2); 52 | 53 | std::pair data; 54 | data = {3,10}; 55 | source.push(&data); 56 | data = {8,20}; 57 | source.push(&data); 58 | source.close(); 59 | 60 | dfi::Tuple tuple1; 61 | target1.consume(tuple1); 62 | 63 | dfi::Tuple tuple2; 64 | target2.consume(tuple2); 65 | 66 | std::cout << "Target 1 got tuple (" << tuple1.getAs("key") << "," << tuple1.getAs("value") << ")" << std::endl; 67 | std::cout << "Target 2 got tuple (" << tuple2.getAs("key") << "," << tuple2.getAs("value") << ")" << std::endl; 68 | ``` 69 | 70 | ## DFI Use cases 71 | Examples of distributed use cases can be found in src/use-cases/ 72 | 73 | Use the distributed experiment runner for easily running use-cases: https://github.com/mjasny/distexprunner 74 | 75 | ## Installation: 76 | DFI can optionally be installed, however for development git submodule is recommended. 77 | Install the shared library after compilation with 'make install'. 78 | By default, files are installed at /usr/local/. 79 | This can by changed by setting CMAKE_INSTALL_PREFIX when running cmake. 80 | 81 | Usage: 82 | When compiling external code that uses DFI, link it with -ldfi. 83 | To include DFI: `#include ` 84 | -------------------------------------------------------------------------------- /src/use-cases/distributed-radix-join-flow/NetworkPartitionerThread.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file NetworkPartitionerThread.h 3 | * @author Lasse Thostrup 4 | * @brief Adaption of Claude Barthels' MPI join from https://www.systems.ethz.ch/node/334 5 | * Paper: http://www.vldb.org/pvldb/vol10/p517-barthels.pdf 6 | * @date 2020-06-09 7 | * 8 | */ 9 | 10 | #pragma once 11 | #include 12 | #include "Settings.h" 13 | #include "Relation.h" 14 | #include "Partition.h" 15 | #include "../../flow-api/dfi.h" 16 | #include "utils/Thread.h" 17 | 18 | 19 | 20 | class NetworkPartitionerThread : public utils::Thread 21 | { 22 | public: 23 | NetworkPartitionerThread(Relation &relation, size_t from, size_t to); 24 | void run(); 25 | size_t get_processed_tuples() { return processed_tuples; }; 26 | static TargetID distribution_function(const Tuple &tuple); 27 | private: 28 | Relation &relation; 29 | DFI_Shuffle_flow_source flow_source; 30 | size_t from; 31 | size_t to; 32 | size_t processed_tuples = 0; 33 | }; 34 | 35 | NetworkPartitionerThread::NetworkPartitionerThread(Relation &relation, size_t from, size_t to) : relation(relation), 36 | flow_source((relation.get_type() == Relation::Type::LEFT) ? Settings::LEFT_REL_FLOW_NAME : Settings::RIGHT_REL_FLOW_NAME, dfi::Config::DFI_SOURCE_SEGMENT_COUNT, true), 37 | from(from), to(to) 38 | { 39 | } 40 | 41 | TargetID NetworkPartitionerThread::distribution_function(const Tuple &tuple) 42 | { 43 | return ((*reinterpret_cast(tuple.getDataPtr()))&(Settings::NETWORK_PARTITION_COUNT-1)); 44 | } 45 | 46 | //NOTE: Partitioning code taken from Claude Barthels' MPI join from https://www.systems.ethz.ch/node/334 47 | void NetworkPartitionerThread::run() 48 | { 49 | #ifdef COMPRESSED_TUPLES 50 | const uint32_t partitionBits = Settings::NETWORK_PARTITION_BITS; 51 | #endif 52 | 53 | cacheline_t cacheline_buffer[Settings::NETWORK_PARTITION_COUNT] __attribute__((aligned(Settings::CACHELINE_SIZE))); 54 | 55 | for(size_t i = from; i <= to; ++i) 56 | { 57 | // Compute partition 58 | uint32_t partition_id = HASH_BIT_MODULO(relation.get_tuple(i)->key, Settings::NETWORK_PARTITION_COUNT - 1, 0); 59 | cacheline_t *cacheline = cacheline_buffer + partition_id; 60 | #ifdef COMPRESSED_TUPLES 61 | CompressedTuple_t tuple{relation.get_tuple(i)->value + ((relation.get_tuple(i)->key >> partitionBits) << (partitionBits + Settings::PAYLOAD_BITS))}; 62 | #else 63 | Tuple_t tuple{relation.get_tuple(i)->key, relation.get_tuple(i)->value}; 64 | #endif 65 | bool is_full = cacheline->add_tuple(tuple); 66 | 67 | if (is_full) { 68 | flow_source.pushCacheLineNonTemp(cacheline, partition_id); 69 | cacheline->clear(); 70 | } 71 | 72 | ++processed_tuples; 73 | } 74 | 75 | // Flush remaining elements to memory buffers 76 | for (uint32_t i = 0; i < Settings::NETWORK_PARTITION_COUNT; ++i) { 77 | cacheline_t *cacheline = cacheline_buffer + i; 78 | if (cacheline->size() > 0) { 79 | flow_source.pushBulk(cacheline, i, cacheline->size()); 80 | } 81 | } 82 | 83 | flow_source.close(); 84 | } -------------------------------------------------------------------------------- /src/gtest/examples/combiner_flow_examples.cc: -------------------------------------------------------------------------------- 1 | #include "combiner_flow_examples.h" 2 | 3 | void CombinerFlowExamples::SetUp() 4 | { 5 | //Setup Test DFI 6 | rdma::Config::RDMA_MEMSIZE = 1024ul * 1024 * 8; //128MB 7 | Config::DFI_FULL_SEGMENT_SIZE = (2048 + sizeof(DFI_SEGMENT_FOOTER_t)); 8 | Config::DFI_SEGMENTS_PER_RING = 12; 9 | Config::DFI_SOURCE_SEGMENT_COUNT = 8; 10 | Config::DFI_REGISTRY_SERVER = rdma::Config::getIP(rdma::Config::RDMA_INTERFACE); 11 | Config::DFI_REGISTRY_PORT = 5300; 12 | rdma::Config::SEQUENCER_IP = rdma::Config::getIP(rdma::Config::RDMA_INTERFACE); 13 | 14 | uint16_t serverPort = 5401; 15 | Config::DFI_NODES = {rdma::Config::getIP(rdma::Config::RDMA_INTERFACE) + ":" + to_string(serverPort)}; 16 | 17 | m_regServer = std::make_unique(); 18 | m_nodeServer = std::make_unique(serverPort); 19 | } 20 | 21 | void CombinerFlowExamples::TearDown() 22 | { 23 | 24 | } 25 | 26 | TEST_F(CombinerFlowExamples, simpleBigTupleCombiner) 27 | { 28 | string flow_name = "Simple Big Tuple Combiner Flow"; 29 | 30 | const int attr_count = 128; 31 | // ------- MASTER ------- 32 | std::vector> schema_vec; 33 | for (int i = 0; i < attr_count; i++) 34 | { 35 | schema_vec.push_back({"attr" + to_string(i), dfi::TypeId::BIGUINT}); 36 | } 37 | // ------- Flow Source 1 ------- 38 | uint64_t data1[attr_count]; 39 | uint64_t data2[attr_count]; 40 | for (uint64_t i = 0; i < attr_count; i++) 41 | { 42 | data1[i] = i; 43 | data2[i] = i + attr_count; 44 | } 45 | 46 | // ------- MASTER ------- 47 | size_t sources_count = 2; 48 | DFI_Combiner_flow_init(flow_name, sources_count, {{1, 1}}, schema_vec, AggrFunc::SUM, DFI_Combiner_flow_optimization::Bandwidth); 49 | 50 | // ------- Flow Source 1 ------- 51 | std::thread source_thread1([flow_name, &data1]() { 52 | std::cout << "Creating Flow Source 1" << '\n'; 53 | DFI_Combiner_flow_source *source = new DFI_Combiner_flow_source(flow_name, 8); 54 | source->push(data1); 55 | delete source; 56 | }); 57 | 58 | // ------- Flow Source 2 ------- 59 | std::thread source_thread2([flow_name, &data2]() { 60 | std::cout << "Creating Flow Source 2" << '\n'; 61 | DFI_Combiner_flow_source *source = new DFI_Combiner_flow_source(flow_name, 8); 62 | source->push(data2); 63 | delete source; 64 | }); 65 | 66 | // ------- Flow Target 1 ------- 67 | std::thread target_thread([flow_name, attr_count, &data1, &data2]() { 68 | std::cout << "Creating Flow Target 1" << '\n'; 69 | DFI_Combiner_flow_target target(flow_name, 1); 70 | 71 | dfi::Tuple tuple = target.create_tuple(); 72 | size_t tuplesConsumed = 0; 73 | int msg; 74 | while ((msg = target.consume(tuple, 4, tuplesConsumed)) != DFI_FLOW_FINISHED) 75 | { 76 | ASSERT_EQ((size_t)2, tuplesConsumed); 77 | for (int i = 0; i < attr_count; i++) 78 | { 79 | ASSERT_EQ(data1[i] + data2[i], *(uint64_t *)tuple.getDataPtr(i)); 80 | } 81 | } 82 | }); 83 | 84 | source_thread1.join(); 85 | source_thread2.join(); 86 | target_thread.join(); 87 | } -------------------------------------------------------------------------------- /src/dfi/flow/FlowSourceLat.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "FlowSourceInterface.h" 4 | #include "../memory/BufferWriter.h" 5 | 6 | namespace dfi 7 | { 8 | 9 | class FlowSourceLat final : public FlowSourceInterface { 10 | std::vector> m_bufferWriters; 11 | public: 12 | FlowSourceLat(FlowHandle flowHandle, size_t sourceSegmentCount = Config::DFI_SOURCE_SEGMENT_COUNT) : 13 | FlowSourceInterface(flowHandle) { 14 | 15 | if (m_flowHandle.optimization != FlowOptimization::LAT) { 16 | throw new invalid_argument("FlowSourceBW ctor: FlowOptimization not Latency (FlowOptimization::LAT)"); 17 | } 18 | 19 | const size_t totalNodeSize = (sourceSegmentCount * (flowHandle.segmentSizes + sizeof(DFI_SEGMENT_FOOTER_t))) * m_flowHandle.targets.size() + (m_flowHandle.targets.size() * (sizeof(DFI_SEGMENT_FOOTER_t) + Config::CACHELINE_SIZE + sizeof(uint64_t))); 20 | 21 | auto nodeClient = std::make_shared(totalNodeSize); 22 | 23 | const TargetID maxTargetId = std::max_element(m_flowHandle.targets.begin(), m_flowHandle.targets.end())->targetId; 24 | m_bufferWriters.resize(maxTargetId + 1); 25 | 26 | for (auto target : m_flowHandle.targets) 27 | { 28 | auto bufferName = Config::getBufferName(m_flowHandle.name, target.targetId); 29 | 30 | Logging::debug(__FILE__, __LINE__, "FlowSourceBW: Connecting to remote node " + to_string(target.nodeId) + ", and creating BufferWriter"); 31 | nodeClient->connect(Config::getIPFromNodeId(target.nodeId), target.nodeId); 32 | 33 | // Create BufferWriter 34 | m_bufferWriters.emplace(m_bufferWriters.begin() + target.targetId, make_unique(bufferName, m_registryClient, sourceSegmentCount, nodeClient)); 35 | 36 | Logging::debug(__FILE__, __LINE__, "BufferWriter (" + bufferName + ") created for TargetID: " + to_string(target.targetId)); 37 | } 38 | } 39 | 40 | ~FlowSourceLat() { 41 | if (!m_isClosed) { 42 | close(); 43 | } 44 | } 45 | 46 | inline bool push(Tuple const &tuple, TargetID targetId, bool) override 47 | { 48 | auto &bufferWriter = m_bufferWriters[targetId]; 49 | return bufferWriter->add(tuple.getDataPtr(), m_tupleSize); 50 | }; 51 | 52 | inline bool flush(TargetID targetId) override 53 | { 54 | //Nothing to do? -> Yes 55 | (void) targetId; 56 | return true; 57 | }; 58 | 59 | void close() override 60 | { 61 | if (!m_isClosed) { 62 | for (const auto target : m_flowHandle.targets) 63 | { 64 | // std::cout << "Closing target " << target.targetId << std::endl; 65 | Logging::debug(__FILE__, __LINE__, "Closing BufferWriter on TargetID: " + to_string(target.targetId)); 66 | auto &bufferWriter = m_bufferWriters[target.targetId]; 67 | if (!bufferWriter->close()) 68 | { 69 | Logging::error(__FILE__, __LINE__, "Error occured while closing buffer writer for target: " + to_string(target.targetId)); 70 | } 71 | } 72 | } 73 | m_isClosed = true; 74 | } 75 | }; 76 | 77 | 78 | } -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/LocalPartitioner.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Partition.h" 4 | #include "Settings.h" 5 | #include "LocalPartitionerThread.h" 6 | 7 | class LocalPartitioner 8 | { 9 | public: 10 | LocalPartitioner(Relation &relation); 11 | ~LocalPartitioner(); 12 | void start_threads(); 13 | void join_threads(); 14 | PartitionHolder **get_end_partitions() { 15 | return end_partitions.data(); 16 | }; 17 | 18 | private: 19 | Relation &relation; 20 | 21 | std::vector partitioner_threads; 22 | std::vector end_partitions; 23 | }; 24 | 25 | 26 | LocalPartitioner::LocalPartitioner(Relation &relation): relation(relation) 27 | { 28 | size_t end_partition_size = 1.5 * (Settings::RIGHT_REL_FULL_SIZE / Settings::LOCAL_PARTITION_COUNT / Settings::TOTAL_THREADS_COUNT); 29 | std::cout << "end_partition_size: " << end_partition_size << std::endl; 30 | partitioner_threads.reserve(Settings::TOTAL_THREADS_COUNT); 31 | end_partitions.reserve(Settings::TOTAL_THREADS_COUNT); 32 | 33 | for(size_t i = 0; i < Settings::TOTAL_THREADS_COUNT; i++) { 34 | PartitionHolder *partition_holder = new PartitionHolder{end_partition_size}; 35 | end_partitions.push_back(partition_holder); 36 | 37 | size_t from = i * (relation.get_size() / Settings::TOTAL_THREADS_COUNT); 38 | size_t to = (i + 1) * (relation.get_size() / Settings::TOTAL_THREADS_COUNT) - 1; 39 | if (i == Settings::TOTAL_THREADS_COUNT-1) { 40 | to = relation.get_size() - 1; 41 | } 42 | std::cout << "Creating LocalPartitionerThread, range: " << from << " -> " << to << '\n'; 43 | 44 | partitioner_threads.push_back(new LocalPartitionerThread(relation, from, to, partition_holder)); 45 | } 46 | } 47 | 48 | LocalPartitioner::~LocalPartitioner() { 49 | for(size_t i = 0; i < Settings::TOTAL_THREADS_COUNT; i++) { 50 | delete partitioner_threads[i]; 51 | delete end_partitions[i]; 52 | } 53 | } 54 | 55 | void LocalPartitioner::start_threads() { 56 | for (auto &thread : partitioner_threads) { 57 | thread->start(); 58 | } 59 | } 60 | 61 | void LocalPartitioner::join_threads() { 62 | size_t processed_tuples = 0; 63 | 64 | long long avg_exec_time = 0; 65 | long long longest_exec_time = 0; 66 | 67 | for (auto &thread : partitioner_threads) { 68 | thread->join(); 69 | 70 | processed_tuples += thread->get_processed_tuples(); 71 | // std::cout << "Local partitioner for network partition " << node_partitions[i] << " processed " << thread->get_processed_tuples() << " tuples." << '\n'; 72 | // std::cout << "(" << thread->execution_part_time << " " << thread->execution_time << " " << thread->get_processed_tuples()/1000 << ") "; 73 | avg_exec_time += thread->execution_part_time + thread->execution_time; 74 | if (thread->execution_part_time > longest_exec_time) 75 | longest_exec_time = thread->execution_part_time; 76 | } 77 | 78 | 79 | std::cout << "Local Partitioner processed total " << processed_tuples << " tuples." << '\n'; 80 | std::cout << "Average execution time: " << avg_exec_time/partitioner_threads.size()/1000 << " ms. Longest: " << longest_exec_time/1000 << " ms" << '\n'; 81 | } -------------------------------------------------------------------------------- /src/gtest/memory/TestBufferWriterLat.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file TestBufferWriterLat.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2018-08-17 5 | */ 6 | 7 | #pragma once 8 | #include 9 | 10 | #include "../../utils/Config.h" 11 | 12 | #include "../../dfi/memory/NodeServer.h" 13 | #include "../../dfi/memory/NodeClient.h" 14 | #include "../../dfi/registry/RegistryClient.h" 15 | #include "../../dfi/registry/RegistryServer.h" 16 | #include "../../dfi/memory/BufferWriter.h" 17 | #include "../../dfi/memory/BufferWriter.h" 18 | 19 | #include 20 | 21 | class TestBufferWriterLat : public testing::Test { 22 | 23 | public: 24 | void SetUp() override; 25 | void TearDown() override; 26 | 27 | 28 | static std::atomic bar; // Counter of threads, faced barrier. 29 | static std::atomic passed; // Number of barriers, passed by all threads. 30 | static const int NUMBER_THREADS = 2; 31 | 32 | DFI_SEGMENT_FOOTER_t *readSegmentFooter(size_t offset); 33 | DFI_SEGMENT_FOOTER_t *readSegmentFooter(BufferSegment* segment); 34 | 35 | protected: 36 | NodeServer* m_nodeServer; 37 | RegistryClient* m_regClient; 38 | RegistryServer *m_regServer; 39 | 40 | 41 | struct TestData 42 | { 43 | int a; 44 | int b; 45 | int c; 46 | int d; 47 | TestData(int a, int b, int c, int d) : a(a), b(b), c(c), d(d){} 48 | }; 49 | 50 | template 51 | class BufferWriterClient : public rdma::Thread 52 | { 53 | NodeServer* nodeServer = nullptr; 54 | RegistryClient* regClient = nullptr; 55 | BufferHandle* buffHandle = nullptr; 56 | string& buffername = ""; 57 | std::vector *dataToWrite = nullptr; //tuple 58 | 59 | public: 60 | 61 | BufferWriterClient(NodeServer* nodeServer, string& bufferName, std::vector *dataToWrite) : 62 | Thread(), nodeServer(nodeServer), buffername(bufferName), dataToWrite(dataToWrite) {} 63 | 64 | void run() 65 | { 66 | //ARRANGE 67 | 68 | RegistryClient registry_client; 69 | BufferWriter buffWriter(buffername, registry_client, Config::DFI_SOURCE_SEGMENT_COUNT); 70 | 71 | barrier_wait(); 72 | 73 | //ACT 74 | for(size_t i = 0; i < dataToWrite->size(); i++) 75 | { 76 | buffWriter.add(&dataToWrite->operator[](i), sizeof(DataType)); 77 | } 78 | 79 | buffWriter.close(); 80 | } 81 | 82 | void barrier_wait() 83 | { 84 | // std::cout << "Enter Barrier" << '\n'; 85 | int passed_old = passed.load(std::memory_order_relaxed); 86 | 87 | if (bar.fetch_add(1) == (NUMBER_THREADS - 1)) 88 | { 89 | // The last thread, faced barrier. 90 | bar = 0; 91 | // Synchronize and store in one operation. 92 | passed.store(passed_old + 1, std::memory_order_release); 93 | } 94 | else 95 | { 96 | // Not the last thread. Wait others. 97 | while (passed.load(std::memory_order_relaxed) == passed_old) 98 | { 99 | }; 100 | // Need to synchronize cache with other threads, passed barrier. 101 | std::atomic_thread_fence(std::memory_order_acquire); 102 | } 103 | } 104 | }; 105 | 106 | }; 107 | -------------------------------------------------------------------------------- /src/dfi/flow/FlowSourceInterface.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../utils/Config.h" 4 | #include "FlowHandle.h" 5 | #include "../type/Schema.h" 6 | #include "../type/Value.h" 7 | #include "../type/Tuple.h" 8 | #include 9 | #include 10 | #include "../registry/RegistryClient.h" 11 | #include "../memory/NodeClient.h" 12 | 13 | //Setting this flag will optimize the inject method to do non-temporal stores of cache-line size. 14 | //Better performance is only achieved if fan-out is big (i.e., many partitions), and if tuples are small (more tuples fit into cacheline) 15 | //WARNING: - only enable if the cacheline size is divisible by the size of a tuple 16 | // - sendTuplesCount * size of tuple is divisible by size of cacheline. 17 | // - AVX needs to be enabled 18 | // - FLOWSOURCE_CACHE_LINE_SIZE must be sat! 19 | // #define FLOWSOURCE_NONTEMP_CACHELINE_STORES_OPTIMIZATION 20 | #define FLOWSOURCE_CACHE_LINE_SIZE 64 21 | 22 | 23 | #ifdef FLOWSOURCE_NONTEMP_CACHELINE_STORES_OPTIMIZATION 24 | #include 25 | #endif 26 | 27 | namespace dfi 28 | { 29 | 30 | 31 | class FlowSourceInterface { 32 | protected: 33 | FlowHandle m_flowHandle; 34 | RegistryClient m_registryClient; 35 | const size_t m_tupleSize = 0; 36 | bool m_isClosed = false; 37 | public: 38 | FlowSourceInterface(FlowHandle flowHandle) : m_flowHandle{flowHandle}, m_tupleSize{m_flowHandle.schema.getTupleSize()} 39 | { 40 | if (m_flowHandle.targets.empty()) { 41 | throw invalid_argument("Passed flow-handle does not contain any targets!"); 42 | } 43 | 44 | if (m_tupleSize == 0) { 45 | throw invalid_argument("Passed flow-handle has invalid tuple size of 0!"); 46 | } 47 | 48 | Logging::debug(__FILE__, __LINE__, "Creating FlowSource, target size: " + to_string(m_flowHandle.targets.size())); 49 | } 50 | 51 | virtual ~FlowSourceInterface() = default; 52 | 53 | virtual bool push(Tuple const &tuple, TargetID targetId, bool forceSignaled=false) = 0; 54 | 55 | virtual bool pushBulk(void *, TargetID, size_t, bool) 56 | { 57 | throw new runtime_error("pushBulk functionality is not supported for specified Optimization"); 58 | } 59 | virtual bool pushCacheLineNonTemp(void *, TargetID, bool) 60 | { 61 | throw new runtime_error("pushBulk functionality is not supported for specified Optimization"); 62 | } 63 | 64 | virtual bool pushToAll(Tuple const &tuple, bool forceSignaled=false) { 65 | bool success = true; 66 | for (const auto &target : m_flowHandle.targets) 67 | { 68 | success &= push(tuple, target.targetId, forceSignaled); 69 | } 70 | return success; 71 | } 72 | virtual void close() = 0; 73 | 74 | virtual bool flush(TargetID targetId) = 0; 75 | 76 | virtual bool flushToAll() { 77 | bool success = true; 78 | for (const auto &target : m_flowHandle.targets) 79 | { 80 | success &= flush(target.targetId); 81 | } 82 | return success; 83 | } 84 | }; 85 | 86 | 87 | 88 | 89 | } //dfi namespace end -------------------------------------------------------------------------------- /src/gtest/memory/IntegrationTestsAppend.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file IntegrationTestsAppend.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2018-08-17 5 | */ 6 | 7 | #pragma once 8 | #include 9 | 10 | #include "../../utils/Config.h" 11 | 12 | #include "../../dfi/registry/RegistryClient.h" 13 | #include "../../dfi/registry/RegistryServer.h" 14 | #include "../../dfi/memory/BufferHandle.h" 15 | #include "../../dfi/memory/NodeServer.h" 16 | #include "../../dfi/memory/NodeClient.h" 17 | #include "../../dfi/memory/BufferWriter.h" 18 | 19 | #include 20 | 21 | 22 | class IntegrationTestsAppend : public testing::Test 23 | { 24 | 25 | 26 | public: 27 | void SetUp() override; 28 | void TearDown() override; 29 | 30 | static std::atomic bar; // Counter of threads, faced barrier. 31 | static std::atomic passed; // Number of barriers, passed by all threads. 32 | 33 | protected: 34 | RegistryClient *m_regClient; 35 | RegistryServer *m_regServer; 36 | NodeServer *m_nodeServer; 37 | NodeClient *m_nodeClient; 38 | 39 | 40 | 41 | template 42 | class BufferWriterClient : public rdma::Thread 43 | { 44 | BufferHandle* buffHandle = nullptr; 45 | string& bufferName = ""; 46 | std::vector *dataToWrite = nullptr; //tuple 47 | 48 | public: 49 | 50 | BufferWriterClient(string& bufferName, std::vector *dataToWrite, int numThread = 4, FlowOptimization buffertype = FlowOptimization::BW) : 51 | Thread(), bufferName(bufferName), dataToWrite(dataToWrite), NUMBER_THREADS(numThread), buffertype(buffertype) {} 52 | 53 | int NUMBER_THREADS; 54 | FlowOptimization buffertype; 55 | void run() 56 | { 57 | //ARRANGE 58 | BufferWriterInterface *buffWriter = nullptr; 59 | RegistryClient regClient; 60 | if (buffertype == FlowOptimization::LAT) 61 | { 62 | buffWriter = new BufferWriter(bufferName, regClient, Config::DFI_SOURCE_SEGMENT_COUNT); 63 | } 64 | else 65 | { 66 | buffWriter = new BufferWriter(bufferName, regClient, Config::DFI_SOURCE_SEGMENT_COUNT); 67 | } 68 | 69 | barrier_wait(); //Use barrier to simulate concurrent appends between BufferWriters 70 | 71 | //ACT 72 | for(size_t i = 0; i < dataToWrite->size(); i++) 73 | { 74 | buffWriter->add(&dataToWrite->operator[](i), sizeof(DataType)); 75 | } 76 | 77 | buffWriter->close(); 78 | } 79 | 80 | void barrier_wait() 81 | { 82 | // std::cout << "Enter Barrier" << '\n'; 83 | int passed_old = passed.load(std::memory_order_relaxed); 84 | 85 | if (bar.fetch_add(1) == (NUMBER_THREADS - 1)) 86 | { 87 | // The last thread, faced barrier. 88 | bar = 0; 89 | // Synchronize and store in one operation. 90 | passed.store(passed_old + 1, std::memory_order_release); 91 | } 92 | else 93 | { 94 | // Not the last thread. Wait others. 95 | while (passed.load(std::memory_order_relaxed) == passed_old) 96 | { 97 | }; 98 | // Need to synchronize cache with other threads, passed barrier. 99 | std::atomic_thread_fence(std::memory_order_acquire); 100 | } 101 | } 102 | }; 103 | 104 | }; -------------------------------------------------------------------------------- /src/use-cases/distributed-replicate-join-flow/BuildProberThread.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BuildProberThread.h 3 | * @author Lasse Thostrup 4 | * @brief Adaption of Claude Barthels' MPI join from https://www.systems.ethz.ch/node/334 5 | * Paper: http://www.vldb.org/pvldb/vol10/p517-barthels.pdf 6 | * @date 2020-06-09 7 | * 8 | */ 9 | 10 | #pragma once 11 | #include "Settings.h" 12 | #include "../../flow-api/dfi.h" 13 | #include 14 | #include "utils/Thread.h" 15 | #include "Relation.h" 16 | 17 | class BuildProberThread : public utils::Thread 18 | { 19 | // using Hashtable_t = HashTable>; //KeyType, Hashmap-Size, Hashing-function 20 | 21 | public: 22 | BuildProberThread(size_t partition_id, PartitionHolder **left_partitions, PartitionHolder **right_partitions); 23 | void run(); 24 | private: 25 | PartitionHolder **left_partitions; 26 | PartitionHolder **right_partitions; 27 | size_t partition_id; 28 | public: 29 | size_t joined_tuples_cnt = 0; 30 | size_t non_matched_tuples = 0; 31 | }; 32 | 33 | BuildProberThread::BuildProberThread(size_t partition_id, PartitionHolder **left_partitions, PartitionHolder **right_partitions) : 34 | left_partitions(left_partitions), right_partitions(right_partitions), partition_id(partition_id) 35 | { 36 | 37 | } 38 | 39 | 40 | //NOTE: Build Probe code taken from Claude Barthels' MPI join from https://www.systems.ethz.ch/node/334 41 | void BuildProberThread::run() 42 | { 43 | #ifdef USE_COMPRESSION 44 | const size_t est_merged_size = 1.1 * sizeof(CompressedTuple_t) * (Settings::LEFT_REL_FULL_SIZE / Settings::LOCAL_PARTITION_COUNT); 45 | #else 46 | const size_t est_merged_size = 1.1 * sizeof(Tuple_t) * (Settings::LEFT_REL_FULL_SIZE / Settings::LOCAL_PARTITION_COUNT); 47 | #endif 48 | 49 | 50 | uint64_t N = est_merged_size; 51 | NEXT_POW_2(N); 52 | uint64_t const MASK = (N-1); 53 | 54 | struct ht_entry { 55 | uint64_t t; 56 | uint64_t key; 57 | }; 58 | 59 | ht_entry *hashTableNext = (ht_entry*) calloc(est_merged_size, sizeof(ht_entry)); 60 | uint64_t *hashTableBucket = (uint64_t*) calloc(N, sizeof(uint64_t)); // stores indices 61 | 62 | 63 | // build hash table 64 | uint64_t t = 0; 65 | for (size_t i = 0; i < Settings::PART_THREADS_COUNT; i++) { 66 | Partition *left = left_partitions[i]->partitions[partition_id]; 67 | 68 | for (size_t j = 0; j < left->size; j++) { 69 | uint64_t idx = (left->tuples[j].key >> Settings::LOCAL_PARTITION_BITS) & MASK; //HASH_BIT_MODULO(left_partition.get_tuple(t)->value, MASK, shiftBits); 70 | hashTableNext[t] = {hashTableBucket[idx], left->tuples[j].key}; 71 | hashTableBucket[idx] = ++t; 72 | } 73 | } 74 | 75 | // Probe hash table 76 | for (size_t i = 0; i < Settings::TOTAL_THREADS_COUNT; i++) { 77 | Partition *right = right_partitions[i]->partitions[partition_id]; 78 | 79 | for (size_t j = 0; j < right->size; j++) { 80 | uint64_t idx = (right->tuples[j].key >> Settings::LOCAL_PARTITION_BITS) & MASK; 81 | 82 | uint64_t hit; 83 | for(hit = hashTableBucket[idx]; hit > 0; hit = hashTableNext[hit-1].t) { 84 | if (right->tuples[j].key == hashTableNext[hit-1].key) { 85 | ++joined_tuples_cnt; 86 | } 87 | } 88 | // if (hashTableBucket[idx] == 0) { 89 | // ++non_matched_tuples; 90 | // } 91 | } 92 | 93 | } 94 | 95 | free(hashTableNext); 96 | free(hashTableBucket); 97 | } -------------------------------------------------------------------------------- /src/gtest/memory/TestBufferWriter.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file TestBufferWriter.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2018-08-17 5 | */ 6 | 7 | #pragma once 8 | #include 9 | 10 | #include "../../utils/Config.h" 11 | 12 | #include "../../dfi/memory/NodeServer.h" 13 | #include "../../dfi/memory/NodeClient.h" 14 | #include "../../dfi/registry/RegistryClient.h" 15 | #include "../../dfi/registry/RegistryServer.h" 16 | #include "../../dfi/memory/BufferWriter.h" 17 | #include "../../dfi/memory/BufferReader.h" 18 | 19 | #include 20 | 21 | class TestBufferWriter : public testing::Test { 22 | 23 | 24 | public: 25 | void SetUp() override; 26 | void TearDown() override; 27 | 28 | static std::atomic bar; // Counter of threads, faced barrier. 29 | static std::atomic passed; // Number of barriers, passed by all threads. 30 | static const int NUMBER_THREADS = 2; 31 | 32 | 33 | protected: 34 | void* readSegmentData(BufferSegment* segment, size_t &size); 35 | void* readSegmentData(size_t offset, size_t &size); 36 | DFI_SEGMENT_FOOTER_t *readSegmentFooter(size_t offset); 37 | DFI_SEGMENT_FOOTER_t *readSegmentFooter(BufferSegment* segment); 38 | 39 | NodeServer* m_nodeServer; 40 | RegistryClient* m_regClient; 41 | RegistryServer *m_regServer; 42 | 43 | 44 | struct TestData 45 | { 46 | int a; 47 | int b; 48 | int c; 49 | int d; 50 | TestData(int a, int b, int c, int d) : a(a), b(b), c(c), d(d){} 51 | }; 52 | 53 | template 54 | class BufferWriterClient : public rdma::Thread 55 | { 56 | NodeServer* nodeServer = nullptr; 57 | RegistryClient* regClient = nullptr; 58 | BufferHandle* buffHandle = nullptr; 59 | string& buffername = ""; 60 | std::vector *dataToWrite = nullptr; //tuple 61 | 62 | public: 63 | 64 | BufferWriterClient(NodeServer* nodeServer, string& bufferName, std::vector *dataToWrite) : 65 | Thread(), nodeServer(nodeServer), buffername(bufferName), dataToWrite(dataToWrite) {} 66 | 67 | void run() 68 | { 69 | //ARRANGE 70 | RegistryClient registry_client; 71 | BufferWriter buffWriter(buffername, registry_client, Config::DFI_SOURCE_SEGMENT_COUNT); 72 | 73 | barrier_wait(); 74 | 75 | //ACT 76 | for(size_t i = 0; i < dataToWrite->size(); i++) 77 | { 78 | buffWriter.add(&dataToWrite->operator[](i), sizeof(DataType)); 79 | } 80 | 81 | buffWriter.close(); 82 | } 83 | 84 | void barrier_wait() 85 | { 86 | // std::cout << "Enter Barrier" << '\n'; 87 | int passed_old = passed.load(std::memory_order_relaxed); 88 | 89 | if (bar.fetch_add(1) == (NUMBER_THREADS - 1)) 90 | { 91 | // The last thread, faced barrier. 92 | bar = 0; 93 | // Synchronize and store in one operation. 94 | passed.store(passed_old + 1, std::memory_order_release); 95 | } 96 | else 97 | { 98 | // Not the last thread. Wait others. 99 | while (passed.load(std::memory_order_relaxed) == passed_old) 100 | { 101 | }; 102 | // Need to synchronize cache with other threads, passed barrier. 103 | std::atomic_thread_fence(std::memory_order_acquire); 104 | } 105 | } 106 | }; 107 | 108 | }; 109 | -------------------------------------------------------------------------------- /src/use-cases/rsm-paxos/Settings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../utils/Config.h" 4 | #include "utils/HashTable.h" 5 | 6 | #define UNUSED ((uint64_t) 0) 7 | #define HT_SIZE 4194304 8 | 9 | #define CMD_SIZE 64 10 | #define EMPTY_CMD {.operation = Operation::EMPTY, .key = 0, .value = 0, .padding = {0}} 11 | 12 | #define PADDING_SIZE (CMD_SIZE - 24) 13 | typedef uint64_t Padding[PADDING_SIZE / 8]; 14 | 15 | enum Operation { 16 | EMPTY = 0, 17 | READ = 1, 18 | WRITE = 2, 19 | }; 20 | 21 | enum Mode 22 | { 23 | SYNCHRONOUS = 0, 24 | ASYNCHRONOUS = 1, 25 | BATCHING = 2, 26 | }; 27 | 28 | 29 | enum Return // of the operation 30 | { 31 | SUCCESS = 0, 32 | FAILED = 1, // e.g. could not store value; value not found etc.. 33 | }; 34 | 35 | // Commands send to the RSM. We artificailly inflate the commands to emulate CMD_SIZE byte commands. 36 | struct Command { 37 | uint64_t operation; 38 | uint64_t key; 39 | uint64_t value; 40 | Padding padding; 41 | } __attribute__((packed)); 42 | 43 | struct ClientRequest 44 | { 45 | int8_t clientid; 46 | Command cmd; 47 | } __attribute__((packed)); 48 | 49 | struct ClientResponse 50 | { 51 | int8_t clientid; 52 | int8_t ret_code; 53 | uint64_t ret_val; 54 | } __attribute__((packed)); 55 | 56 | struct Phase1Request 57 | { 58 | uint64_t reqid; 59 | uint64_t proposal_number; 60 | uint64_t committed; // dummy 61 | uint64_t slotid; // dummy 62 | Command command; // dummy 63 | } __attribute__((packed)); 64 | 65 | 66 | struct Phase2Request 67 | { 68 | uint64_t reqid; 69 | uint64_t proposal_number; 70 | uint64_t committed; // up until this slotid are commands committed and can be applied 71 | uint64_t slotid; // command log slot id of this command 72 | Command command; // proposed command 73 | } __attribute__((packed)); 74 | 75 | struct Phase1Response 76 | { 77 | uint64_t reqid; 78 | int8_t ret; 79 | uint64_t accepted_proposal; 80 | Command accepted_command; 81 | } __attribute__((packed)); 82 | 83 | struct Phase2Response 84 | { 85 | uint64_t reqid; 86 | int8_t ret; 87 | uint64_t highest_seen_proposal; 88 | } __attribute__((packed)); 89 | 90 | struct VerificationMsg 91 | { 92 | uint64_t slotid; 93 | Command cmd; 94 | } __attribute__((packed)); 95 | 96 | struct Settings 97 | { 98 | static string FLOWNAME_CLIENT_REQ; 99 | static string FLOWNAME_CLIENT_RESP; 100 | static string FLOWNAME_P1REQ; 101 | static string FLOWNAME_P2REQ; 102 | static string FLOWNAME_P1RESP; 103 | static string FLOWNAME_P2RESP; 104 | static string FLOWNAME_VERIFICATION; 105 | static NodeID LEADER_ID; 106 | static NodeID NODE_ID; 107 | 108 | static string BENCH_FILE; 109 | static Mode MODE; 110 | static uint64_t COMMAND_COUNT; // total number of commands send during run 111 | static uint64_t COMMANDS_PER_SECOND; // total number of commands send during run 112 | static size_t REPLICA_COUNT; 113 | static size_t CLIENT_COUNT; 114 | }; 115 | 116 | inline uint64_t rand_val() 117 | { 118 | return (rand() % 100000000); 119 | } 120 | 121 | inline bool commands_equal(const Command& a, const Command& b) 122 | { 123 | return a.operation == b.operation && a.key == b.key && a.value == b.value; 124 | } -------------------------------------------------------------------------------- /src/gtest/memory/TestBufferWriterReplicate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file TestBufferWriterReplicate.h 3 | * @author cbinnig, lthostrup, tziegler 4 | * @date 2018-08-17 5 | */ 6 | 7 | #pragma once 8 | #include 9 | 10 | #include "../../utils/Config.h" 11 | 12 | #include "../../dfi/memory/NodeServer.h" 13 | #include "../../dfi/memory/NodeClient.h" 14 | #include "../../dfi/registry/RegistryClient.h" 15 | #include "../../dfi/registry/RegistryServer.h" 16 | #include "../../dfi/memory/BufferWriterReplicate.h" 17 | #include "../../dfi/memory/BufferReader.h" 18 | 19 | #include 20 | 21 | class TestBufferWriterReplicate : public testing::Test { 22 | 23 | public: 24 | void SetUp() override; 25 | void TearDown() override; 26 | 27 | static std::atomic bar; // Counter of threads, faced barrier. 28 | static std::atomic passed; // Number of barriers, passed by all threads. 29 | static const int NUMBER_THREADS = 2; 30 | 31 | 32 | protected: 33 | void* readSegmentData(BufferSegment* segment, size_t &size); 34 | void* readSegmentData(size_t offset, size_t &size); 35 | DFI_SEGMENT_FOOTER_t *readSegmentFooter(size_t offset); 36 | DFI_SEGMENT_FOOTER_t *readSegmentFooter(BufferSegment* segment); 37 | 38 | NodeServer* m_nodeServer; 39 | RegistryClient* m_regClient; 40 | RegistryServer *m_regServer; 41 | 42 | 43 | struct TestData 44 | { 45 | int a; 46 | int b; 47 | int c; 48 | int d; 49 | TestData(int a, int b, int c, int d) : a(a), b(b), c(c), d(d){} 50 | }; 51 | 52 | template 53 | class BufferWriterReplicateClient : public rdma::Thread 54 | { 55 | NodeServer* nodeServer = nullptr; 56 | RegistryClient* regClient = nullptr; 57 | BufferHandle* buffHandle = nullptr; 58 | string& buffername = ""; 59 | std::vector *dataToWrite = nullptr; //tuple 60 | 61 | public: 62 | 63 | BufferWriterReplicateClient(NodeServer* nodeServer, string& bufferName, std::vector *dataToWrite) : 64 | Thread(), nodeServer(nodeServer), buffername(bufferName), dataToWrite(dataToWrite) {} 65 | 66 | void run() 67 | { 68 | //ARRANGE 69 | RegistryClient registry_client; 70 | BufferWriterReplicate buffWriter({buffername}, registry_client, Config::DFI_SOURCE_SEGMENT_COUNT); 71 | 72 | barrier_wait(); 73 | 74 | //ACT 75 | for(size_t i = 0; i < dataToWrite->size(); i++) 76 | { 77 | buffWriter.add(&dataToWrite->operator[](i), sizeof(DataType)); 78 | } 79 | 80 | buffWriter.close(); 81 | } 82 | 83 | void barrier_wait() 84 | { 85 | // std::cout << "Enter Barrier" << '\n'; 86 | int passed_old = passed.load(std::memory_order_relaxed); 87 | 88 | if (bar.fetch_add(1) == (NUMBER_THREADS - 1)) 89 | { 90 | // The last thread, faced barrier. 91 | bar = 0; 92 | // Synchronize and store in one operation. 93 | passed.store(passed_old + 1, std::memory_order_release); 94 | } 95 | else 96 | { 97 | // Not the last thread. Wait others. 98 | while (passed.load(std::memory_order_relaxed) == passed_old) 99 | { 100 | }; 101 | // Need to synchronize cache with other threads, passed barrier. 102 | std::atomic_thread_fence(std::memory_order_acquire); 103 | } 104 | } 105 | }; 106 | 107 | }; 108 | -------------------------------------------------------------------------------- /src/flow-api/flow_barrier.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file flow_barrier_init.h 3 | * @author lthostrup 4 | * @date 2020-03-01 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../utils/Config.h" 10 | #include "schema.h" 11 | #include "../dfi/registry/RegistryClient.h" 12 | #include "../dfi/type/ErrorCodes.h" 13 | 14 | 15 | class DFI_Flow_barrier 16 | { 17 | using rdmaclient_t = rdma::RDMAClient; //Reliable client 18 | public: 19 | 20 | /** 21 | * @brief Construct a new dfi flow barrier object. Both Flow and flow barrier must be pre-initialized. 22 | * 23 | * @param name Unique flow name identifier 24 | */ 25 | DFI_Flow_barrier(std::string &name) 26 | { 27 | dfi::RegistryClient regClient; 28 | 29 | while (!regClient.getFlowBarrierOffset(name, m_barrierOffset)) 30 | { 31 | usleep(Config::DFI_SLEEP_INTERVAL); 32 | } 33 | 34 | m_flowHandle = regClient.retrieveFlowHandle(name); 35 | if(m_flowHandle == nullptr) 36 | { 37 | Logging::error(__FILE__, __LINE__, "DFI_Flow_barrier could not get flow handle for barrier. Flow name: " + name); 38 | return; 39 | } 40 | 41 | auto rdmaclient_size = rdma::Config::CACHELINE_SIZE; 42 | m_rdmaclient = std::make_unique(rdmaclient_size); 43 | 44 | m_rdmaclient->connect(Config::DFI_REGISTRY_SERVER + ":" + to_string(Config::DFI_REGISTRY_PORT), m_registryServerID); 45 | m_localCounter = reinterpret_cast(m_rdmaclient->localAlloc(sizeof(size_t))); 46 | }; 47 | 48 | ~DFI_Flow_barrier() = default; 49 | 50 | /** 51 | * @brief Arrive at barrier and wait for all sources to arrive. Should exclusively be used to sync sources (i.e. not concurrently sync targets) 52 | * 53 | */ 54 | void arriveWaitSources() 55 | { 56 | arriveWait(m_flowHandle->sources.size()); 57 | }; 58 | 59 | /** 60 | * @brief Arrive at barrier and wait for all targets to arrive. Should exclusively be used to sync targets (i.e. not concurrently sync source) 61 | * 62 | */ 63 | void arriveWaitTargets() 64 | { 65 | arriveWait(m_flowHandle->targets.size()); 66 | }; 67 | 68 | /** 69 | * @brief Arrive at barrier and wait for all sources and targets to arrive. 70 | * 71 | */ 72 | void arriveWaitAll() 73 | { 74 | arriveWait(m_flowHandle->targets.size() + m_flowHandle->sources.size()); 75 | }; 76 | 77 | /** 78 | * @brief Resets the barrier for later reuse 79 | * 80 | */ 81 | void reset() 82 | { 83 | *m_localCounter = 0; 84 | m_rdmaclient->write(m_registryServerID, m_barrierOffset, m_localCounter, sizeof(size_t), true); 85 | }; 86 | 87 | private: 88 | size_t m_barrierOffset; 89 | size_t *m_localCounter; 90 | std::unique_ptr m_flowHandle; 91 | std::unique_ptr m_rdmaclient; 92 | NodeID m_registryServerID; 93 | 94 | void arriveWait(size_t count) 95 | { 96 | //fetch and add 97 | m_rdmaclient->fetchAndAdd(m_registryServerID, m_barrierOffset, m_localCounter, sizeof(size_t), true); 98 | ++(*m_localCounter); 99 | //rdma read until count 100 | while (*m_localCounter != count) 101 | { 102 | m_rdmaclient->read(m_registryServerID, m_barrierOffset, m_localCounter, sizeof(size_t), true); 103 | } 104 | }; 105 | }; -------------------------------------------------------------------------------- /src/dfi/memory/BufferWriterInterface.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @brief BufferWriter implements two different RDMA strategies to write into the remote memory 3 | * 4 | * @file BufferWriter.h 5 | * @author cbinnig, lthostrup, tziegler 6 | * @date 2018-07-06 7 | */ 8 | 9 | #pragma once 10 | 11 | #include "../../utils/Config.h" 12 | // #if defined(__AVX512F__) && defined(__AVX512BW__) 13 | #ifndef __CUDACC__ 14 | #include 15 | #endif 16 | namespace dfi 17 | { 18 | 19 | struct OutputBuffer 20 | { 21 | uint8_t* bufferPtr = nullptr; 22 | size_t segmentCount = 0; 23 | size_t segmentSize = 0; 24 | size_t segmentIdx = 0; 25 | size_t offset = 0; //write offset in current segment 26 | size_t segmentPadding = 0; 27 | /** 28 | * @brief Construct a new Internal Buffer object 29 | * 30 | * @param bufferPtr Pointer to location of output buffer 31 | * @param segmentCount Number of segments allocated in bufferPtr 32 | * @param segmentSize Size of segments without footer in bytes 33 | * @param cacheAlignedSegments Align each segment start to cache lines such that e.g., non_temp operations can be used 34 | */ 35 | OutputBuffer(void* bufferPtr, size_t segmentCount, size_t segmentSize, bool cacheAlignedSegments) : bufferPtr(reinterpret_cast(bufferPtr)), segmentCount(segmentCount), segmentSize(segmentSize) 36 | { 37 | assert(segmentSize > 0); 38 | assert(segmentCount > 0); 39 | assert(bufferPtr != nullptr); 40 | 41 | if (cacheAlignedSegments) 42 | { 43 | size_t cachelineOffset = ((segmentSize + sizeof(DFI_SEGMENT_FOOTER_t)) % Config::CACHELINE_SIZE); 44 | segmentPadding = Config::CACHELINE_SIZE - (cachelineOffset == 0 ? Config::CACHELINE_SIZE : cachelineOffset); 45 | // std::cout << "segmentPadding " << segmentPadding << std::endl; 46 | } 47 | } 48 | 49 | void *next() 50 | { 51 | offset = 0; 52 | if (++segmentIdx == segmentCount) 53 | { 54 | segmentIdx = 0; 55 | // std::cout << "Next, new offset: 0 idx: " << segmentIdx << std::endl; 56 | return bufferPtr; 57 | } 58 | auto a = bufferPtr + (segmentSize + sizeof(DFI_SEGMENT_FOOTER_t) + segmentPadding) * segmentIdx; 59 | // std::cout << "Next, new offset: " << (segmentSize + sizeof(DFI_SEGMENT_FOOTER_t)) * segmentIdx << " idx: " << segmentIdx << " segmentCount: " << segmentCount << std::endl; 60 | return a; 61 | } 62 | 63 | DFI_SEGMENT_FOOTER_t *getFooter() 64 | { 65 | // std::cout << "segmentIdx: " << segmentIdx << " footer offset: " << segmentSize + (segmentSize + sizeof(DFI_SEGMENT_FOOTER_t) + segmentPadding) * segmentIdx << std::endl; 66 | return reinterpret_cast(bufferPtr + segmentSize + (segmentSize + sizeof(DFI_SEGMENT_FOOTER_t) + segmentPadding) * segmentIdx); 67 | } 68 | }; 69 | 70 | class BufferWriterInterface 71 | { 72 | public: 73 | virtual ~BufferWriterInterface() = default; 74 | virtual bool add(const void *data, size_t size, bool forceSignaled = false) = 0; 75 | virtual bool flush(bool forceSignaled = false, bool isEndSegment = false) = 0; 76 | virtual bool close(bool signaled = true) = 0; 77 | 78 | protected: 79 | inline void store_nontemp_64B(const void *dst, const void *src) 80 | { 81 | #ifndef __CUDACC__ 82 | __m512i s1 = _mm512_loadu_si512(src); 83 | 84 | _mm512_stream_si512((__m512i*)dst, s1); 85 | #else 86 | (void)dst; 87 | (void)src; 88 | #endif 89 | } 90 | }; 91 | 92 | } // namespace dfi -------------------------------------------------------------------------------- /src/use-cases/rsm-nopaxos/benchmark.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | APPNAME="rsm_nopaxos" 4 | pkill -f "bin/$APPNAME" # kill old instance 5 | 6 | CMD_COUNT=1000000 7 | REPITITIONS=1 8 | 9 | CPS_FROM=50000 10 | CPS_TO=50000 11 | CPS_STEP=50000 12 | 13 | REPLICA_COUNT=5 14 | CLIENT_COUNT=6 15 | #REPLICA_IP_LIST="172.18.94.10 172.18.94.20 172.18.94.30 172.18.94.40 172.18.94.50 172.18.94.11 172.18.94.21 172.18.94.31 172.18.94.41 172.18.94.51 172.18.94.60 172.18.94.70 172.18.94.80 172.18.94.61 172.18.94.71 172.18.94.81" 16 | REPLICA_IP_LIST="172.18.94.10 172.18.94.20 172.18.94.30 172.18.94.40 172.18.94.50 172.18.94.60 172.18.94.70 172.18.94.80 172.18.94.61 172.18.94.71 172.18.94.81" 17 | BENCHNAME="${APPNAME}_r${REPLICA_COUNT}_c${CLIENT_COUNT}_max" 18 | 19 | DFI_PATH="$HOME/dfi_library_private" 20 | DFI_BUILD="$DFI_PATH/build" 21 | APP_EXEC="$DFI_BUILD/bin/$APPNAME" 22 | BENCHMARK_DIR="$DFI_PATH/_consensus_bench_data" 23 | LOG_DIR="$BENCHMARK_DIR/log" 24 | 25 | NODE_COUNT=$((REPLICA_COUNT + CLIENT_COUNT)) 26 | 27 | kill_dfi() { 28 | echo "################# Killing running instances of DFI" 29 | for i in `seq $NODE_COUNT -1 1`; 30 | do 31 | NODE="$(echo $REPLICA_IP_LIST | cut -d' ' -f$i)" 32 | ssh $NODE "pkill -f bin/$APPNAME"& 33 | done 34 | wait 35 | 36 | echo "################# DFI killed" 37 | } 38 | 39 | abort_bench() { 40 | >&2 echo "ERROR: Aborting benchmark (manually or something went wrong)" 41 | kill_dfi 42 | echo "################# Everything cleared" 43 | exit 1 44 | } 45 | 46 | is_local() { 47 | ifconfig | grep $1 | wc -l 48 | } 49 | 50 | trap abort_bench SIGINT SIGTERM 51 | 52 | 53 | echo "################# Creating benchmark directory $BENCHMARK_DIR/$BENCHNAME" 54 | mkdir -p $BENCHMARK_DIR/$BENCHNAME 55 | mkdir -p $LOG_DIR 56 | 57 | echo "################# Synching directories" 58 | for i in `seq 1 $NODE_COUNT`; 59 | do 60 | NODE="$(echo $REPLICA_IP_LIST | cut -d' ' -f$i)" 61 | if [ `is_local $NODE` -eq 0 ]; 62 | then 63 | echo "Synching to node $NODE" 64 | rsync -av --exclude build/ $DFI_PATH $NODE:$HOME/ --delete-after || abort_bench 65 | fi 66 | done 67 | wait 68 | 69 | echo "################# compiling DFI" 70 | for i in `seq 1 $NODE_COUNT`; 71 | do 72 | echo "Compiling on node $NODE" 73 | NODE="$(echo $REPLICA_IP_LIST | cut -d' ' -f$i)" 74 | ssh $NODE "make -C $DFI_PATH/build -j8" || abort_bench 75 | done 76 | wait 77 | 78 | for CMD_PER_SECOND in `seq $CPS_FROM $CPS_STEP $CPS_TO`; 79 | do 80 | for r in `seq 1 $REPITITIONS`; 81 | do 82 | echo "################# Starting repitition $r ($CMD_PER_SECOND commands per second)" 83 | 84 | kill_dfi 85 | 86 | echo "################# Executing runs" 87 | for i in `seq 1 1 $NODE_COUNT`; 88 | do 89 | BENCHFILE="$BENCHMARK_DIR/$BENCHNAME/node-tp$CMD_PER_SECOND-r$r-n$i.data" 90 | NODE="$(echo $REPLICA_IP_LIST | cut -d' ' -f$i)" 91 | echo "Starting on node $NODE" 92 | 93 | ssh $NODE "$APP_EXEC $BENCHFILE $CMD_COUNT $CMD_PER_SECOND $i $REPLICA_COUNT $CLIENT_COUNT $REPLICA_IP_LIST" | tee -a $LOG_DIR/node$i.log& 94 | done 95 | wait 96 | 97 | kill_dfi 98 | 99 | echo "################# Collecting benchmark results" 100 | for i in `seq 1 1 $NODE_COUNT`; 101 | do 102 | NODE="$(echo $REPLICA_IP_LIST | cut -d' ' -f$i)" 103 | 104 | BENCHFILE="$BENCHMARK_DIR/$BENCHNAME/node-tp$CMD_PER_SECOND-r$r-n$i.data" 105 | TO="$BENCHMARK_DIR/$BENCHNAME/" 106 | scp "$NODE:$BENCHFILE" $TO 107 | done 108 | done 109 | done --------------------------------------------------------------------------------