├── xutils ├── tests │ ├── test.sh │ ├── build-config.toml │ └── test_rtm.cc ├── print.hh ├── average_report.hh ├── dist_report.hh ├── spin_lock.hh ├── file_loader.hh ├── local_barrier.hh ├── memory_region.hh ├── huge_region.hh ├── xy_data.hh ├── atomic.hh ├── rtm.hh └── cdf.hh ├── xcomm ├── src │ ├── lib.hh │ ├── atomic_rw │ │ ├── ptr.hh │ │ ├── local_async_rw_op.hh │ │ ├── async_rw_trait.hh │ │ ├── rw_trait.hh │ │ ├── rdma_async_rw_op.hh │ │ ├── unwrapper_type.hh │ │ ├── rdma_rw_op.hh │ │ ├── local_rw_op.hh │ │ ├── mod.hh │ │ └── wrapper_type.hh │ ├── rpc │ │ ├── proto.hh │ │ └── reply_station.hh │ ├── batch_rw_op.hh │ └── transport │ │ └── trait.hh ├── benchs │ ├── main.cc │ └── bench_ud.cc ├── scripts │ ├── make.toml │ ├── bench.toml │ ├── kill.toml │ └── test.toml └── tests │ ├── test_async_local.cc │ ├── transport_util.hh │ ├── utils.hh │ ├── test_local_rw.cc │ ├── test_ud_transport.cc │ └── test_remote_rw.cc ├── deps ├── progress-cpp │ ├── .gitignore │ ├── example │ │ ├── CMakeLists.txt │ │ └── src │ │ │ └── example.cpp │ ├── LICENSE │ ├── README.md │ ├── include │ │ └── progresscpp │ │ │ └── ProgressBar.hpp │ └── CMakeLists.txt ├── rlib │ ├── scripts │ │ ├── make.toml │ │ ├── run.toml │ │ ├── examples │ │ │ ├── rc_overflow │ │ │ │ ├── run.toml │ │ │ │ └── make.toml │ │ │ └── ud_overflow │ │ │ │ ├── run.toml │ │ │ │ └── make.toml │ │ ├── benchs │ │ │ └── rw_bench │ │ │ │ ├── make.toml │ │ │ │ └── run.toml │ │ └── sync_to_server.sh │ ├── tests │ │ ├── sample.cc │ │ ├── main.cc │ │ ├── tests.cmake │ │ ├── test_common.cc │ │ ├── test_nicinfo.cc │ │ ├── test_marshal.cc │ │ ├── test_rpc.cc │ │ ├── test_qp_progress.cc │ │ ├── test_mmsg.cc │ │ ├── fast_random.hh │ │ ├── test_channel.cc │ │ ├── random.hh │ │ ├── test_rc.cc │ │ ├── test_cm.cc │ │ └── test_mem.cc │ ├── .gitignore │ ├── .gitmodules │ ├── core │ │ ├── utils │ │ │ ├── option.hh │ │ │ ├── mod.hh │ │ │ ├── timer.hh │ │ │ ├── marshal.hh │ │ │ └── marshal.hpp │ │ ├── qps │ │ │ ├── abs_recv_allocator.hh │ │ │ └── recv_iter.hh │ │ ├── naming.hh │ │ ├── common.hh │ │ ├── nicinfo.hh │ │ ├── rmem │ │ │ ├── mem.hh │ │ │ └── config.hh │ │ ├── bootstrap │ │ │ ├── multi_msg_iter.hh │ │ │ └── proto.hh │ │ └── result.hh │ ├── roadmap │ ├── benchs │ │ ├── bench.cmake │ │ ├── statics.hh │ │ ├── thread.hh │ │ ├── reporter.hh │ │ └── bench_server.cc │ ├── CMakeLists.txt │ ├── .gitlab-ci.yml │ ├── examples │ │ ├── exp.cmake │ │ ├── rc_write │ │ │ └── server.cc │ │ └── rc_pingpong │ │ │ └── server.cc │ ├── README.md │ └── docs │ │ ├── examples │ │ └── TUTORIALS.md │ │ └── benchs │ │ ├── op_performance.md │ │ ├── ro_performance.md │ │ └── TUTORIALS.md └── r2 │ ├── .gitignore │ ├── tests │ ├── test_rdtsc.cc │ ├── test_list.cc │ ├── test_ssched.cc │ ├── tests.cmake │ └── test_srop.cc │ ├── src │ ├── utils │ │ ├── option.hh │ │ └── rdtsc.hh │ ├── msg │ │ ├── ud_msg.hh │ │ ├── msg_session.hh │ │ └── ud_msg.hpp │ ├── ring_msg │ │ ├── proto.hh │ │ ├── id_helper.hh │ │ ├── recv_bundler.hh │ │ ├── ring.hh │ │ └── cm.hh │ ├── mem_block.hh │ ├── allocator.hh │ ├── rpc │ │ ├── rpc_data.hpp │ │ └── buf_factory.hpp │ ├── timer.hh │ ├── routine.hh │ ├── tm_manager.hh │ ├── common.hh │ ├── logging.cc │ ├── thread.hh │ ├── linked_list.hh │ ├── rdma │ │ └── async_op.hh │ ├── random.hh │ ├── scheduler.cc │ └── channel │ │ └── mod.hh │ ├── benchs │ ├── bench.cmake │ ├── mem_region.hh │ ├── huge_region.hh │ └── bench_server.cc │ ├── .gitmodules │ ├── CMakeLists.txt │ ├── .gitlab-ci.yml │ └── README.md ├── benchs ├── Rolex │ └── tests │ │ ├── main.cc │ │ ├── tests.cmake │ │ └── test_leaf_table.cc ├── statics.hh ├── arc │ └── val │ │ ├── net_config.hh │ │ └── cpu.hh ├── reporter.hh ├── load_config.hh └── rolex_util_back.hh ├── rolex ├── trait.hpp ├── rolex_util.hh ├── memory_region.hh ├── local_allocator.hh ├── huge_region.hh └── remote_requests.hpp ├── README.md └── CMakeLists.txt /xutils/tests/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ./test_rtm 4 | -------------------------------------------------------------------------------- /xcomm/src/lib.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "./atomic_rw/mod.hh" 4 | -------------------------------------------------------------------------------- /deps/progress-cpp/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | build 3 | cmake-build-debug 4 | cmake-build-release 5 | -------------------------------------------------------------------------------- /xcomm/benchs/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::cout << "hello world!"; 5 | } 6 | -------------------------------------------------------------------------------- /deps/rlib/scripts/make.toml: -------------------------------------------------------------------------------- 1 | [[pass]] 2 | host = "val02" 3 | path = '' 4 | cmd = 'cd rib/; cmake .; make coretest' -------------------------------------------------------------------------------- /deps/rlib/tests/sample.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | TEST(RDMAIO,Sample) { 4 | ASSERT_EQ(1,1); 5 | } 6 | -------------------------------------------------------------------------------- /xcomm/benchs/bench_ud.cc: -------------------------------------------------------------------------------- 1 | #include "../src/transport/rdma_ud_t.hh" 2 | 3 | #include 4 | 5 | int main() { std::cout << "hello world!"; } 6 | -------------------------------------------------------------------------------- /deps/r2/.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.exe 3 | *.swp 4 | *.DS_Store 5 | build/ 6 | .vs/ 7 | .vscode/ 8 | .git/ 9 | .settings/ 10 | .cproject 11 | .project 12 | 13 | -------------------------------------------------------------------------------- /deps/rlib/.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.exe 3 | *.swp 4 | *.DS_Store 5 | build/ 6 | .vs/ 7 | .vscode/ 8 | .git/ 9 | .settings/ 10 | .cproject 11 | .project 12 | 13 | -------------------------------------------------------------------------------- /benchs/Rolex/tests/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) { 4 | ::testing::InitGoogleTest(&argc, argv); 5 | return RUN_ALL_TESTS(); 6 | } -------------------------------------------------------------------------------- /deps/rlib/tests/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) { 4 | ::testing::InitGoogleTest(&argc, argv); 5 | return RUN_ALL_TESTS(); 6 | } 7 | -------------------------------------------------------------------------------- /xcomm/scripts/make.toml: -------------------------------------------------------------------------------- 1 | [[pass]] 2 | host = "val2" 3 | path = '/cock/xstore/xcomm' 4 | cmd = 'cmake .; make test_transport; make test_ud; make rpc_server; make rpc_client;' 5 | -------------------------------------------------------------------------------- /deps/rlib/scripts/run.toml: -------------------------------------------------------------------------------- 1 | [[pass]] 2 | host = "val08" 3 | path = '' 4 | cmd = 'cd rib/; ./pserver' 5 | 6 | [[pass]] 7 | host = "val08" 8 | path = '' 9 | cmd = 'cd rib/; ./pclient' -------------------------------------------------------------------------------- /deps/rlib/tests/tests.cmake: -------------------------------------------------------------------------------- 1 | 2 | 3 | file(GLOB TSOURCES "tests/*.cc" ) 4 | add_executable(coretest ${TSOURCES} ) 5 | 6 | target_link_libraries(coretest gtest gtest_main ibverbs pthread) 7 | -------------------------------------------------------------------------------- /xutils/tests/build-config.toml: -------------------------------------------------------------------------------- 1 | [config] 2 | std = "c++17" 3 | 4 | [[apps]] 5 | name = "test_rtm" 6 | src = ["../../deps/r2/src/logging.cc","./test_rtm.cc"] 7 | extra = ["pthread", "gtest"] 8 | 9 | 10 | -------------------------------------------------------------------------------- /deps/rlib/scripts/examples/rc_overflow/run.toml: -------------------------------------------------------------------------------- 1 | [[pass]] 2 | host = "val09" 3 | path = '' 4 | cmd = 'cd rib/; ./roserver' 5 | 6 | [[pass]] 7 | host = "val08" 8 | path = '' 9 | cmd = 'cd rib/; ./roclient -addr val09:8888' -------------------------------------------------------------------------------- /deps/rlib/scripts/examples/ud_overflow/run.toml: -------------------------------------------------------------------------------- 1 | [[pass]] 2 | host = "val09" 3 | path = '' 4 | cmd = 'cd rib/; ./uoserver' 5 | 6 | [[pass]] 7 | host = "val08" 8 | path = '' 9 | cmd = 'cd rib/; ./uoclient -addr val09:8888' -------------------------------------------------------------------------------- /deps/rlib/scripts/examples/rc_overflow/make.toml: -------------------------------------------------------------------------------- 1 | [[pass]] 2 | host = "val08" 3 | path = '' 4 | cmd = 'cd rib/; cmake .; make roclient;' 5 | 6 | [[pass]] 7 | host = "val09" 8 | path = '' 9 | cmd = 'cd rib/; cmake .; make roserver;' -------------------------------------------------------------------------------- /deps/rlib/scripts/examples/ud_overflow/make.toml: -------------------------------------------------------------------------------- 1 | [[pass]] 2 | host = "val08" 3 | path = '' 4 | cmd = 'cd rib/; cmake .; make uoclient;' 5 | 6 | [[pass]] 7 | host = "val09" 8 | path = '' 9 | cmd = 'cd rib/; cmake .; make uoserver;' -------------------------------------------------------------------------------- /deps/rlib/.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "examples/gflags"] 2 | path = examples/gflags 3 | url = https://github.com/gflags/gflags.git 4 | [submodule "tests/googletest"] 5 | path = tests/googletest 6 | url = https://github.com/google/googletest.git 7 | -------------------------------------------------------------------------------- /xcomm/scripts/bench.toml: -------------------------------------------------------------------------------- 1 | [[pass]] 2 | host = "val1" 3 | path = "/cock/xstore/xcomm" 4 | cmd = "./rpc_server" 5 | 6 | 7 | [[pass]] 8 | host = "val2" 9 | path = "/cock/xstore/xcomm" 10 | cmd = "sleep 2; ./rpc_client --addr='val01:8888' --coros 10" 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /xcomm/scripts/kill.toml: -------------------------------------------------------------------------------- 1 | [[pass]] 2 | host = "val2" 3 | path = "/cock/xstore/xcomm" 4 | cmd = "pkill rpc_client; pkill rpc_server;" 5 | 6 | [[pass]] 7 | host = "val1" 8 | path = "/cock/xstore/xcomm" 9 | cmd = "pkill rpc_server; pkill rpc_client;" 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /deps/r2/tests/test_rdtsc.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../src/utils/rdtsc.hh" 4 | 5 | using namespace r2; 6 | 7 | namespace test { 8 | 9 | TEST(Util, Rdtsc) { 10 | RDTSC rdtsc; 11 | sleep(1); 12 | ASSERT_GE(rdtsc.passed(), 0); 13 | } 14 | } // namespace test 15 | -------------------------------------------------------------------------------- /benchs/Rolex/tests/tests.cmake: -------------------------------------------------------------------------------- 1 | 2 | file(GLOB TSOURCES "benchs/Rolex/tests/*.cc") 3 | file(GLOB coretest_SORUCES "" "deps/r2/src/logging.cc" "benchs/Rolex/tests/*.cc") 4 | add_executable(coretest ${coretest_SORUCES} ${TSOURCES} ) 5 | 6 | target_link_libraries(coretest gtest_main gtest gflags ibverbs pthread boost_system boost_coroutine) 7 | 8 | -------------------------------------------------------------------------------- /deps/rlib/scripts/benchs/rw_bench/make.toml: -------------------------------------------------------------------------------- 1 | [[pass]] 2 | host = "val09" 3 | path = '' 4 | cmd = 'cd rib/; cmake .; make bench_server;' 5 | 6 | [[pass]] 7 | host = "val08" 8 | path = '' 9 | cmd = 'cd rib/; cmake .; make bench_client;' 10 | 11 | [[pass]] 12 | host = "val10" 13 | path = '' 14 | cmd = 'cd rib/; cmake .; make bench_client;' -------------------------------------------------------------------------------- /deps/rlib/tests/test_common.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../core/common.hh" 4 | 5 | TEST(RDMAIO, Common) { 6 | using namespace rdmaio; 7 | 8 | auto result = Ok(); 9 | ASSERT_EQ(result.code.c, IOCode::Ok); 10 | ASSERT_EQ(result.code.name(), "Ok"); 11 | auto res = (result.code == IOCode::Ok); 12 | ASSERT_TRUE(res); 13 | } 14 | -------------------------------------------------------------------------------- /deps/rlib/scripts/benchs/rw_bench/run.toml: -------------------------------------------------------------------------------- 1 | [[pass]] 2 | host = "val09" 3 | path = '' 4 | cmd = 'cd rib/; ./bench_server' 5 | 6 | [[pass]] 7 | host = "val08" 8 | path = '' 9 | cmd = 'cd rib/; ./bench_client -client_name val08 -threads 12' 10 | 11 | [[pass]] 12 | host = "val10" 13 | path = '' 14 | cmd = 'cd rib/; ./bench_client -client_name val10 -threads 12' -------------------------------------------------------------------------------- /deps/r2/src/utils/option.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(__GNUC__) && __GNUC__ < 7 4 | #include 5 | #define _r2_optional std::experimental::optional 6 | #else 7 | #include 8 | #define _r2_optional std::optional 9 | #endif 10 | 11 | namespace r2 { 12 | template using Option = _r2_optional; 13 | } // namespace r2 14 | -------------------------------------------------------------------------------- /deps/rlib/core/utils/option.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(__GNUC__) && __GNUC__ < 7 4 | #include 5 | #define _rlib_optional std::experimental::optional 6 | #else 7 | #include 8 | #define _rlib_optional std::optional 9 | #endif 10 | 11 | namespace rdmaio { 12 | template using Option = _rlib_optional; 13 | } 14 | -------------------------------------------------------------------------------- /deps/r2/benchs/bench.cmake: -------------------------------------------------------------------------------- 1 | 2 | set(benchs 3 | bench_server co_client) 4 | 5 | add_executable(co_client benchs/co_bench/client.cc) 6 | add_executable(bench_server benchs/bench_server.cc) 7 | 8 | foreach(b ${benchs}) 9 | target_link_libraries(${b} pthread gflags boost_serialization jemalloc ibverbs boost_coroutine boost_chrono boost_thread boost_context boost_system r2) 10 | endforeach(b) 11 | -------------------------------------------------------------------------------- /deps/rlib/scripts/sync_to_server.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # this script will sync the project to the remote server 3 | 4 | user="wjq" 5 | target=("val08" "val09") 6 | 7 | for machine in ${target[*]} 8 | do 9 | rsync -i -rtuv \ 10 | $PWD/../core $PWD/../tests $PWD/../examples $PWD/../benchs $PWD/../CMakeLists.txt \ 11 | ${user}@${machine}:/home/${user}/rib 12 | done 13 | -------------------------------------------------------------------------------- /deps/r2/src/msg/ud_msg.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "./ud_session.hh" 6 | 7 | namespace r2 { 8 | 9 | class UDMsg { 10 | using session_id_t = u32; 11 | using session_map_t = std::unordered_map < session_id_t, Arc; 12 | 13 | session_map_t opened_sessions; 14 | 15 | Arc ud; 16 | 17 | explicit UDMsg(Arc ud) : ud(ud) {} 18 | 19 | 20 | }; 21 | } // namespace r2 22 | -------------------------------------------------------------------------------- /deps/r2/.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "deps/rlib"] 2 | path = deps/rlib 3 | url = https://github.com/wxdwfc/rlibv2.git 4 | [submodule "deps/gflags"] 5 | path = deps/gflags 6 | url = https://github.com/gflags/gflags.git 7 | [submodule "deps/googletest"] 8 | path = deps/googletest 9 | url = https://github.com/google/googletest.git 10 | [submodule "deps/jemalloc"] 11 | path = deps/jemalloc 12 | url = https://github.com/jemalloc/jemalloc.git 13 | -------------------------------------------------------------------------------- /deps/rlib/roadmap: -------------------------------------------------------------------------------- 1 | Refine list: 2 | - Different codes (done, good result code) 3 | - Marshalling lib (done) 4 | - Memory (done) 5 | - Memory registration + factory (done) 6 | - QPs 7 | - progress (done) 8 | - RC (done) 9 | - QP poll 10 | - QP factory 11 | - fetch op 12 | - Simple bootstrap RPC 13 | - timeout (done) 14 | - TCP (done) 15 | - RPC sender (done) 16 | - RPC receiver (done) 17 | - UDP (done) 18 | - connector () 19 | - QPs 20 | - UD -------------------------------------------------------------------------------- /xutils/print.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace xstore { 7 | namespace util { 8 | 9 | template 10 | std::string 11 | vec_slice_to_str(const std::vector& v, int begin, int end) 12 | { 13 | std::ostringstream oss; 14 | oss << "["; 15 | for (uint i = begin; i < std::min(static_cast(v.size()), end); ++i) 16 | oss << v[i] << ","; 17 | oss << "]"; 18 | return oss.str(); 19 | } 20 | 21 | } 22 | } -------------------------------------------------------------------------------- /deps/r2/src/utils/rdtsc.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../common.hh" 4 | 5 | namespace r2 { 6 | 7 | class RDTSC { 8 | public: 9 | static inline u64 read_tsc(void) { 10 | u32 a, d; 11 | __asm __volatile("rdtsc" : "=a"(a), "=d"(d)); 12 | return ((u64)a) | (((u64)d) << 32); 13 | } 14 | 15 | RDTSC() : start(read_tsc()) {} 16 | u64 passed() const { return read_tsc() - start; } 17 | 18 | private: 19 | u64 start; 20 | }; 21 | 22 | } // namespace r2 23 | -------------------------------------------------------------------------------- /xcomm/scripts/test.toml: -------------------------------------------------------------------------------- 1 | [[pass]] 2 | host = "localhost" 3 | path = '~/lab/xstore/scripts/' 4 | cmd = './sync.sh' 5 | local = "yes" 6 | 7 | 8 | [[pass]] 9 | host = "val2" 10 | path = '/cock/xstore/xcomm' 11 | #cmd = '../magic.py config -f build-config.toml; cmake .; make test_transport; make test_ud;' ## build from scratch 12 | cmd = 'cmake .; make test_transport; make test_ud;' 13 | 14 | [[pass]] 15 | host = "val2" 16 | path = "/cock/xstore/xcomm" 17 | cmd = "./test_ud" 18 | 19 | 20 | -------------------------------------------------------------------------------- /deps/rlib/benchs/bench.cmake: -------------------------------------------------------------------------------- 1 | 2 | 3 | add_executable(bench_client ./benchs/bench_client.cc) 4 | add_executable(bench_server ./benchs/bench_server.cc) 5 | add_executable(fly_client ./benchs/fly_bench/client.cc) 6 | add_executable(or_client ./benchs/or_bench/client.cc) 7 | add_executable(db_client ./benchs/db_bench/client.cc) 8 | 9 | 10 | set(benchs 11 | bench_client bench_server 12 | fly_client or_client db_client) 13 | 14 | foreach(b ${benchs}) 15 | target_link_libraries(${b} pthread ibverbs gflags) 16 | endforeach(b) -------------------------------------------------------------------------------- /xcomm/src/atomic_rw/ptr.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace xstore { 4 | 5 | namespace xcomm { 6 | 7 | namespace rw { 8 | 9 | template inline auto read_volatile(char *ptr) -> T { 10 | volatile T *v_ptr = reinterpret_cast(ptr); 11 | return *v_ptr; 12 | } 13 | 14 | template inline void write_volatile(char *ptr, const T &v) { 15 | volatile T *v_ptr = reinterpret_cast(ptr); 16 | *v_ptr = v; 17 | } 18 | 19 | } // namespace rw 20 | } // namespace xcomm 21 | } // namespace xstore 22 | -------------------------------------------------------------------------------- /deps/rlib/core/utils/mod.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "./timer.hh" 4 | #include 5 | 6 | namespace rdmaio { 7 | 8 | /*! 9 | A set of number utilities. 10 | */ 11 | /** 12 | * This nice code comes from 13 | * https://stackoverflow.com/questions/1392059/algorithm-to-generate-bit-mask 14 | */ 15 | template static constexpr R bitmask(unsigned int const onecount) { 16 | return static_cast(-(onecount != 0)) & 17 | (static_cast(-1) >> ((sizeof(R) * CHAR_BIT) - onecount)); 18 | } 19 | } // namespace rdmaio 20 | -------------------------------------------------------------------------------- /deps/rlib/tests/test_nicinfo.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../core/nicinfo.hh" 4 | 5 | using namespace rdmaio; 6 | 7 | TEST(RNic,Exists) { 8 | auto res = RNicInfo::query_dev_names(); 9 | ASSERT_FALSE(res.empty()); // there has to be NIC on the host machine 10 | } 11 | 12 | TEST(RNic, State) { 13 | // check the NIC at this server is activate, 14 | // which means that the call to `ibstatus` will result in ACTIVE 15 | auto nic = 16 | RNic::create(RNicInfo::query_dev_names().at(0)).value(); 17 | ASSERT_TRUE(nic->is_active()==IOCode::Ok); 18 | } 19 | -------------------------------------------------------------------------------- /deps/r2/tests/test_list.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../src/linked_list.hh" 4 | #include "../src/logging.hh" 5 | 6 | using namespace r2; 7 | 8 | namespace test { 9 | 10 | TEST(List, Basic) { 11 | 12 | LinkedList test; 13 | for(uint i = 0;i < 12;++i){ 14 | test.add(new Node(i)); 15 | //LOG(2) << "tailer's value " << test.tailer_p->val << "; prev: " << test.tailer_p->prev_p->val; 16 | } 17 | 18 | for (uint i = 0;i < 12;++i) { 19 | auto n = test.peek().value(); 20 | ASSERT_EQ(n->val,i); 21 | delete n; 22 | } 23 | } 24 | 25 | } // namespace test 26 | -------------------------------------------------------------------------------- /deps/r2/tests/test_ssched.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../src/libroutine.hh" 4 | #include "../src/logging.hh" 5 | 6 | using namespace r2; 7 | 8 | namespace test { 9 | 10 | TEST(SSched, Basic) { 11 | 12 | usize counter = 0; 13 | SScheduler ssched; 14 | #if 1 15 | for (uint i = 0; i < 12; ++i) 16 | ssched.spawn([&counter,i](R2_ASYNC) { 17 | 18 | counter += 1; 19 | if (i == 11) 20 | R2_STOP(); 21 | //LOG(2) << "inc done"; 22 | R2_RET; 23 | }); 24 | #endif 25 | 26 | ssched.run(); 27 | ASSERT_EQ(12,counter); 28 | } 29 | 30 | } // namespace test 31 | -------------------------------------------------------------------------------- /deps/rlib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8...3.13) 2 | 3 | add_definitions(-std=c++1z) 4 | 5 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 6 | set(CMAKE_CXX_COMPILER /usr/bin/g++) 7 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") 8 | 9 | 10 | ## tests 11 | enable_testing() 12 | 13 | add_test(NAME test COMMAND coretest) 14 | add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --verbose 15 | DEPENDS coretest) 16 | 17 | include(tests/tests.cmake) 18 | 19 | 20 | ## for examples 21 | 22 | include(examples/exp.cmake) 23 | 24 | include(benchs/bench.cmake) 25 | 26 | 27 | project (rlib) 28 | 29 | -------------------------------------------------------------------------------- /deps/r2/src/ring_msg/proto.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "rlib/core/bootstrap/proto.hh" 4 | 5 | namespace r2 { 6 | 7 | namespace ring_msg { 8 | 9 | using namespace rdmaio; 10 | using namespace rdmaio::qp; 11 | using namespace rdmaio::proto; 12 | using namespace rdmaio::rmem; 13 | 14 | const u32 kMagic = 73; 15 | 16 | struct __attribute__((packed)) RingReply { 17 | RCReply rc_reply; 18 | u64 base_off; 19 | RegAttr mr; 20 | }; 21 | 22 | struct __attribute__((packed)) RingBootstrap { 23 | u64 base_off; 24 | RegAttr mr; 25 | u32 magic_key = kMagic; 26 | }; 27 | 28 | } // namespace ring_msg 29 | 30 | } // namespace r2 31 | -------------------------------------------------------------------------------- /xcomm/src/atomic_rw/local_async_rw_op.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../../deps/r2/src/sshed.hh" 4 | 5 | #include "./async_rw_trait.hh" 6 | 7 | #include "./local_rw_op.hh" 8 | 9 | namespace xstore { 10 | 11 | namespace xcomm { 12 | 13 | namespace rw { 14 | 15 | using namespace rdmaio; 16 | 17 | struct AsyncLocalRWOp : public AsyncReadWriteTrait 18 | { 19 | AsyncLocalRWOp() = default; 20 | auto read_impl(const MemBlock& src, const MemBlock& dest, R2_ASYNC) 21 | -> Result<> 22 | { 23 | return LocalRWOp().read(src, dest); 24 | } 25 | }; 26 | } // namespace rw 27 | } // namespace xcomm 28 | } // namespace xstore -------------------------------------------------------------------------------- /deps/rlib/core/qps/abs_recv_allocator.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../rmem/handler.hh" 4 | 5 | namespace rdmaio { 6 | 7 | namespace qp { 8 | 9 | class AbsRecvAllocator { 10 | public: 11 | /*! 12 | allocate an RDMA recv buffer, 13 | which has (ptr, key) 14 | */ 15 | virtual Option> 16 | alloc_one(const usize &sz) = 0; 17 | 18 | /*! 19 | allocate an memory for the remote; which needs to register this memory 20 | */ 21 | virtual Option> 22 | alloc_one_for_remote(const usize &sz) = 0; 23 | }; 24 | 25 | } // namespace qp 26 | } // namespace rdmaio 27 | -------------------------------------------------------------------------------- /deps/rlib/benchs/statics.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../core/common.hh" 4 | 5 | namespace rdmaio { 6 | 7 | /*! 8 | * Statictics used for multi-thread reporting. 9 | * The structure is 128-byte padded and aligned to avoid false sharing. 10 | */ 11 | struct alignas(128) Statics { 12 | 13 | typedef struct { 14 | u64 counter = 0; 15 | u64 counter1 = 0; 16 | u64 counter2 = 0; 17 | u64 counter3 = 0; 18 | double lat = 0; 19 | } data_t; 20 | data_t data; 21 | 22 | char pad[128 - sizeof(data)]; 23 | 24 | void increment(int d = 1) { data.counter += d; } 25 | 26 | void increment_gap_1(u64 d) { data.counter1 += d; } 27 | }; 28 | 29 | } // namespace rdmaio 30 | -------------------------------------------------------------------------------- /deps/progress-cpp/example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5 FATAL_ERROR) 2 | 3 | project(progresscppExample 4 | LANGUAGES CXX 5 | ) 6 | 7 | # ---- Dependencies ---- 8 | 9 | include(../cmake/CPM.cmake) 10 | 11 | CPMAddPackage( 12 | NAME progresscpp 13 | SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/.. 14 | ) 15 | 16 | # ---- Create standalone executable ---- 17 | 18 | file(GLOB sources CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) 19 | 20 | add_executable(progresscppExample ${sources}) 21 | 22 | set_target_properties(progresscppExample PROPERTIES 23 | CXX_STANDARD 11 24 | OUTPUT_NAME "Progress-cpp Example" 25 | ) 26 | 27 | target_link_libraries(progresscppExample progresscpp) -------------------------------------------------------------------------------- /deps/r2/tests/tests.cmake: -------------------------------------------------------------------------------- 1 | 2 | ## main test files 3 | file(GLOB TSOURCES "tests/test_srop.cc" "tests/test_ud_session.cc" "tests/test_rc_session.cc" "tests/test_rm.cc") 4 | add_executable(coretest ${TSOURCES} ) 5 | 6 | target_link_libraries(coretest gtest gtest_main rocksdb boost_serialization jemalloc ibverbs boost_coroutine boost_chrono boost_thread boost_context boost_system r2 pthread) 7 | 8 | ## test file when there is no RDMA, allow local debug 9 | file(GLOB T_WO_SOURCES "tests/test_list.cc" "tests/test_rdtsc.cc" "tests/test_ssched.cc" ) 10 | add_executable(coretest_wo_rdma ${T_WO_SOURCES} "src/logging.cc") 11 | target_link_libraries(coretest_wo_rdma gtest gtest_main boost_context boost_system boost_coroutine boost_thread boost_chrono r2 pthread) 12 | -------------------------------------------------------------------------------- /deps/r2/src/mem_block.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "./common.hh" 4 | 5 | namespace r2 { 6 | 7 | /*! 8 | Msg is a safe wrapper over a raw pointer. 9 | To safely create/destory a message, 10 | please refer to constructors at msg_factory.hpp 11 | */ 12 | 13 | struct MemBlock { 14 | void *mem_ptr = nullptr; 15 | u32 sz = 0; 16 | 17 | MemBlock() = default; 18 | 19 | MemBlock(void *data_p, const u32 &sz) : mem_ptr(data_p), sz(sz) {} 20 | 21 | template inline T *interpret_as(const u32 &offset = 0) const { 22 | if (unlikely(sz - offset < sizeof(T))) 23 | return nullptr; 24 | { // unsafe 25 | return reinterpret_cast((char *)mem_ptr + offset); 26 | } 27 | } 28 | }; 29 | 30 | } // namespace r2 31 | -------------------------------------------------------------------------------- /rolex/trait.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "leaf.hpp" 5 | #include "leaf_allocator.hpp" 6 | #include "model_allocator.hpp" 7 | #include "leaf_table.hpp" 8 | #include "rolex.hpp" 9 | #include "learned_cache.hpp" 10 | #include "remote_memory.hh" 11 | 12 | namespace rolex { 13 | 14 | using K = u64; 15 | using V = u64; 16 | using leaf_t = Leaf<64, K, V>; 17 | using leaf_alloc_t = LeafAllocator; 18 | using model_alloc_t = ModelAllocator; 19 | using remote_memory_t = RemoteMemory; 20 | using leaf_table_t = LeafTable; 21 | using rolex_t = Rolex; 22 | using learned_cache_t = LearnedCache; 23 | 24 | 25 | 26 | } -------------------------------------------------------------------------------- /deps/r2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | 3 | project(rtwo) 4 | 5 | ADD_DEFINITIONS(-std=c++1z) 6 | 7 | set(CMAKE_CXX_FLAGS "-O2") 8 | 9 | include_directories("../") 10 | 11 | ## install dependies 12 | #include(deps/deps.cmake) 13 | 14 | add_library(r2 src/logging.cc src/sshed.cc) 15 | target_include_directories (r2 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 16 | target_link_libraries(r2 boost_context boost_system boost_coroutine boost_thread boost_chrono) 17 | 18 | 19 | ## tests 20 | #include(tests/tests.cmake) 21 | 22 | 23 | ## benchs 24 | include(benchs/bench.cmake) 25 | 26 | #[[ 27 | enable_testing() 28 | 29 | add_test(NAME test COMMAND tests/coretest) 30 | add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --verbose 31 | DEPENDS tests/coretest ) 32 | ]] 33 | 34 | 35 | -------------------------------------------------------------------------------- /deps/rlib/core/naming.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "./common.hh" 6 | 7 | namespace rdmaio { 8 | 9 | /*! 10 | */ 11 | using HostId = std::tuple; // TCP host host,port 12 | 13 | /*! 14 | DevIdx is a handy way to identify the RNIC. 15 | A NIC is identified by a dev_id, while each device has several ports. 16 | */ 17 | struct DevIdx { 18 | usize dev_id; 19 | usize port_id; 20 | 21 | friend std::ostream &operator<<(std::ostream &os, const DevIdx &i) { 22 | return os << "{" << i.dev_id << ":" << i.port_id << "}"; 23 | } 24 | }; 25 | 26 | /*! 27 | Internal network address used by the driver 28 | */ 29 | struct __attribute__((packed)) RAddress { 30 | u64 subnet_prefix; 31 | u64 interface_id; 32 | u32 local_id; 33 | }; 34 | 35 | 36 | } // namespace rdmaio 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## ROLEX 2 | ROLEX: A Scalable RDMA-oriented Learned Key-Value Store for Disaggregated Memory Systems 3 | 4 | ### Build 5 | 1. Dependency 6 | ``` 7 | MLNX_OFED_LINUX-5.4-1.0.3.0-ubuntu18.04-x86_64 8 | Boost_1.65 9 | Gflags_2.2.2 10 | ``` 11 | 2. CMake 12 | ``` 13 | $ mkdir build 14 | $ cd build 15 | $ cmake .. 16 | $ make 17 | ``` 18 | 3. Create HugePage 19 | ### Run 20 | ``` 21 | ./rolex --nkeys=100000 --non_nkeys=100000 22 | ``` 23 | 24 | | parameters | descriptions | 25 | | ---- | ---- | 26 | | --nkeys | the number of trained data | 27 | | --non_nkeys | the number of new data | 28 | | --threads | the number of threads | 29 | | --coros | the number of coroutines | 30 | | --workloads | workloads | 31 | | --read_ratio | the read ratio | 32 | | --insert_ratio | the write ratio | 33 | | --update_ratio | the update ratio |. 34 | -------------------------------------------------------------------------------- /deps/r2/.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | before_script: 2 | - python -V # Print out python version for debugging 3 | - pip install toml 4 | - git config --global user.email "wxdwfc@gmail.com" 5 | - git config --global user.name "wxd" 6 | - git submodule sync 7 | - git submodule update --init 8 | - git submodule update --remote deps/rlib 9 | - export export CXX=g++-7 10 | 11 | cache: 12 | key: ${CI_COMMIT_REF_SLUG} 13 | paths: 14 | - deps/ 15 | 16 | # run tests using the binary built before 17 | build: 18 | stage: build 19 | tags: 20 | - rdma 21 | script: 22 | - cmake .; make boost; make jemalloc; make; 23 | 24 | 25 | test: 26 | stage: test 27 | tags: 28 | - rdma 29 | script: 30 | # - cmake .; make boost; 31 | - cmake .; make coretest; ./coretest; 32 | - cmake .; make coretest_wo_rdma; ./coretest_wo_rdma; 33 | 34 | -------------------------------------------------------------------------------- /xcomm/src/atomic_rw/async_rw_trait.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Result<> to record whether the op is done 4 | #include "../../../deps/rlib/core/result.hh" 5 | 6 | // Memblock, which abstract away a raw pointer 7 | #include "../../../deps/r2/src/mem_block.hh" 8 | #include "../../../deps/r2/src/libroutine.hh" 9 | 10 | namespace xstore { 11 | 12 | namespace xcomm { 13 | 14 | namespace rw { 15 | 16 | using namespace rdmaio; 17 | using namespace r2; 18 | 19 | // abstract interface 20 | template class AsyncReadWriteTrait { 21 | public: 22 | // read content from src -> dest 23 | auto read(const MemBlock &src, const MemBlock &dest, R2_ASYNC) -> Result<> { 24 | return static_cast(this)->read_impl(src, dest, R2_ASYNC_WAIT); 25 | } 26 | }; 27 | 28 | } // namespace rw 29 | } // namespace xcomm 30 | 31 | } // namespace xstore 32 | -------------------------------------------------------------------------------- /xutils/average_report.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../deps/r2/src/common.hh" 4 | 5 | namespace xstore { 6 | 7 | namespace util { 8 | 9 | using namespace r2; 10 | 11 | template class AvgReport { 12 | public: 13 | double average = 0; 14 | T min; 15 | T max; 16 | u64 num = 1; 17 | 18 | AvgReport() 19 | : min(std::numeric_limits::max()), max(std::numeric_limits::min()) { 20 | } 21 | 22 | void add(const T &v) { 23 | min = std::min(v, min); 24 | max = std::max(v, max); 25 | average += (static_cast(v) - average) / static_cast(num); 26 | num += 1; 27 | } 28 | 29 | void clear() { 30 | average = 0; 31 | min = std::numeric_limits::max(); 32 | max = std::numeric_limits::min(); 33 | num = 1; 34 | } 35 | }; 36 | } // namespace util 37 | 38 | } // namespace xstore 39 | -------------------------------------------------------------------------------- /deps/rlib/.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | before_script: 2 | - python -V # Print out python version for debugging 3 | - git config --global user.email "wxdwfc@gmail.com" 4 | - git config --global user.name "wxd" 5 | - git submodule sync 6 | - git submodule update --init 7 | 8 | # run tests using the binary built before 9 | build: 10 | stage: build 11 | tags: 12 | - rdma 13 | script: 14 | - cmake .; make ; 15 | 16 | test: 17 | stage: test 18 | tags: 19 | - rdma 20 | script: 21 | - cmake .; make coretest; ./coretest; 22 | 23 | example: 24 | stage : deploy 25 | tags: 26 | - rdma 27 | script: 28 | - cmake .; 29 | - make pclient; make pserver; 30 | - ./pserver & 31 | - ./pclient 32 | 33 | bench: 34 | stage : deploy 35 | tags: 36 | - rdma 37 | script: 38 | - cmake .; 39 | - make bench_client; make bench_server; 40 | 41 | 42 | -------------------------------------------------------------------------------- /xutils/dist_report.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../deps/r2/src/common.hh" 4 | 5 | namespace xstore { 6 | 7 | namespace util { 8 | 9 | using namespace r2; 10 | 11 | template class DistReport { 12 | public: 13 | double average = 0; 14 | T min; 15 | T max; 16 | u64 num = 1; 17 | 18 | DistReport() 19 | : min(std::numeric_limits::max()), max(std::numeric_limits::min()) { 20 | } 21 | 22 | void add(const T &v) { 23 | min = std::min(v, min); 24 | max = std::max(v, max); 25 | average += (static_cast(v) - average) / static_cast(num); 26 | num += 1; 27 | } 28 | 29 | void clear() { 30 | average = 0; 31 | min = std::numeric_limits::max(); 32 | max = std::numeric_limits::min(); 33 | num = 1; 34 | } 35 | }; 36 | 37 | } // namespace util 38 | 39 | } // namespace xstore 40 | -------------------------------------------------------------------------------- /benchs/statics.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "r2/src/common.hh" 4 | 5 | namespace rolex { 6 | 7 | namespace bench { 8 | 9 | using namespace r2; 10 | 11 | /*! 12 | * Statictics used for multi-thread reporting. 13 | * The structure is 128-byte padded and aligned to avoid false sharing. 14 | */ 15 | struct alignas(128) Statics 16 | { 17 | 18 | typedef struct 19 | { 20 | u64 counter = 0; 21 | u64 counter1 = 0; 22 | u64 counter2 = 0; 23 | u64 counter3 = 0; 24 | double lat = 0; 25 | 26 | double lat1 = 0; 27 | } data_t; 28 | data_t data; 29 | 30 | char pad[128 - sizeof(data)]; 31 | 32 | // methods 33 | void increment() { data.counter += 1; } 34 | 35 | void increment_gap_1(u64 d) { data.counter1 += d; } 36 | 37 | void set_lat(const double& l) { data.lat = l; } 38 | }; 39 | 40 | } // namespace bench 41 | 42 | } // namespace xstore 43 | -------------------------------------------------------------------------------- /xcomm/tests/test_async_local.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../src/atomic_rw/local_async_rw_op.hh" 4 | 5 | #include "./utils.hh" 6 | 7 | namespace test { 8 | 9 | using namespace xstore::xcomm::rw; 10 | 11 | TEST(Local, Async) { 12 | 13 | auto src_str = random_string(1024); 14 | auto dest_str = std::string(1024, '\0'); 15 | 16 | r2::MemBlock src((void *)src_str.data(), src_str.size()); 17 | r2::MemBlock dest((void *)dest_str.data(), dest_str.size()); 18 | 19 | SScheduler ssched; 20 | ssched.spawn([](R2_ASYNC) { 21 | // read src into dest 22 | 23 | //LocalRWOp().read(src, dest); 24 | 25 | R2_STOP(); 26 | R2_RET; 27 | }); 28 | 29 | ASSERT_EQ(0, dest_str.compare(src_str)); 30 | 31 | ssched.run(); 32 | } 33 | } 34 | 35 | int main(int argc, char **argv) { 36 | ::testing::InitGoogleTest(&argc, argv); 37 | return RUN_ALL_TESTS(); 38 | } 39 | -------------------------------------------------------------------------------- /deps/progress-cpp/example/src/example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "progresscpp/ProgressBar.hpp" 4 | 5 | /* Example usage of ProgressBar */ 6 | int main() { 7 | const int total = 10000; 8 | 9 | /* 10 | * Define a progress bar that has a total of 10000, 11 | * a width of 70, shows `#` to indicate completion 12 | * and a dash '-' for incomplete 13 | */ 14 | progresscpp::ProgressBar progressBar(total, 70, '#', '-'); 15 | 16 | for (int i = 0; i < total; i++) { 17 | ++progressBar; // record the tick 18 | 19 | usleep(200); // simulate work 20 | 21 | // display the bar only at certain steps 22 | if (i % 10 == 0) 23 | progressBar.display(); 24 | } 25 | 26 | // tell the bar to finish 27 | progressBar.done(); 28 | 29 | std::cout << "Done!" << std::endl; 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /deps/r2/src/allocator.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "jemalloc/jemalloc.h" 4 | 5 | #include "common.hh" 6 | 7 | namespace r2 8 | { 9 | 10 | using ptr_t = void *; 11 | 12 | class Allocator 13 | { 14 | public: 15 | explicit Allocator(unsigned id) : id(id) 16 | { 17 | } 18 | 19 | inline ptr_t alloc(u32 size, int flag = 0) 20 | { 21 | auto ptr = jemallocx(size, id | flag); 22 | return ptr; 23 | } 24 | 25 | inline void dealloc(ptr_t ptr) { free(ptr); } 26 | 27 | inline void free(ptr_t ptr) 28 | { 29 | /*! 30 | According to WenHao, using 0 is fine, because jemalloc will 31 | automatically free the memory to this thread's allocation. 32 | But according to my test, if using id has better scalability.d 33 | */ 34 | //jedallocx(ptr,0); 35 | jedallocx(ptr, id); 36 | } 37 | 38 | private: 39 | unsigned id; 40 | }; 41 | 42 | } // end namespace r2 43 | -------------------------------------------------------------------------------- /deps/rlib/tests/test_marshal.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../core/utils/marshal.hh" 4 | 5 | using namespace rdmaio; 6 | 7 | TEST(Marshal,basic) { 8 | 9 | // init the test buffer 10 | usize test_sz = 12; 11 | 12 | ByteBuffer test_buf = Marshal::alloc(test_sz); 13 | for(u8 i = 0;i < test_sz;++i) { 14 | //Marshal::safe_set_byte(test_buf,i,i); 15 | test_buf[i] = i; 16 | } 17 | 18 | auto res = Marshal::forward(test_buf, 0); 19 | usize count = 0; 20 | while(res && count < test_sz) { 21 | 22 | ASSERT_EQ(res.value()[0],count); 23 | count += 1; 24 | 25 | res = Marshal::forward(res.value(), 1); 26 | } 27 | ASSERT_EQ(count, test_sz); 28 | } 29 | 30 | 31 | TEST(Marshal,dedump) { 32 | u64 test_val = 73; 33 | ByteBuffer buf = Marshal::dump(test_val); 34 | auto dedumped_val = Marshal::dedump(buf).value(); 35 | ASSERT_EQ(dedumped_val,test_val); 36 | } 37 | -------------------------------------------------------------------------------- /xcomm/src/atomic_rw/rw_trait.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Result<> to record whether the op is done 4 | #include "../../../deps/rlib/core/result.hh" 5 | 6 | // Memblock, which abstract away a raw pointer 7 | #include "../../../deps/r2/src/mem_block.hh" 8 | 9 | namespace xstore { 10 | 11 | namespace xcomm { 12 | 13 | namespace rw { 14 | 15 | using namespace rdmaio; 16 | using namespace r2; 17 | 18 | // abstract interface 19 | template 20 | class ReadWriteTrait 21 | { 22 | public: 23 | // read content from src -> dest 24 | auto read(const MemBlock& src, const MemBlock& dest) -> Result<> 25 | { 26 | return static_cast(this)->read_impl(src, dest); 27 | } 28 | 29 | // write content from dest -> src 30 | auto write(const MemBlock& src, const MemBlock& dest) -> Result<> 31 | { 32 | return this->read(dest, src); 33 | } 34 | }; 35 | 36 | } 37 | } // namespace xcomm 38 | 39 | } // namespace xstore 40 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | 3 | # set(CMAKE_CXX_COMPILER "clang++") 4 | 5 | project(xxx) 6 | ADD_DEFINITIONS(-std=c++17) 7 | 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0") 9 | 10 | # directories 11 | include_directories("./") 12 | include_directories("deps") 13 | 14 | 15 | ## tests 16 | include(benchs/Rolex/tests/tests.cmake) 17 | enable_testing() 18 | 19 | add_test(NAME test COMMAND coretest) 20 | add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --verbose 21 | DEPENDS coretest ) 22 | 23 | 24 | set(LOG_SRC "./deps/r2/src/logging.cc" "./deps/r2/src/sshed.cc" "./benchs/terminate.cc") 25 | 26 | 27 | 28 | # rolex 29 | file(GLOB rolex_SORUCES "" "./benchs/Rolex/rolex.cc" "./deps/r2/src/logging.cc" "./deps/r2/src/sshed.cc" "./benchs/terminate.cc" ) 30 | add_executable(rolex ${rolex_SORUCES} ) 31 | target_link_libraries(rolex gflags ibverbs pthread boost_system boost_coroutine) 32 | -------------------------------------------------------------------------------- /xutils/spin_lock.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "./atomic.hh" 4 | 5 | #include "../deps/r2/src/common.hh" 6 | 7 | namespace xstore { 8 | 9 | namespace util { 10 | 11 | using namespace r2; 12 | 13 | inline auto cpu_relax() { asm volatile("pause\n" : : : "memory"); } 14 | 15 | struct SpinLock { 16 | // 0: free, 1: busy 17 | // occupy an exclusive cache line 18 | volatile u8 padding1[32]; 19 | volatile u16 lock_ = 0; 20 | volatile u8 padding2[32]; 21 | 22 | SpinLock() = default; 23 | 24 | inline void lock() { 25 | while (1) { 26 | if (!xchg16((u16 *)&lock_, 1)) 27 | return; 28 | 29 | while (lock_) 30 | cpu_relax(); 31 | } 32 | } 33 | 34 | inline void unlock() { 35 | compile_fence(); 36 | lock_ = 0; 37 | } 38 | 39 | inline u16 try_lock() { return xchg16((u16 *)&lock_, 1); } 40 | 41 | inline u16 is_locked() const { return lock_; } 42 | }; 43 | 44 | } // namespace util 45 | 46 | } // namespace xstore 47 | -------------------------------------------------------------------------------- /xutils/file_loader.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../deps/r2/src/common.hh" 8 | 9 | /*! 10 | load keys from a file 11 | */ 12 | 13 | namespace xstore { 14 | 15 | struct FileLoader 16 | { 17 | std::ifstream file; 18 | 19 | explicit FileLoader(const std::string& name) 20 | : file(name) 21 | {} 22 | 23 | template 24 | auto next_key(std::function converter) 25 | -> ::r2::Option 26 | { 27 | std::string line; 28 | if (std::getline(file, line)) { 29 | return converter(line); 30 | } 31 | return {}; 32 | } 33 | 34 | template 35 | static auto default_converter(const std::string& s) -> KeyType 36 | { 37 | KeyType ret; 38 | std::istringstream iss(s); 39 | iss >> ret; 40 | return ret; 41 | } 42 | 43 | ~FileLoader() { file.close(); } 44 | }; 45 | 46 | } // namespace xstore 47 | -------------------------------------------------------------------------------- /xutils/local_barrier.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef __APPLE__ // OSX does not provide pthread barrier 4 | #include 5 | #include 6 | #endif 7 | 8 | #include "../deps/r2/src/common.hh" 9 | 10 | namespace xstore { 11 | 12 | namespace util { 13 | 14 | /** 15 | * a simple wrapper over pthread 16 | */ 17 | class PBarrier { 18 | pthread_barrier_t barrier_; 19 | std::atomic wait_num_; 20 | 21 | public: 22 | explicit PBarrier(int num) : wait_num_(num) { 23 | ASSERT(num > 0); 24 | pthread_barrier_init(&barrier_, nullptr, num); 25 | } 26 | 27 | ~PBarrier() { pthread_barrier_destroy(&barrier_); } 28 | 29 | void wait() { 30 | wait_num_ -= 1; 31 | pthread_barrier_wait(&barrier_); 32 | } 33 | 34 | void done() { wait_num_ -= 1; } 35 | 36 | bool ready() const { return wait_num_ == 0; } 37 | 38 | int wait_num() const { return wait_num_; } 39 | 40 | DISABLE_COPY_AND_ASSIGN(PBarrier); 41 | }; 42 | 43 | } // namespace util 44 | 45 | } // namespace xstore 46 | 47 | -------------------------------------------------------------------------------- /deps/r2/src/ring_msg/id_helper.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../common.hh" 4 | 5 | namespace r2 { 6 | 7 | namespace ring_msg { 8 | 9 | using id_t = u16; 10 | using sz_t = u16; 11 | 12 | class IDEncoder { 13 | public: 14 | static u32 encode_id_sz(const id_t &id, const sz_t &sz) { 15 | u32 base = static_cast(id); 16 | return base << 16 | sz; 17 | } 18 | }; 19 | 20 | /** 21 | * This nice piece of code comes from 22 | * https://stackoverflow.com/questions/1392059/algorithm-to-generate-bit-mask 23 | */ 24 | template static constexpr R bitmask(unsigned int const onecount) { 25 | return static_cast(-(onecount != 0)) & 26 | (static_cast(-1) >> ((sizeof(R) * CHAR_BIT) - onecount)); 27 | } 28 | 29 | class IDDecoder { 30 | public: 31 | static std::pair decode(const usize &val) { 32 | usize sz_mask = bitmask(16); 33 | return std::make_pair(val >> 16, sz_mask & val); 34 | } 35 | }; 36 | 37 | } // namespace ring_msg 38 | } // namespace r2 39 | -------------------------------------------------------------------------------- /benchs/arc/val/net_config.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.hpp" // fstore's common 4 | 5 | namespace fstore { 6 | 7 | namespace platforms { 8 | 9 | /*! 10 | \Note: This file is only used for temporal usage, 11 | which choose the corresponding RDMA nic device on our VAL cluster. 12 | This is because each VAL machine has multiple nics, 13 | choosing the appropriate NIC is essential to the performance. 14 | 15 | Here is our detailed NIC configuration: 16 | - 24 cores, 2 CX4 NIC. 17 | 18 | The user must provide its corresponding NIC choosing logic for better 19 | performance. 20 | */ 21 | class VALNic 22 | { 23 | public: 24 | static const int core_per_socket = 12; 25 | 26 | static u32 choose_nic(u32 tid) 27 | { 28 | if (tid >= core_per_socket) { 29 | /* 30 | * using the first NIC for the thread with id 12-23, 31 | * this choice is based on our evaluations. 32 | */ 33 | return 1; 34 | } 35 | return 0; 36 | } 37 | }; 38 | 39 | } // end namespace platform 40 | 41 | } 42 | -------------------------------------------------------------------------------- /deps/rlib/examples/exp.cmake: -------------------------------------------------------------------------------- 1 | 2 | 3 | add_executable(pclient "${CMAKE_SOURCE_DIR}/examples/rc_pingpong/client.cc") 4 | add_executable(pserver "${CMAKE_SOURCE_DIR}/examples/rc_pingpong/server.cc") 5 | 6 | add_executable(uclient "${CMAKE_SOURCE_DIR}/examples/ud_pingpong/client.cc") 7 | add_executable(userver "${CMAKE_SOURCE_DIR}/examples/ud_pingpong/server.cc") 8 | 9 | add_executable(wclient "${CMAKE_SOURCE_DIR}/examples/rc_write/client.cc") 10 | add_executable(wserver "${CMAKE_SOURCE_DIR}/examples/rc_write/server.cc") 11 | 12 | add_executable(uoclient "${CMAKE_SOURCE_DIR}/examples/ud_overflow/client.cc") 13 | add_executable(uoserver "${CMAKE_SOURCE_DIR}/examples/ud_overflow/server.cc") 14 | 15 | add_executable(roclient "${CMAKE_SOURCE_DIR}/examples/rc_overflow/client.cc") 16 | add_executable(roserver "${CMAKE_SOURCE_DIR}/examples/rc_overflow/server.cc") 17 | 18 | set(exps 19 | pclient pserver 20 | uclient userver 21 | uoclient uoserver 22 | roclient roserver 23 | wserver wclient) 24 | 25 | foreach(e ${exps}) 26 | target_link_libraries(${e} pthread ibverbs gflags) 27 | endforeach(e) 28 | -------------------------------------------------------------------------------- /rolex/rolex_util.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | namespace rolex { 8 | 9 | 10 | 11 | // preserve 2M space for upper models, which accommodates 131,072 models 12 | constexpr uint64_t kUpperModel = 32 * 1024 * 1024; 13 | 14 | 15 | // ====== for binary search ========= 16 | #define FORCEINLINE __attribute__((always_inline)) inline 17 | // power of 2 at most x, undefined for x == 0 18 | FORCEINLINE uint32_t bsr(uint32_t x) { 19 | return 31 - __builtin_clz(x); 20 | } 21 | 22 | template 23 | static int binary_search_branchless(const KEY_TYPE *arr, int n, KEY_TYPE key) { 24 | //static int binary_search_branchless(const int *arr, int n, int key) { 25 | intptr_t pos = -1; 26 | intptr_t logstep = bsr(n - 1); 27 | intptr_t step = intptr_t(1) << logstep; 28 | 29 | pos = (arr[pos + n - step] < key ? pos + n - step : pos); 30 | step >>= 1; 31 | 32 | while (step > 0) { 33 | pos = (arr[pos + step] < key ? pos + step : pos); 34 | step >>= 1; 35 | } 36 | pos += 1; 37 | 38 | return (int) (arr[pos] >= key ? pos : n); 39 | } 40 | 41 | 42 | 43 | } // namespace rolex -------------------------------------------------------------------------------- /deps/r2/benchs/mem_region.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../deps/rlib/core/lib.hh" 4 | 5 | #include "../src/common.hh" 6 | 7 | namespace r2 { 8 | 9 | namespace bench { 10 | 11 | using namespace rdmaio; 12 | 13 | struct MemoryRegion { 14 | u64 sz; // total region size 15 | 16 | void *addr = nullptr; // region 17 | 18 | void *start_ptr() const { return addr; } 19 | 20 | u64 size() const { return sz; } 21 | 22 | MemoryRegion() = default; 23 | 24 | MemoryRegion(const u64 &sz, void *addr) : sz(sz), addr(addr) {} 25 | 26 | virtual bool valid() { return addr != nullptr; } 27 | 28 | ::rdmaio::Option> convert_to_rmem() { 29 | if (!valid()) 30 | return {}; 31 | return std::make_shared( 32 | sz, [this](u64 s) { return addr; }, [](rmem::RMem::raw_ptr_t p) {}); 33 | } 34 | }; 35 | 36 | class DRAMRegion : public MemoryRegion { 37 | public: 38 | explicit DRAMRegion(const u64 &sz) : MemoryRegion(sz, new char[sz]) {} 39 | 40 | static ::rdmaio::Option> create(const u64 &sz) { 41 | return std::make_shared(sz); 42 | } 43 | }; 44 | } // namespace bench 45 | 46 | } // namespace r2 47 | -------------------------------------------------------------------------------- /deps/progress-cpp/LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2016 Prakhar Srivastav 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /deps/r2/src/rpc/rpc_data.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../msg/protocol.hpp" 4 | 5 | namespace r2 { 6 | 7 | namespace rpc { 8 | 9 | enum MsgType { 10 | REQ = 1, // RPC request 11 | REPLY // RPC reply 12 | }; 13 | 14 | /** 15 | * RPC request structure 16 | */ 17 | class Req { 18 | public: 19 | struct __attribute__((packed)) Meta { 20 | u8 cor_id; 21 | Addr dest; 22 | }; 23 | 24 | struct Arg { 25 | const char *send_buf = nullptr; 26 | u32 len = 0; 27 | char *reply_buf = nullptr; 28 | u32 reply_cnt = 0; 29 | }; 30 | 31 | // internal data structures used in RPC 32 | struct __attribute__ ((packed)) Header { 33 | u32 type : 2; 34 | u32 rpc_id : 5; 35 | u32 payload : 18; 36 | u32 cor_id : 7; 37 | } __attribute__ ((aligned (sizeof(u64)))); 38 | 39 | public: 40 | static int sizeof_header(void) { 41 | return sizeof(Header); 42 | } 43 | }; // end class RPC data 44 | 45 | /** 46 | * record the pending reply structures 47 | */ 48 | struct Reply { 49 | char *reply_buf = nullptr; 50 | int reply_count = 0; 51 | }; 52 | 53 | } // end namespace rpc 54 | 55 | } // end namespace r2 56 | -------------------------------------------------------------------------------- /xcomm/src/rpc/proto.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../../../deps/r2/src/common.hh" 6 | 7 | /*! 8 | This file defines common RPC exchange data structures 9 | */ 10 | 11 | namespace xstore { 12 | 13 | namespace rpc { 14 | 15 | using namespace r2; 16 | 17 | /*! 18 | Define the msg type that can be exchanged 19 | */ 20 | enum MsgType { 21 | Req = 1, // RPC request 22 | Reply = 2, // RPC reply 23 | Connect = 3, // msg connect 24 | }; 25 | 26 | /*! 27 | Abstract the end-point of Addr 28 | */ 29 | struct __attribute__((packed)) Addr { 30 | u32 mac_id : 16; 31 | u32 thread_id : 16; 32 | }; 33 | 34 | struct __attribute__((packed)) Meta { 35 | u8 cor_id; 36 | Addr dest; 37 | }; 38 | 39 | struct __attribute__((packed)) Header { 40 | u32 type : 2; 41 | u32 rpc_id : 5; 42 | u32 payload : 18; 43 | u32 cor_id : 7; 44 | 45 | friend std::ostream &operator<<(std::ostream &os, const Header &h) { 46 | os << "type:" << h.type << "; rpc_id: " << h.rpc_id << "; payload:" << h.payload 47 | << " cor_id: " << h.cor_id; 48 | } 49 | } __attribute__((aligned(sizeof(u64)))); 50 | 51 | } // namespace rpc 52 | 53 | } // namespace xstore 54 | -------------------------------------------------------------------------------- /rolex/memory_region.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // use some utilities (i.e., Option) defined in RLib 4 | #include "rlib/core/common.hh" 5 | #include "rlib/core/rmem/mem.hh" 6 | 7 | namespace rolex { 8 | 9 | using namespace rdmaio; 10 | 11 | struct MemoryRegion { 12 | u64 sz; // total region size 13 | 14 | void *addr = nullptr; // region 15 | 16 | void *start_ptr() const { return addr; } 17 | 18 | u64 size() const { return sz; } 19 | 20 | MemoryRegion() = default; 21 | 22 | MemoryRegion(const u64 &sz, void *addr) : sz(sz), addr(addr) {} 23 | 24 | virtual bool valid() { return addr != nullptr; } 25 | 26 | ::rdmaio::Option> convert_to_rmem() { 27 | if (!valid()) 28 | return {}; 29 | return std::make_shared(sz, [this](u64 s) { return addr; }, 30 | [](rmem::RMem::raw_ptr_t p) {}); 31 | } 32 | }; 33 | 34 | class DRAMRegion : public MemoryRegion { 35 | public: 36 | explicit DRAMRegion(const u64 &sz) : MemoryRegion(sz, new char[sz]) {} 37 | 38 | static ::rdmaio::Option> create(const u64 &sz) { 39 | return std::make_shared(sz); 40 | } 41 | }; 42 | 43 | } // namespace rolex 44 | -------------------------------------------------------------------------------- /xutils/memory_region.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // use some utilities (i.e., Option) defined in RLib 4 | #include "../deps/rlib/core/common.hh" 5 | #include "../deps/rlib/core/rmem/mem.hh" 6 | 7 | namespace xstore { 8 | 9 | namespace util { 10 | 11 | using namespace rdmaio; 12 | 13 | struct MemoryRegion { 14 | u64 sz; // total region size 15 | 16 | void *addr = nullptr; // region 17 | 18 | void *start_ptr() const { return addr; } 19 | 20 | u64 size() const { return sz; } 21 | 22 | MemoryRegion() = default; 23 | 24 | MemoryRegion(const u64 &sz, void *addr) : sz(sz), addr(addr) {} 25 | 26 | virtual bool valid() { return addr != nullptr; } 27 | 28 | ::rdmaio::Option> convert_to_rmem() { 29 | if (!valid()) 30 | return {}; 31 | return std::make_shared(sz, [this](u64 s) { return addr; }, 32 | [](rmem::RMem::raw_ptr_t p) {}); 33 | } 34 | }; 35 | 36 | class DRAMRegion : public MemoryRegion { 37 | public: 38 | explicit DRAMRegion(const u64 &sz) : MemoryRegion(sz, new char[sz]) {} 39 | 40 | static ::rdmaio::Option> create(const u64 &sz) { 41 | return std::make_shared(sz); 42 | } 43 | }; 44 | } // namespace util 45 | } // namespace xstore 46 | -------------------------------------------------------------------------------- /deps/r2/src/ring_msg/recv_bundler.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "rlib/core/qps/rc.hh" 4 | #include "rlib/core/qps/recv_helper.hh" 5 | 6 | #include "../mem_block.hh" 7 | 8 | #include "./session.hh" 9 | 10 | namespace r2 { 11 | 12 | namespace ring_msg { 13 | 14 | using namespace rdmaio; 15 | using namespace rdmaio::qp; 16 | 17 | template class RecvBundler { 18 | // structure for post_recvs 19 | usize idle_recv_entries = 0; 20 | 21 | public: 22 | Arc> recv_entries; 23 | 24 | explicit RecvBundler(Arc &alloc_p) 25 | : recv_entries(RecvEntriesFactoryv2::create(alloc_p, 0)) {} 26 | 27 | explicit RecvBundler(Arc> ent) : recv_entries(ent) {} 28 | 29 | Result consume_one(Arc &qp) { 30 | 31 | const usize poll_recv_step = R / 2; 32 | //const usize poll_recv_step = 32; 33 | static_assert(poll_recv_step > 0, ""); 34 | 35 | idle_recv_entries += 1; 36 | if (idle_recv_entries >= poll_recv_step) { 37 | auto ret = qp->post_recvs(*recv_entries, idle_recv_entries); 38 | ASSERT(ret == IOCode::Ok); 39 | idle_recv_entries = 0; 40 | return ret; 41 | } 42 | return ::rdmaio::Ok(0); 43 | } 44 | }; 45 | 46 | } // namespace ring_msg 47 | } // namespace r2 48 | -------------------------------------------------------------------------------- /xcomm/src/atomic_rw/rdma_async_rw_op.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "./async_rw_trait.hh" 4 | 5 | #include "../../../deps/r2/src/rdma/async_op.hh" 6 | 7 | namespace xstore { 8 | 9 | namespace xcomm { 10 | 11 | namespace rw { 12 | 13 | using namespace r2::rdma; 14 | using namespace rdmaio; 15 | 16 | class AsyncRDMARWOp : public AsyncReadWriteTrait { 17 | AsyncOp<1> op; 18 | Arc qp; 19 | public: 20 | explicit AsyncRDMARWOp(Arc qp) : qp(qp) {} 21 | /*! 22 | In an RDMA context, the src buf ptr is a remote addr that can be 23 | passed tp r2::rdma::SROp. Basically, it is a wrapper over SROp, 24 | implemented ReadWriteTrait. 25 | */ 26 | auto read_impl(const MemBlock &src, const MemBlock &dest, R2_ASYNC) -> Result<> { 27 | 28 | if (unlikely(src.sz > dest.sz)) { 29 | // size not match 30 | return ::rdmaio::Err(); 31 | } 32 | op.set_rdma_addr(reinterpret_cast(src.mem_ptr), qp->remote_mr.value()) 33 | .set_read() 34 | .set_payload(static_cast(dest.mem_ptr), dest.sz, 35 | qp->local_mr.value().lkey); 36 | 37 | auto ret = op.execute_async(this->qp, IBV_SEND_SIGNALED, R2_ASYNC_WAIT); 38 | return ::rdmaio::transfer_raw(ret); 39 | } 40 | }; 41 | } // namespace rw 42 | } // namespace xcomm 43 | } // namespace xstore 44 | -------------------------------------------------------------------------------- /rolex/local_allocator.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "rlib/core/rmem/handler.hh" 4 | #include "rlib/core/common.hh" 5 | 6 | 7 | 8 | using namespace rdmaio; 9 | using namespace rdmaio::rmem; 10 | 11 | namespace rolex { 12 | 13 | 14 | class LocalAllocator { 15 | 16 | private: 17 | RMem::raw_ptr_t buf = nullptr; 18 | usize total_mem = 0; 19 | mr_key_t key; 20 | RegAttr mr; 21 | 22 | usize cur_alloc_off = 0; 23 | 24 | // preserve for leaf reading 25 | usize leaf_buf_off = 0; 26 | 27 | public: 28 | LocalAllocator(rdmaio::Arc mem, const RegAttr &mr) 29 | : buf(mem->raw_ptr), total_mem(mem->sz), mr(mr), key(mr.key), cur_alloc_off(0) { 30 | // RDMA_LOG(4) << "simple allocator use key: " << key; 31 | } 32 | 33 | void reset_for_leaf(const usize leaf_buf_size) { 34 | leaf_buf_off = 0; 35 | cur_alloc_off = leaf_buf_size; 36 | } 37 | 38 | auto get_leaf_buf() -> rmem::RMem::raw_ptr_t { 39 | return static_cast(buf) + leaf_buf_off; 40 | } 41 | 42 | auto alloc(const usize &sz) -> rmem::RMem::raw_ptr_t { 43 | if(cur_alloc_off+sz > total_mem) { 44 | ASSERT(false) << "Local Allocator too small."; 45 | } 46 | auto ret = static_cast(buf) + cur_alloc_off; 47 | cur_alloc_off += sz; 48 | return ret; 49 | } 50 | 51 | 52 | 53 | }; 54 | 55 | 56 | } // namespace rolex -------------------------------------------------------------------------------- /deps/rlib/core/common.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * This file provides common utilities and definiation of RLib 3 | */ 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "./utils/logging.hh" 13 | #include "./utils/option.hh" 14 | 15 | #include "./result.hh" 16 | 17 | namespace rdmaio { 18 | 19 | // some handy integer defines 20 | using u64 = uint64_t; 21 | using u32 = uint32_t; 22 | using u16 = uint16_t; 23 | using i64 = int64_t; 24 | using u8 = uint8_t; 25 | using i8 = int8_t; 26 | using usize = unsigned int; 27 | 28 | // some handy alias for smart pointer 29 | template 30 | using Arc = std::shared_ptr; 31 | 32 | #ifndef DISABLE_COPY_AND_ASSIGN 33 | #define DISABLE_COPY_AND_ASSIGN(classname) \ 34 | private: \ 35 | classname(const classname &) = delete; \ 36 | classname &operator=(const classname &) = delete 37 | #endif 38 | 39 | #ifndef unlikely 40 | #define unlikely(x) __builtin_expect(!!(x), 0) 41 | #endif 42 | 43 | #ifndef likely 44 | #define likely(x) __builtin_expect(!!(x), 1) 45 | #endif 46 | 47 | static inline void compile_fence(void) { asm volatile("" ::: "memory"); } 48 | 49 | } // namespace rdmaio 50 | -------------------------------------------------------------------------------- /deps/rlib/tests/test_rpc.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../core/bootstrap/srpc.hh" 4 | 5 | namespace test { 6 | 7 | using namespace rdmaio; 8 | using namespace rdmaio::bootstrap; 9 | 10 | TEST(RPC, Basic) { 11 | 12 | SRpc rpc("localhost:1111"); 13 | SRpcHandler handler(1111); 14 | 15 | for (uint i = 0; i < 12; ++i) { 16 | handler.register_handler(73 + i, [i](const ByteBuffer &b) -> ByteBuffer { 17 | RDMA_ASSERT(b.size() == i + 233) 18 | << "recv sz: " << b.size() << "; compare:" << 233 + i; 19 | RDMA_ASSERT(b.compare(ByteBuffer(i + 233, '3' + i)) == 0); 20 | return ByteBuffer(73 + i, '1' + i); 21 | }); 22 | } 23 | 24 | for (uint i = 0; i < 12; ++i) { 25 | 26 | // send the rpc 27 | auto res = rpc.call(73 + i, ByteBuffer(233 + i, '3' + i)); 28 | RDMA_ASSERT(res == IOCode::Ok) << "call error: " << res.desc; 29 | 30 | // wait for enough time so the msg must arrive at the target 31 | sleep(1); 32 | 33 | auto rpc_calls = handler.run_one_event_loop(); 34 | ASSERT_EQ(rpc_calls, 1); 35 | 36 | // wait for enough time so the reply must arrive at the sender 37 | sleep(1); 38 | 39 | auto res_reply = rpc.receive_reply(); 40 | RDMA_ASSERT(res_reply == IOCode::Ok); 41 | 42 | ASSERT_EQ(res_reply.desc.size(), 73 + i); 43 | } 44 | } 45 | 46 | } // namespace test 47 | -------------------------------------------------------------------------------- /xcomm/src/atomic_rw/unwrapper_type.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../../deps/r2/src/common.hh" 4 | #include "./rw_trait.hh" 5 | 6 | namespace xstore { 7 | 8 | namespace xcomm { 9 | 10 | namespace rw { 11 | 12 | using namespace r2; 13 | 14 | /*! 15 | The unwrapped type assumes that sizeof(T) <= 8, such that 16 | we can atomically read it wihtout using seq techniques. 17 | 18 | This class merely prevides similar interfaces as Wrappedtype 19 | */ 20 | template struct __attribute__((packed)) UWrappedType { 21 | static_assert(sizeof(T) <= sizeof(u64), " T too large!"); 22 | // when the seq equals invalid seq, then it is being written 23 | T payload; 24 | UWrappedType(const T &p) : payload(p) {} 25 | 26 | void init() {} 27 | 28 | /*! 29 | reset the content of the wrapped type 30 | */ 31 | void reset(const T &t) { 32 | this->init(); 33 | this->payload = t; 34 | } 35 | 36 | T &get_payload() { return payload; } 37 | 38 | // sz of the meta data, namely, two seqs 39 | static auto meta_sz() -> usize { return 0; } 40 | 41 | inline bool consistent() const { return true; } 42 | 43 | /* 44 | */ 45 | inline void begin_write() {} 46 | 47 | inline void done_write() {} 48 | 49 | } __attribute__((aligned(sizeof(u64)))); 50 | 51 | } // namespace rw 52 | } // namespace xcomm 53 | } // namespace xstore 54 | -------------------------------------------------------------------------------- /deps/rlib/core/utils/timer.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace rdmaio { 6 | 7 | /** 8 | * a simple wrapper over std::time API 9 | */ 10 | class Timer { 11 | std::chrono::time_point start_time_; 12 | 13 | public: 14 | static constexpr double no_timeout() { 15 | return std::numeric_limits::max(); 16 | } 17 | 18 | Timer(std::chrono::time_point t = 19 | std::chrono::steady_clock::now()) 20 | : start_time_(t) {} 21 | 22 | ~Timer() = default; 23 | 24 | template bool timeout(double count) const { 25 | return passed() >= count; 26 | } 27 | 28 | double passed_sec() const { return passed(); } 29 | 30 | double passed_msec() const { return passed(); } 31 | 32 | template double passed() const { 33 | return passed(std::chrono::steady_clock::now()); 34 | } 35 | 36 | template 37 | double passed(std::chrono::time_point tt) const { 38 | const auto elapsed = std::chrono::duration_cast(tt - start_time_); 39 | return elapsed.count(); 40 | } 41 | 42 | void reset() { start_time_ = std::chrono::steady_clock::now(); } 43 | 44 | Timer &operator=(Timer &) = default; 45 | }; 46 | 47 | } // namespace rdmaio 48 | -------------------------------------------------------------------------------- /deps/rlib/core/nicinfo.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "nic.hh" 6 | 7 | namespace rdmaio { 8 | 9 | class RNicInfo { 10 | public: 11 | /*! 12 | Query all available RNic on the host machine. 13 | Return a vector of all their index used by RLib, 14 | so one can open a device handler using RNic, as follows: 15 | ` 16 | auto dev_idxs = RNicInfo::query_dev_names(); 17 | if(dev_idxs.size() > 0) { 18 | RNic nic(dev_idxs[0]); 19 | } 20 | ` 21 | */ 22 | static std::vector query_dev_names() { 23 | 24 | std::vector res; 25 | 26 | int num_devices; 27 | struct ibv_device **dev_list = ibv_get_device_list(&num_devices); 28 | 29 | for (uint i = 0; i < num_devices; ++i) { 30 | RNic rnic({.dev_id = i, .port_id = 73 /* a dummy value*/}); 31 | if (rnic.valid()) { 32 | ibv_device_attr attr; 33 | auto rc = ibv_query_device(rnic.get_ctx(), &attr); 34 | 35 | if (rc) 36 | continue; 37 | for (uint port_id = 1; port_id <= attr.phys_port_cnt; ++port_id) { 38 | res.push_back({.dev_id = i, .port_id = port_id}); 39 | } 40 | } else 41 | RDMA_ASSERT(false); 42 | } 43 | if (dev_list != nullptr) 44 | ibv_free_device_list(dev_list); 45 | return res; 46 | } 47 | }; // end class RNicInfo 48 | 49 | } // namespace rdmaio 50 | -------------------------------------------------------------------------------- /deps/r2/src/timer.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace r2 { 6 | /** 7 | * a simple wrapper over std::time API 8 | */ 9 | class Timer { 10 | public: 11 | static const constexpr double no_timeout = std::numeric_limits::max(); 12 | 13 | Timer(std::chrono::time_point t = std::chrono::steady_clock::now()) 14 | : start_time_(t) { 15 | } 16 | 17 | ~Timer() = default; 18 | 19 | template 20 | bool timeout(double count) const { 21 | return passed() >= count; 22 | } 23 | 24 | double passed_sec() const { 25 | return passed(); 26 | } 27 | 28 | double passed_msec() const { 29 | return passed(); 30 | } 31 | 32 | template double passed() const { 33 | return passed(std::chrono::steady_clock::now()); 34 | } 35 | 36 | template double 37 | passed(std::chrono::time_point tt) const { 38 | const auto elapsed = std::chrono::duration_cast( 39 | tt - start_time_); 40 | return elapsed.count(); 41 | } 42 | 43 | void reset() { 44 | start_time_ = std::chrono::steady_clock::now(); 45 | } 46 | 47 | Timer& operator=(Timer&) = default; 48 | private: 49 | std::chrono::time_point start_time_; 50 | }; 51 | 52 | } // end namespace r2 53 | -------------------------------------------------------------------------------- /deps/r2/benchs/huge_region.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "./mem_region.hh" 6 | 7 | namespace r2 { 8 | 9 | namespace bench { 10 | 11 | class HugeRegion : public MemoryRegion { 12 | static u64 align_to_sz(const u64 &x, const usize &align_sz) { 13 | return (((x) + align_sz - 1) / align_sz * align_sz); 14 | } 15 | 16 | public: 17 | static ::rdmaio::Option> 18 | create(const u64 &sz, const usize &align_sz = (2 << 20)) { 19 | auto region = std::make_shared(sz, align_sz); 20 | if (region->valid()) 21 | return region; 22 | return {}; 23 | } 24 | 25 | explicit HugeRegion(const u64 &sz, const usize &align_sz = (2 << 20)) { 26 | 27 | this->sz = align_to_sz(sz + align_sz, align_sz); 28 | char *ptr = (char *)mmap( 29 | nullptr, this->sz, PROT_READ | PROT_WRITE, 30 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE | MAP_HUGETLB, -1, 0); 31 | 32 | if (ptr == MAP_FAILED) { 33 | this->addr = nullptr; 34 | RDMA_LOG(4) << "error allocating huge page wiht sz: " << this->sz 35 | << " aligned with: " << align_sz 36 | << "; with error: " << strerror(errno); 37 | } else { 38 | // RDMA_LOG(4) << "alloc huge page size: " << this->sz; 39 | this->addr = ptr; 40 | } 41 | } 42 | }; 43 | 44 | 45 | } // namespace bench 46 | 47 | } // namespace r2 48 | -------------------------------------------------------------------------------- /deps/r2/src/routine.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // R2 coroutine is a wrapper over boost asymmetric coroutine 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "rlib/core/result.hh" 10 | 11 | #include "./common.hh" 12 | #include "./linked_list.hh" 13 | 14 | namespace r2 { 15 | 16 | using namespace rdmaio; 17 | 18 | using yield_f = boost::coroutines::symmetric_coroutine::yield_type; 19 | using b_coroutine_f = boost::coroutines::symmetric_coroutine::call_type; 20 | 21 | /*! 22 | Exposed to user, a routine function is just void -> void 23 | */ 24 | using routine_func_t = std::function; 25 | 26 | class Routine { 27 | public: 28 | using id_t = u8; 29 | 30 | const id_t id; 31 | 32 | std::shared_ptr raw_f; 33 | 34 | b_coroutine_f *core; 35 | 36 | Result<> status; 37 | 38 | bool active = false; 39 | 40 | Routine(const id_t &id, std::shared_ptr f) 41 | : id(id), raw_f(f), core(new b_coroutine_f(*f)), status(::rdmaio::Ok()) { 42 | // 43 | } 44 | 45 | ~Routine() { 46 | // maybe we should not delete this core 47 | // because other coroutines may have reference to it 48 | //delete core; 49 | } 50 | 51 | inline void execute(yield_f &yield) { 52 | active = true; 53 | yield(*core); 54 | } 55 | 56 | void start() { (*core)(); } 57 | }; 58 | } // namespace r2 59 | -------------------------------------------------------------------------------- /deps/r2/README.md: -------------------------------------------------------------------------------- 1 | R2 is a communication library over RDMA, which aimes at fast and easy use of RDMA. 2 | It is built over `ibverbs`, with minimal dependencies. 3 | It provides several new abstractions for easier use of RDMA, 4 | such as high-performance messaging primitives, lightweight async one-sided RDMA operations 5 | using corotuines. 6 | R2 is well-tuned to achieved the best-possible performance with minimal overhead due to better abstractions. 7 | It is part of **DrTM+H**, a high performance experimantal transactional engine using RDMA. 8 | 9 | 10 | ## License 11 | 12 | R2 is released under the [Apache 2.0 license](http://www.apache.org/licenses/LICENSE-2.0.html). 13 | 14 | As R2 is the refined execution framework of DrTM+H, 15 | if you use R2 in your research, please cite our paper: 16 | 17 | @inproceedings {drtmhosdi18, 18 | author = {Xingda Wei and Zhiyuan Dong and Rong Chen and Haibo Chen}, 19 | title = {Deconstructing RDMA-enabled Distributed Transactions: Hybrid is Better!}, 20 | booktitle = {13th {USENIX} Symposium on Operating Systems Design and Implementation ({OSDI} 18)}, 21 | year = {2018}, 22 | isbn = {978-1-939133-08-3}, 23 | address = {Carlsbad, CA}, 24 | pages = {233--251}, 25 | url = {https://www.usenix.org/conference/osdi18/presentation/wei}, 26 | publisher = {{USENIX} Association}, 27 | month = oct, 28 | } 29 | -------------------------------------------------------------------------------- /xcomm/src/atomic_rw/rdma_rw_op.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "./rw_trait.hh" 4 | 5 | #include "../../../deps/r2/src/rdma/async_op.hh" 6 | 7 | namespace xstore { 8 | 9 | namespace xcomm { 10 | 11 | namespace rw { 12 | 13 | using namespace r2::rdma; 14 | using namespace rdmaio; 15 | 16 | class RDMARWOp : public ReadWriteTrait { 17 | AsyncOp<1> op; 18 | Arc qp; 19 | public: 20 | explicit RDMARWOp(Arc qp) : qp(qp) {} 21 | /*! 22 | In an RDMA context, the src buf ptr is a remote addr that can be 23 | passed tp r2::rdma::SROp. Basically, it is a wrapper over SROp, 24 | implemented ReadWriteTrait. 25 | */ 26 | auto read_impl(const MemBlock &src, const MemBlock &dest) -> Result<> { 27 | 28 | if (unlikely(src.sz > dest.sz)) { 29 | // size not match 30 | return ::rdmaio::Err(); 31 | } 32 | 33 | op.set_rdma_addr(reinterpret_cast(src.mem_ptr), qp->remote_mr.value()) 34 | .set_read() 35 | .set_payload(static_cast(dest.mem_ptr), dest.sz, 36 | qp->local_mr.value().lkey); 37 | 38 | auto ret = op.execute(this->qp, IBV_SEND_SIGNALED); 39 | if (unlikely(ret != IOCode::Ok)) { 40 | return ::rdmaio::transfer_raw(ret); 41 | } 42 | auto res_p = qp->wait_one_comp(); 43 | return ::rdmaio::transfer_raw(res_p); 44 | } 45 | }; 46 | } // namespace rw 47 | } // namespace xcomm 48 | } // namespace xstore 49 | -------------------------------------------------------------------------------- /rolex/huge_region.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "memory_region.hh" 6 | 7 | namespace rolex { 8 | 9 | using namespace rdmaio; 10 | 11 | /*! 12 | Malloc huge pages in 2M huge pages, align_sz = 2M 13 | */ 14 | class HugeRegion : public MemoryRegion { 15 | static u64 align_to_sz(const u64 &x, const usize &align_sz) { 16 | return (((x) + align_sz - 1) / align_sz * align_sz); 17 | } 18 | 19 | public: 20 | static ::rdmaio::Option> 21 | create(const u64 &sz, const usize &align_sz = (2 << 20)) { 22 | auto region = std::make_shared(sz, align_sz); 23 | if (region->valid()) 24 | return region; 25 | return {}; 26 | } 27 | 28 | explicit HugeRegion(const u64 &sz, const usize &align_sz = (2 << 20)) { 29 | 30 | this->sz = align_to_sz(sz, align_sz); 31 | char *ptr = (char *)mmap( 32 | nullptr, this->sz, PROT_READ | PROT_WRITE, 33 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE | MAP_HUGETLB, -1, 0); 34 | 35 | if (ptr == MAP_FAILED) { 36 | this->addr = nullptr; 37 | RDMA_LOG(4) << "error allocating huge page wiht sz: " << this->sz 38 | << " aligned with: " << align_sz 39 | << "; with error: " << strerror(errno); 40 | } else { 41 | RDMA_LOG(4) << "alloc huge page size: " << this->sz << ", "<sz/align_sz<<" * 2M"; 42 | this->addr = ptr; 43 | } 44 | } 45 | }; 46 | 47 | } // namespace rolex 48 | 49 | -------------------------------------------------------------------------------- /deps/rlib/core/rmem/mem.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "../common.hh" 7 | 8 | namespace rdmaio { 9 | 10 | namespace rmem { 11 | 12 | /*! 13 | An abstract memory handler of registered RDMA memory 14 | usage: 15 | auto mem = Arc(1024); 16 | assert(mem->valid()); 17 | 18 | RNic rnic(...); 19 | // then use it to register a handler 20 | RegHandler reg(mem,rnic); 21 | Option attr = reg.get_reg_attr(); 22 | 23 | Note, we recommend to use Arc for RegHandler and RNic, 24 | so that resources can be automatically freed. 25 | */ 26 | struct RMem : public std::enable_shared_from_this { // state for "R"egistered "Mem"ory 27 | using raw_ptr_t = void *; 28 | using alloc_fn_t = std::function; 29 | using dealloc_fn_t = std::function; 30 | 31 | /*! 32 | Fixme: hwo to automatically dealloc the memory ? 33 | */ 34 | raw_ptr_t raw_ptr; 35 | const u64 sz; 36 | 37 | dealloc_fn_t dealloc_fn; 38 | 39 | explicit RMem(const u64 &s, 40 | alloc_fn_t af = [](u64 s) -> raw_ptr_t { 41 | return (raw_ptr_t)malloc(s); 42 | }, 43 | dealloc_fn_t df = [](raw_ptr_t p) { free(p); }) 44 | : raw_ptr(af(s)), sz(s), dealloc_fn(df) {} 45 | 46 | bool valid() const { return raw_ptr != nullptr; } 47 | 48 | ~RMem() { 49 | dealloc_fn(raw_ptr); 50 | } 51 | }; 52 | 53 | } // namespace rmem 54 | 55 | } // namespace rdmaio 56 | -------------------------------------------------------------------------------- /xcomm/src/atomic_rw/local_rw_op.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "./rw_trait.hh" 6 | #include "./ptr.hh" 7 | 8 | namespace xstore { 9 | 10 | namespace xcomm { 11 | 12 | namespace rw { 13 | 14 | class LocalRWOp : public ReadWriteTrait { 15 | public: 16 | LocalRWOp() = default; 17 | 18 | auto read_impl(const MemBlock &src, const MemBlock &dest) -> Result<> { 19 | if (src.sz > dest.sz) { 20 | // size not match 21 | return ::rdmaio::Err(); 22 | } 23 | // memcpy version 24 | memcpy(dest.mem_ptr, src.mem_ptr, dest.sz); 25 | return ::rdmaio::Ok(); 26 | } 27 | }; 28 | 29 | class OrderedRWOp : public ReadWriteTrait { 30 | public: 31 | OrderedRWOp() = default; 32 | 33 | auto read_impl(const MemBlock &src, const MemBlock &dest) -> Result<> { 34 | usize cur_copy_sz = 0; 35 | char *sp = reinterpret_cast(src.mem_ptr); 36 | char *dp = reinterpret_cast(dest.mem_ptr); 37 | 38 | while (cur_copy_sz < dest.sz) { 39 | if (dest.sz - cur_copy_sz < sizeof(u64)) { 40 | ASSERT(false); 41 | memcpy(dp, sp, dest.sz - cur_copy_sz); 42 | break; 43 | } 44 | u64 v = read_volatile(sp); 45 | write_volatile(dp, v); 46 | r2::mfence(); 47 | 48 | cur_copy_sz += sizeof(u64); 49 | sp += sizeof(u64); 50 | dp += sizeof(u64); 51 | } 52 | return ::rdmaio::Ok(); 53 | } 54 | }; 55 | } 56 | 57 | } // namespace xcomm 58 | 59 | } // namespace xstore 60 | -------------------------------------------------------------------------------- /deps/rlib/tests/test_qp_progress.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../core/qps/mod.hh" 4 | #include "./fast_random.hh" 5 | 6 | namespace test { 7 | 8 | using namespace rdmaio; 9 | using namespace rdmaio::qp; 10 | 11 | TEST(QP, Progress) { 12 | 13 | auto limit = std::numeric_limits::max(); 14 | 15 | Progress progress; 16 | 17 | progress.forward(12); 18 | ASSERT_EQ(progress.pending_reqs(), 12); 19 | 20 | progress.done(12); 21 | ASSERT_EQ(progress.pending_reqs(), 0); 22 | 23 | // now we run a bunch of whole tests 24 | FastRandom rand(0xdeadbeaf); 25 | u64 sent = 0; 26 | u64 done = 0; 27 | 28 | u64 temp_done = 0; 29 | #if 0 // usually we donot do this test, since it's so time consuming 30 | Progress p2; 31 | 32 | while(sent <= 33 | static_cast(std::numeric_limits::max()) * 64) { 34 | int to_send = rand.rand_number(12, 4096); 35 | p2.forward(to_send); 36 | 37 | sent += to_send; 38 | ASSERT_EQ(p2.pending_reqs(),to_send); 39 | 40 | int to_recv = rand.rand_number(0,to_send); 41 | while(to_send > 0) { 42 | temp_done += to_recv; 43 | p2.done(temp_done); 44 | ASSERT(to_send >= to_recv) << "send: " << to_send <<";" 45 | << "recv: " << to_recv; 46 | ASSERT_EQ(p2.pending_reqs(),to_send - to_recv); 47 | to_send -= to_recv; 48 | 49 | to_recv = rand.rand_number(0, to_send); 50 | } 51 | } 52 | ASSERT_EQ(p2.pending_reqs(),0); 53 | #endif 54 | } 55 | 56 | } // namespace test 57 | -------------------------------------------------------------------------------- /xutils/huge_region.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "./memory_region.hh" 6 | 7 | namespace xstore { 8 | 9 | namespace util { 10 | 11 | using namespace rdmaio; 12 | 13 | /*! 14 | Malloc huge pages in 2M huge pages, align_sz = 2M 15 | */ 16 | class HugeRegion : public MemoryRegion { 17 | static u64 align_to_sz(const u64 &x, const usize &align_sz) { 18 | return (((x) + align_sz - 1) / align_sz * align_sz); 19 | } 20 | 21 | public: 22 | static ::rdmaio::Option> 23 | create(const u64 &sz, const usize &align_sz = (2 << 20)) { 24 | auto region = std::make_shared(sz, align_sz); 25 | if (region->valid()) 26 | return region; 27 | return {}; 28 | } 29 | 30 | explicit HugeRegion(const u64 &sz, const usize &align_sz = (2 << 20)) { 31 | 32 | this->sz = align_to_sz(sz + align_sz, align_sz); 33 | char *ptr = (char *)mmap( 34 | nullptr, this->sz, PROT_READ | PROT_WRITE, 35 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE | MAP_HUGETLB, -1, 0); 36 | 37 | if (ptr == MAP_FAILED) { 38 | this->addr = nullptr; 39 | RDMA_LOG(4) << "error allocating huge page wiht sz: " << this->sz 40 | << " aligned with: " << align_sz 41 | << "; with error: " << strerror(errno); 42 | } else { 43 | RDMA_LOG(4) << "alloc huge page size: " << this->sz << ", "<sz/align_sz<<" * 2M"; 44 | this->addr = ptr; 45 | } 46 | } 47 | }; 48 | 49 | } // namespace util 50 | 51 | } // namespace xstore 52 | -------------------------------------------------------------------------------- /deps/r2/src/tm_manager.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.hh" 4 | #include "./utils/rdtsc.hh" 5 | 6 | #include 7 | 8 | namespace r2 9 | { 10 | 11 | /*! 12 | We use rdtsc(), namely cycles for timeout management; 13 | All pending routines are add towards a heap, which records its start time 14 | */ 15 | 16 | struct TMElement 17 | { 18 | u8 cor_id; 19 | u64 end_time; 20 | u32 seq; // seq is used to filter out duplicate 21 | 22 | TMElement(const u8 &id, const u64 &end_time, const u32 &s) 23 | : cor_id(id), end_time(end_time),seq(s) {} 24 | }; 25 | 26 | struct TECmp 27 | { 28 | bool operator()(TMElement a, TMElement b) 29 | { 30 | return a.end_time > b.end_time; 31 | } 32 | }; 33 | 34 | class TMIter; 35 | class TM 36 | { 37 | 38 | friend class TMIter; 39 | std::priority_queue, TECmp> q; 40 | 41 | public: 42 | void enqueue(const u8 &id, const u64 &end_time,const u32 &seq) 43 | { 44 | q.emplace(id, end_time,seq); 45 | } 46 | }; 47 | 48 | class TMIter 49 | { 50 | TM *tm; 51 | u64 time; 52 | 53 | public: 54 | TMIter(TM &t, u64 time) : tm(&t), time(time) 55 | { 56 | } 57 | 58 | bool valid() 59 | { 60 | return (!tm->q.empty()) && tm->q.top().end_time < time; 61 | } 62 | 63 | std::pair next() 64 | { 65 | auto id = tm->q.top().cor_id; 66 | auto seq = tm->q.top().seq; 67 | tm->q.pop(); 68 | return std::make_pair(id,seq); 69 | } 70 | }; 71 | 72 | } // namespace r2 73 | -------------------------------------------------------------------------------- /xutils/xy_data.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../deps/r2/src/common.hh" 8 | 9 | namespace xstore { 10 | 11 | namespace util { 12 | 13 | /*! 14 | The data structure for manipulating x -> data. 15 | Record and output them to a python readable format. 16 | */ 17 | template 18 | struct XYData 19 | { 20 | std::vector> data; 21 | 22 | XYData() = default; 23 | 24 | auto add(const K& k, const V& v) -> XYData& 25 | { 26 | data.push_back(std::make_pair(k, v)); 27 | return *this; 28 | } 29 | 30 | auto finalize() -> XYData& 31 | { 32 | using T = std::pair; 33 | std::sort(this->data.begin(), 34 | this->data.end(), 35 | [](const T& lhs, const T& rhs) { return lhs.first < rhs.first; }); 36 | 37 | return *this; 38 | } 39 | 40 | auto dump_as_np_data() -> std::string 41 | { 42 | std::ostringstream osx; 43 | osx << "X = ["; 44 | std::ostringstream osy; 45 | osy << "Y = ["; 46 | for (uint i = 0; i < this->data.size(); i++) { 47 | osx << std::get<0>(this->data.at(i)) << ","; 48 | osy << std::get<1>(this->data.at(i)) << ","; 49 | } 50 | osx << "]"; 51 | osy << "]"; 52 | osx << std::endl << osy.str(); 53 | return osx.str(); 54 | } 55 | 56 | auto dump_as_np_data(const std::string& file) 57 | { 58 | auto data = this->dump_as_np_data(); 59 | std::ofstream out(file); 60 | out << data; 61 | out.close(); 62 | } 63 | }; 64 | 65 | } // 66 | 67 | } -------------------------------------------------------------------------------- /xcomm/src/atomic_rw/mod.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "./rw_trait.hh" 4 | #include "./wrapper_type.hh" 5 | 6 | namespace xstore { 7 | 8 | namespace xcomm { 9 | 10 | namespace rw { 11 | 12 | // OP must implement ReadWriteTrait 13 | class AtomicRW { 14 | usize retry_cnt = 0; 15 | 16 | public: 17 | AtomicRW() = default; 18 | 19 | auto report_reties() -> usize { return this->retry_cnt; } 20 | 21 | template 22 | auto atomic_read(OP &op, MemBlock &src, MemBlock &dest) -> Result<> { 23 | // 1. sanity check the buffer 24 | if (dest.sz < sizeof(WrappedType)) { 25 | ASSERT(false); 26 | return ::rdmaio::Err(); 27 | } 28 | dest.sz = sizeof(WrappedType); 29 | 30 | retry: 31 | this->retry_cnt = 0; 32 | // 1. read the object 33 | auto res = op.read(src, dest); 34 | if (unlikely(res != ::rdmaio::IOCode::Ok)) { 35 | return res; 36 | } 37 | 38 | // 2. check consistent 39 | r2::compile_fence(); 40 | // check consistency 41 | WrappedType *v_p = reinterpret_cast *>(dest.mem_ptr); 42 | if (unlikely(!v_p->consistent())) { 43 | // if (vs->seq != pseq) { 44 | r2::relax_fence(); 45 | this->retry_cnt += 1; 46 | if (unlikely(this->retry_cnt > 1000000)) { 47 | ASSERT(false) << "should never rety so much:" << retry_cnt 48 | << "; seqs: " << v_p->seq << " " << v_p->seq_check; 49 | } 50 | goto retry; 51 | } 52 | return res; 53 | } 54 | }; 55 | 56 | } // namespace rw 57 | } // namespace xcomm 58 | } // namespace xstore 59 | -------------------------------------------------------------------------------- /xcomm/tests/transport_util.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../xutils/huge_region.hh" 4 | #include "../src/transport/rdma_ring_t.hh" 5 | 6 | namespace test { 7 | 8 | using namespace r2; 9 | using namespace rdmaio; 10 | using namespace xstore::util; 11 | using namespace xstore::transport; 12 | 13 | class SimpleAllocator : public AbsRecvAllocator { 14 | RMem::raw_ptr_t buf = nullptr; 15 | usize total_mem = 0; 16 | mr_key_t key; 17 | 18 | RegAttr mr; 19 | 20 | public: 21 | SimpleAllocator(Arc mem, const RegAttr &mr) 22 | : buf(mem->raw_ptr), total_mem(mem->sz), mr(mr), key(mr.key) { 23 | // RDMA_LOG(4) << "simple allocator use key: " << key; 24 | } 25 | 26 | ::r2::Option> 27 | alloc_one(const usize &sz) override { 28 | //LOG(4) << "alloc one!"; 29 | if (total_mem < sz) { 30 | LOG(4) << "total: " << total_mem << "; cur sz:" << sz; 31 | return {}; 32 | } 33 | auto ret = buf; 34 | buf = static_cast(buf) + sz; 35 | total_mem -= sz; 36 | return std::make_pair(ret, key); 37 | } 38 | 39 | ::rdmaio::Option> 40 | alloc_one_for_remote(const usize &sz) override { 41 | if (total_mem < sz) 42 | return {}; 43 | auto ret = buf; 44 | buf = static_cast(buf) + sz; 45 | total_mem -= sz; 46 | return std::make_pair(ret, mr); 47 | } 48 | }; 49 | 50 | template Nat align(const Nat &x, const Nat &a) { 51 | auto r = x % a; 52 | return r ? (x + a - r) : x; 53 | } 54 | 55 | } // namespace test 56 | -------------------------------------------------------------------------------- /deps/r2/src/rpc/buf_factory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../common.hh" 4 | #include "../allocator_master.hh" 5 | 6 | namespace r2 { 7 | 8 | namespace rpc { 9 | 10 | const uint MAX_INLINE_SIZE = 64; 11 | const uint MAX_ROLLING_IDX = 2048; 12 | 13 | class BufFactory { 14 | public: 15 | explicit BufFactory(int padding) : extra_padding(padding) { 16 | for(uint i = 0;i < MAX_ROLLING_IDX; ++i) { 17 | char *buf = alloc(8192); 18 | ASSERT(buf != nullptr); 19 | inline_bufs.push_back(buf); 20 | } 21 | } 22 | 23 | char *alloc(int size) const { 24 | //char *ptr = (char *)Rmalloc(size + extra_padding); 25 | char *ptr = (char *)(AllocatorMaster<>::get_thread_allocator()->alloc(size + extra_padding)); 26 | //LOG(4) << "alloc ptr: " << (void *)ptr << " for sz: " << size; 27 | if(likely(ptr != nullptr)) 28 | return ptr + extra_padding; 29 | return nullptr; 30 | } 31 | 32 | void dealloc(char *ptr) const { 33 | (AllocatorMaster<>::get_thread_allocator()->free(ptr - extra_padding)); 34 | } 35 | 36 | char *get_inline_buf(int idx = 0) { 37 | //return &inline_bufs[idx * MAX_INLINE_SIZE] + extra_padding; 38 | return inline_bufs[idx]; 39 | } 40 | 41 | char *get_inline() { 42 | rolling_idx_ = (rolling_idx_ + 1) % MAX_ROLLING_IDX; 43 | return get_inline_buf(rolling_idx_); 44 | } 45 | 46 | private: 47 | const int extra_padding = 0; // extra padding used for each message 48 | std::vector inline_bufs; 49 | u16 rolling_idx_ = 0; 50 | }; // end class 51 | 52 | } // end namespace rpc 53 | 54 | } // end namespace r2 55 | -------------------------------------------------------------------------------- /deps/rlib/core/rmem/config.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../common.hh" 4 | 5 | namespace rdmaio { 6 | 7 | namespace rmem { 8 | 9 | /*! 10 | class for manging registeration permission of RDMA registered memory. 11 | The detailed documentation of it can be found at the documentation of ibverbs. 12 | Example usage: (generate a flag which has local write and remote read permissions) 13 | ` 14 | MemoryFlags flags; 15 | flags.clear_flags().add_local_write().add_remote_read(); 16 | 17 | // use it: 18 | auto value = flags.get_value(); 19 | */ 20 | class MemoryFlags 21 | { 22 | int protection_flags = IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ | 23 | IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_REMOTE_ATOMIC; 24 | public: 25 | MemoryFlags() = default; 26 | 27 | MemoryFlags& set_flags(int flags) 28 | { 29 | protection_flags = flags; 30 | return *this; 31 | } 32 | 33 | int get_value() const { return protection_flags; } 34 | 35 | MemoryFlags& clear_flags() { return set_flags(0); } 36 | 37 | MemoryFlags& add_local_write() 38 | { 39 | protection_flags |= IBV_ACCESS_LOCAL_WRITE; 40 | return *this; 41 | } 42 | 43 | MemoryFlags& add_remote_write() 44 | { 45 | protection_flags |= IBV_ACCESS_REMOTE_WRITE; 46 | /* 47 | According to https://www.rdmamojo.com/2012/09/07/ibv_reg_mr/ 48 | local write must be set to enable remote write 49 | */ 50 | add_local_write(); 51 | return *this; 52 | } 53 | 54 | MemoryFlags& add_remote_read() 55 | { 56 | protection_flags |= IBV_ACCESS_REMOTE_READ; 57 | return *this; 58 | } 59 | }; 60 | 61 | } // end namespace rmem 62 | 63 | } 64 | -------------------------------------------------------------------------------- /benchs/arc/val/cpu.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "deps/r2/src/common.hh" 6 | 7 | namespace xstore { 8 | 9 | namespace platforms { 10 | 11 | using namespace r2; 12 | 13 | /*! 14 | Hardware setting on VAL: 15 | // TODO 16 | */ 17 | 18 | class VALBinder 19 | { 20 | public: 21 | static void bind(u64 socket, u64 core) 22 | { 23 | u64 id = 0; 24 | switch (socket) { 25 | case 0: 26 | id = socket0_id(core); 27 | break; 28 | case 1: 29 | id = socket1_id(core); 30 | break; 31 | default: 32 | ASSERT(false); 33 | } 34 | 35 | cpu_set_t mask; 36 | CPU_ZERO(&mask); 37 | CPU_SET(id, &mask); 38 | sched_setaffinity(0, sizeof(mask), &mask); 39 | } 40 | 41 | static const u64 core_per_socket() { return 24; } 42 | 43 | static const u64 socket0_id(uint core) 44 | { 45 | static const std::array socket_0 = { 0, 2, 4, 6, 8, 10, 46 | 12, 14, 16, 18, 20, 22, 47 | 24, 26, 28, 30, 32, 34, 48 | 36, 38, 40, 42, 44, 46 }; 49 | return socket_0.at(core); 50 | } 51 | 52 | static const u64 socket1_id(uint core) 53 | { 54 | static const std::array socket_1 = { 1, 3, 5, 7, 9, 11, 55 | 13, 15, 17, 19, 21, 23, 56 | 25, 27, 29, 31, 33, 35, 57 | 37, 39, 41, 43, 45, 47 }; 58 | return socket_1.at(core); 59 | } 60 | }; 61 | 62 | } // platforms 63 | 64 | } 65 | -------------------------------------------------------------------------------- /deps/progress-cpp/README.md: -------------------------------------------------------------------------------- 1 | Progress-CPP 2 | === 3 | 4 | A flexible ASCII progress bar for your console based C++ projects. 5 | 6 | ### Usage 7 | Progress is a header-only library and can be used by simply including the `ProgressBar.hpp` header file. 8 | 9 | The bar takes the following options at initialization 10 | - Limit: the total number of ticks that need to be completed 11 | - Width: width of the bar 12 | - Complete Char: the character to indicate completion (defaults to `=`) 13 | - Incomplete Char: the character to indicate pending. (defaults to ' ') 14 | 15 | ```c++ 16 | #include "ProgressBar.hpp" 17 | 18 | int main() { 19 | 20 | const int limit = 10000; 21 | 22 | // initialize the bar 23 | ProgressBar progressBar(limit, 70); 24 | 25 | for (int i = 0; i < limit; i++) { 26 | // record the tick 27 | ++progressBar; 28 | 29 | // display the bar 30 | progressBar.display(); 31 | } 32 | 33 | // tell the bar to finish 34 | progressBar.done(); 35 | } 36 | ``` 37 | The above code results in the following output 38 | 39 | ``` 40 | [===================> ] 29% 0.821s 41 | ``` 42 | 43 | ### Example 44 | Refer to [example.cpp](example/src/example.cpp) file for an example usage. To run it, 45 | 46 | ``` 47 | $ mkdir build && cd build 48 | $ cmake .. 49 | $ make 50 | $ ./ProgressBar 51 | ``` 52 | 53 | Or without `cmake` 54 | ``` 55 | $ g++ -O3 -I. main.cpp -Wall -std=c++11 -o ProgressBar 56 | $ ./ProgressBar 57 | ``` 58 | 59 | ### CMake configuration 60 | Cmake and project layout is inspired by [github.com/TheLartians/ModernCppStarter](https://github.com/TheLartians/ModernCppStarter). 61 | -------------------------------------------------------------------------------- /deps/r2/src/common.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "./utils/option.hh" 6 | #include "./logging.hh" 7 | 8 | namespace r2 { 9 | 10 | using u64 = uint64_t; 11 | using u32 = uint32_t; 12 | using u16 = uint16_t; 13 | using i64 = int64_t; 14 | using i32 = int32_t; 15 | using u8 = uint8_t; 16 | using i8 = int8_t; 17 | using usize = unsigned int; 18 | 19 | constexpr usize kCacheLineSize = 128; 20 | 21 | } // end namespace r2 22 | 23 | #pragma once 24 | 25 | namespace r2 { 26 | 27 | #define DISABLE_COPY_AND_ASSIGN(classname) \ 28 | private: \ 29 | classname(const classname &) = delete; \ 30 | classname &operator=(const classname &) = delete 31 | 32 | #define unlikely(x) __builtin_expect(!!(x), 0) 33 | #define likely(x) __builtin_expect(!!(x), 1) 34 | 35 | #define NOT_INLE __attribute__((noinline)) 36 | #define ALWAYS_INLINE __attribute__((always_inline)) 37 | 38 | static inline void compile_fence(void) { asm volatile("" ::: "memory"); } 39 | 40 | static inline void lfence(void) { asm volatile("lfence" ::: "memory"); } 41 | 42 | static inline void store_fence(void) { asm volatile("lfence" : : : "memory"); } 43 | 44 | static inline void mfence(void) { asm volatile("mfence" : : : "memory"); } 45 | 46 | static inline void relax_fence(void) { asm volatile("pause" : : : "memory"); } 47 | 48 | #ifndef NO_OPT 49 | /*! 50 | usage: 51 | ` 52 | origin func: void xx() { ...} 53 | no_opt origin func: void NO_OPT xx() {...} 54 | ` 55 | */ 56 | #define NO_OPT __attribute__((optimize("O0"))) 57 | #endif 58 | 59 | } // end namespace r2 60 | -------------------------------------------------------------------------------- /deps/r2/src/logging.cc: -------------------------------------------------------------------------------- 1 | #include "logging.hh" 2 | 3 | #include 4 | 5 | namespace r2 { 6 | 7 | using namespace std; 8 | 9 | // control flags for color 10 | enum 11 | { 12 | R_BLACK = 39, 13 | R_RED = 31, 14 | R_GREEN = 32, 15 | R_YELLOW = 33, 16 | R_BLUE = 34, 17 | R_MAGENTA = 35, 18 | R_CYAN = 36, 19 | R_WHITE = 37 20 | }; 21 | 22 | std::string 23 | StripBasename(const std::string& full_path) 24 | { 25 | const char kSeparator = '/'; 26 | size_t pos = full_path.rfind(kSeparator); 27 | if (pos != std::string::npos) { 28 | return full_path.substr(pos + 1, std::string::npos); 29 | } else { 30 | return full_path; 31 | } 32 | } 33 | 34 | inline string 35 | EndcolorFlag() 36 | { 37 | char flag[7]; 38 | snprintf(flag, 7, "%c[0m", 0x1B); 39 | return string(flag); 40 | } 41 | 42 | const int RTX_DEBUG_LEVEL_COLOR[] = { R_BLACK, R_YELLOW, R_BLACK, R_GREEN, 43 | R_MAGENTA, R_RED, R_RED }; 44 | 45 | DisplayLogger::DisplayLogger(const char* file, int line, int level) 46 | : level_(level) 47 | { 48 | if (level_ < ROCC_LOG_LEVEL) 49 | return; 50 | } 51 | 52 | MessageLogger::MessageLogger(const char* file, int line, int level) 53 | : DisplayLogger(file, line, level) 54 | { 55 | stream_ << "[" << StripBasename(std::string(file)) << ":" << line << "] "; 56 | } 57 | 58 | DisplayLogger::~DisplayLogger() 59 | { 60 | if (level_ >= ROCC_LOG_LEVEL) { 61 | stream_ << "\n"; 62 | std::cout << "\033[" << RTX_DEBUG_LEVEL_COLOR[std::min(level_, 6)] << "m" 63 | << stream_.str() << EndcolorFlag() << std::flush; 64 | if (level_ >= LOG_FATAL) 65 | abort(); 66 | } 67 | } 68 | 69 | } // namespace r2 70 | -------------------------------------------------------------------------------- /deps/r2/src/msg/msg_session.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "rlib/core/result.hh" 4 | 5 | #include "../libroutine.hh" 6 | #include "../mem_block.hh" 7 | 8 | namespace r2 { 9 | /*! 10 | Session manages a connection from myself to a specific remote point. 11 | */ 12 | class Session { 13 | public: 14 | static constexpr double no_timeout = std::numeric_limits::max(); 15 | /*! 16 | Send a message, and spawn a future in the scheduler 17 | 18 | \param msg: the sending msg 19 | \param timeout: time out recorded in **ms** 20 | 21 | usage example: 22 | auto future = session.send(msg,120); 23 | R2_SPAWN(future); 24 | R2_YIELD; 25 | */ 26 | /*! 27 | res, Option 28 | */ 29 | virtual Result send(const MemBlock &msg, const double timeout, 30 | R2_ASYNC) = 0; 31 | 32 | /*! 33 | A blocking version of send. 34 | 35 | \param msg: the sending msg 36 | \param timeout: time out recorded in **ms** 37 | 38 | usage example: 39 | auto ret = session.send_blocking(msg,120); // 120 ms 40 | ASSERT(ret == SUCC); 41 | */ 42 | virtual Result 43 | send_blocking(const MemBlock &msg, const double timeout = no_timeout) = 0; 44 | 45 | /*! 46 | XD:Should recording pending (un-sent message) 47 | Post a request to the RNIC, and ignore its completion. 48 | */ 49 | virtual Result send_pending(const MemBlock &msg) = 0; 50 | 51 | /*! 52 | Async, coroutine version 53 | */ 54 | virtual Result send_pending(const MemBlock &msg, R2_ASYNC) = 0; 55 | }; 56 | 57 | } // namespace r2 58 | -------------------------------------------------------------------------------- /deps/r2/src/msg/ud_msg.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "protocol.hpp" 4 | 5 | #include "rlib/ud.hpp" 6 | #include 7 | 8 | #define R2_SOLICITED 0 9 | 10 | #include "ud_data.hpp" 11 | 12 | namespace r2 13 | { 14 | 15 | class UDIncomingIter; 16 | class UdAdapter : public MsgProtocol 17 | { 18 | friend class UDIncomingIter; 19 | 20 | public: 21 | UdAdapter(const Addr &my_addr, rdmaio::UDQP *sqp, rdmaio::UDQP *qp = nullptr); 22 | 23 | Result connect(const Addr &addr, 24 | const rdmaio::MacID &id, 25 | int i) override; 26 | 27 | Result send_async(const Addr &addr, 28 | const char *msg, 29 | int size) override; 30 | 31 | Result flush_pending() override; 32 | 33 | int poll_all(const MsgProtocol::msg_callback_t &f) override; 34 | 35 | Iter_p_t get_iter() override; 36 | 37 | /*! 38 | Below methods handle connect related works. 39 | */ 40 | rdmaio::Buf_t get_my_conninfo() override; 41 | 42 | Result connect_from_incoming(const Addr &addr, 43 | const rdmaio::Buf_t &connect_info); 44 | 45 | void disconnect(const Addr &addr); 46 | 47 | public: 48 | const Addr my_addr; 49 | 50 | private: 51 | // QP to receive requests 52 | rdmaio::UDQP *qp_ = nullptr; 53 | rdmaio::UDQP *send_qp_ = nullptr; 54 | 55 | std::unordered_map connect_infos_; 56 | 57 | UdSender sender_; 58 | UdReceiver receiver_; 59 | 60 | int current_idle_recvs_ = 0; 61 | 62 | DISABLE_COPY_AND_ASSIGN(UdAdapter); 63 | }; // end class UdAdapter 64 | 65 | } // end namespace r2 66 | -------------------------------------------------------------------------------- /deps/rlib/core/bootstrap/multi_msg_iter.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "./multi_msg.hh" 4 | 5 | namespace rdmaio { 6 | 7 | namespace bootstrap { 8 | 9 | /*! 10 | MsgsIter provides a means to help iterating through the batched msg. 11 | Return a pointer and the size of the Msg. 12 | 13 | Example usage of an unsafe version (but without string copy): 14 | ` 15 | MultiMsg<1024> msgs; 16 | for (MsgsIter iter(msgs); iter.valid();iter.next()) { 17 | auto msg = iter.cur(); 18 | auto msg_ptr = std::get<0>(msg); 19 | auto msg_sz = std::get<1>(msg); 20 | } 21 | ` 22 | 23 | Example usage of a safe version: 24 | ` 25 | MultiMsg<1024> msgs; 26 | for (MsgsIter iter(msgs); iter.valid();iter.next()) { 27 | auto msg = iter.cur_msg(); 28 | // To use ... 29 | } 30 | ` 31 | */ 32 | template 33 | class MsgsIter { 34 | const Msgs *msgs_p; 35 | usize cur_idx = 0; 36 | 37 | public: 38 | explicit MsgsIter(const Msgs &msgs) : msgs_p(&msgs) {} 39 | 40 | bool valid() const { 41 | return cur_idx < msgs_p->num_msg(); 42 | } 43 | 44 | void next() { 45 | cur_idx += 1; 46 | } 47 | 48 | std::pair cur() const { 49 | RDMA_ASSERT(valid()); 50 | MsgEntry &entry = msgs_p->header->entries[cur_idx]; 51 | 52 | char *data_ptr = nullptr; 53 | { 54 | // unsafe code 55 | data_ptr = (char *)(msgs_p->buf->data() + entry.offset); 56 | } 57 | return std::make_pair(data_ptr,static_cast(entry.sz)); 58 | } 59 | 60 | // a safe (but with memcpy) version of cur() 61 | ByteBuffer cur_msg() const { 62 | auto msg = cur(); 63 | return ByteBuffer(std::get<0>(msg),std::get<1>(msg)); 64 | } 65 | }; 66 | } 67 | } // namespace rdmaio 68 | -------------------------------------------------------------------------------- /deps/rlib/benchs/thread.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../core/common.hh" 4 | 5 | #include 6 | #include 7 | 8 | namespace bench { 9 | 10 | /*! 11 | This is a simple wrapper over pthread, which uses a more abstracted way to 12 | create threads. T: the return type of the thread. 13 | 14 | Example: 15 | To create one thread using the function `fn run() -> T`, one can use the 16 | following way: auto t = Thread([]() -> T { T res; return res; 17 | }); 18 | t.start(); // really run the thread 19 | t.join(); // wait for it to stop 20 | */ 21 | template class alignas(128) Thread { 22 | using thread_body_t = std::function; 23 | 24 | thread_body_t core_func; 25 | T res; 26 | pthread_t pid; // pthread id 27 | 28 | public: 29 | explicit Thread(const thread_body_t &b) : core_func(b) {} 30 | 31 | void start() { 32 | pthread_attr_t attr; 33 | RDMA_ASSERT(pthread_attr_init(&attr) == 0); 34 | RDMA_ASSERT(pthread_create(&pid, &attr, pthread_bootstrap, (void *)this) == 0); 35 | RDMA_ASSERT(pthread_attr_destroy(&attr) == 0); 36 | } 37 | 38 | T join() { 39 | RDMA_ASSERT(pthread_join(pid, nullptr) == 0); 40 | return get_res(); 41 | } 42 | 43 | T get_res() const { return res; } 44 | 45 | private: 46 | // TODO: what if the sizeof(T) is very large? 47 | static_assert(sizeof(T) < (128 - sizeof(thread_body_t) - sizeof(pthread_t)), 48 | "xx"); 49 | char padding[128 - (sizeof(thread_body_t) + sizeof(T) + sizeof(pthread_t))]; 50 | 51 | static void *pthread_bootstrap(void *p) { 52 | Thread *self = static_cast(p); 53 | self->res = self->core_func(); 54 | return nullptr; 55 | } 56 | }; 57 | 58 | } // namespace r2 59 | -------------------------------------------------------------------------------- /deps/progress-cpp/include/progresscpp/ProgressBar.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace progresscpp { 7 | class ProgressBar { 8 | private: 9 | unsigned int ticks = 0; 10 | 11 | const unsigned int total_ticks; 12 | const unsigned int bar_width; 13 | const char complete_char = '='; 14 | const char incomplete_char = ' '; 15 | const std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now(); 16 | 17 | public: 18 | ProgressBar(unsigned int total, unsigned int width, char complete, char incomplete) : 19 | total_ticks{total}, bar_width{width}, complete_char{complete}, incomplete_char{incomplete} {} 20 | 21 | ProgressBar(unsigned int total, unsigned int width) : total_ticks{total}, bar_width{width} {} 22 | 23 | unsigned int operator++() { return ++ticks; } 24 | 25 | void display() const { 26 | float progress = (float) ticks / total_ticks; 27 | int pos = (int) (bar_width * progress); 28 | 29 | std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); 30 | auto time_elapsed = std::chrono::duration_cast(now - start_time).count(); 31 | 32 | std::cout << "["; 33 | 34 | for (int i = 0; i < bar_width; ++i) { 35 | if (i < pos) std::cout << complete_char; 36 | else if (i == pos) std::cout << ">"; 37 | else std::cout << incomplete_char; 38 | } 39 | std::cout << "] " << int(progress * 100.0) << "% " 40 | << float(time_elapsed) / 1000.0 << "s\r"; 41 | std::cout.flush(); 42 | } 43 | 44 | void done() const { 45 | display(); 46 | std::cout << std::endl; 47 | } 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /deps/r2/src/thread.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.hh" 4 | 5 | #include 6 | #include 7 | 8 | namespace r2 { 9 | 10 | 11 | /*! 12 | This is a simple wrapper over pthread, which uses a more abstracted way to create threads. 13 | T: the return type of the thread. 14 | 15 | Example: 16 | To create one thread using the function `fn run() -> T`, one can use the following way: 17 | auto t = Thread([]() -> T { 18 | T res; 19 | return res; 20 | }); 21 | t.start(); // really run the thread 22 | t.join(); // wait for it to stop 23 | */ 24 | template 25 | class alignas(128) Thread 26 | { 27 | using thread_body_t = std::function; 28 | 29 | thread_body_t core_func; 30 | T res; 31 | pthread_t pid; // pthread id 32 | 33 | public: 34 | explicit Thread(const thread_body_t& b) 35 | : core_func(b) 36 | {} 37 | 38 | void start() 39 | { 40 | pthread_attr_t attr; 41 | ASSERT(pthread_attr_init(&attr) == 0); 42 | ASSERT(pthread_create(&pid, &attr, pthread_bootstrap, (void*)this) == 0); 43 | ASSERT(pthread_attr_destroy(&attr) == 0); 44 | } 45 | 46 | T join() 47 | { 48 | // ASSERT(pthread_join(pid, nullptr) == 0); 49 | pthread_tryjoin_np(pid, nullptr); 50 | return get_res(); 51 | } 52 | 53 | T get_res() const { return res; } 54 | 55 | private: 56 | // TODO: what if the sizeof(T) is very large? 57 | static_assert(sizeof(T) < (128 - sizeof(thread_body_t) - sizeof(pthread_t)), 58 | "xx"); 59 | char padding[128 - (sizeof(thread_body_t) + sizeof(T) + sizeof(pthread_t))]; 60 | 61 | static void* pthread_bootstrap(void* p) 62 | { 63 | Thread* self = static_cast(p); 64 | self->res = self->core_func(); 65 | return nullptr; 66 | } 67 | }; 68 | 69 | } 70 | -------------------------------------------------------------------------------- /benchs/Rolex/tests/test_leaf_table.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "rolex/leaf_table.hpp" 4 | #include "rolex/trait.hpp" 5 | #include "rolex/remote_memory.hh" 6 | 7 | using namespace rolex; 8 | 9 | namespace test { 10 | 11 | TEST(LeafTable, leaf_table) { 12 | leaf_table_t ltable; 13 | ltable.train_emplace_back(0); 14 | ltable.train_emplace_back(1); 15 | ltable.lock_leaf(1); 16 | 17 | ASSERT_EQ(ltable.table[1].lock, 1); 18 | ASSERT_EQ(ltable.table[0].lock, 0); 19 | 20 | ltable.synonym_emplace_back(true, 1, 3); 21 | ASSERT_EQ(ltable.table[1].synonym_leaf, 1); 22 | ASSERT_EQ(ltable.SynonymTable[1].leaf_num, 3); 23 | 24 | ltable.synonym_emplace_back(false, 1, 5); 25 | ASSERT_EQ(ltable.SynonymTable[1].synonym_leaf, 2); 26 | ASSERT_EQ(ltable.SynonymTable[2].leaf_num, 5); 27 | 28 | ltable.unlock_leaf(1); 29 | ASSERT_EQ(ltable.table[1].lock, 0); 30 | } 31 | 32 | 33 | TEST(LeafTable, leaf_data) { 34 | const usize MB = 1024 * 1024; 35 | const usize leaf_num = 100; 36 | RCtrl* ctrl = new RCtrl(8888); 37 | RM_config conf(ctrl, 1024 * MB, leaf_num*sizeof(leaf_t), 0, leaf_num); 38 | remote_memory_t* RM = new remote_memory_t(conf); 39 | auto alloc = RM->leaf_allocator(); 40 | 41 | auto res = alloc->fetch_new_leaf(); 42 | leaf_table_t ltable; 43 | ltable.train_emplace_back(res.second); 44 | leaf_t* cur_leaf = reinterpret_cast(res.first); 45 | for(int i=0; i<5; i++) cur_leaf->insert_not_full(i, i); 46 | for(int i=30; i<39; i++) { 47 | if(cur_leaf->isfull()){ 48 | res = alloc->fetch_new_leaf(); 49 | ltable.train_emplace_back(res.second); 50 | cur_leaf = reinterpret_cast(res.first); 51 | } 52 | cur_leaf->insert_not_full(i, i); 53 | } 54 | for(int i=10; i<21; i++){ 55 | ltable.insert(i, i, alloc, 0, 0); 56 | } 57 | 58 | ltable.print(alloc); 59 | } 60 | 61 | 62 | 63 | 64 | } 65 | -------------------------------------------------------------------------------- /xcomm/tests/utils.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../deps/r2/src/common.hh" 4 | #include "../../deps/r2/src/random.hh" 5 | 6 | #include // generate_n 7 | #include 8 | #include 9 | 10 | namespace test { 11 | 12 | using namespace r2; 13 | 14 | static ::r2::util::FastRandom rand(0xdeadbeaf); 15 | 16 | template struct __attribute__((packed)) TestObj { 17 | char data[N]; 18 | u64 checksum = 0; 19 | inline auto sz() -> usize { return N; } 20 | } __attribute__((aligned(sizeof(u64)))); 21 | 22 | // random string generator from 23 | // https://stackoverflow.com/questions/440133/how-do-i-create-a-random-alpha-numeric-string-in-c 24 | void inplace_rand_str(char *buf, size_t len) { 25 | auto randchar = []() -> char { 26 | const char charset[] = "0123456789" 27 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 28 | "abcdefghijklmnopqrstuvwxyz"; 29 | const size_t max_index = (sizeof(charset) - 1); 30 | return charset[rand.next() % max_index]; 31 | }; 32 | std::generate_n(buf, len, randchar); 33 | } 34 | 35 | auto random_string(size_t length) -> std::string { 36 | std::string str(length, 0); 37 | inplace_rand_str((char *)str.data(), length); 38 | return str; 39 | } 40 | 41 | auto simple_checksum(const char *buf, size_t len) -> usize { 42 | usize sum = 0; 43 | for (uint i = 0;i < len; ++i) { 44 | sum += static_cast(buf[i]); 45 | } 46 | return ~sum; 47 | } 48 | 49 | auto verbose_simple_checksum(const char *buf, size_t len) -> usize { 50 | LOG(4) << "start check sum with len: " << len; 51 | usize sum = 0; 52 | for (uint i = 0; i < len; ++i) { 53 | LOG(4) << "add: " << static_cast(buf[i]); 54 | sum += static_cast(buf[i]); 55 | } 56 | LOG(4) << "done checksum: " << sum << " ------ " << ~sum; 57 | return ~sum; 58 | } 59 | 60 | } // namespace test 61 | -------------------------------------------------------------------------------- /deps/rlib/tests/test_mmsg.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../core/bootstrap/multi_msg.hh" 4 | #include "../core/bootstrap/multi_msg_iter.hh" 5 | 6 | #include "./random.hh" 7 | 8 | using namespace rdmaio; 9 | using namespace rdmaio::bootstrap; 10 | 11 | namespace test { 12 | 13 | TEST(BootMsg, Basic) { 14 | 15 | using TestMsg = MultiMsg<1024>; 16 | 17 | TestMsg mss; // create a MultioMsg with total 1024-bytes capacity. 18 | 19 | FastRandom rand(0xdeadbeaf); 20 | 21 | std::vector ground_truth; 22 | 23 | usize cur_sz = 0; 24 | for (uint i = 0; i < kMaxMultiMsg; ++i) { 25 | 26 | // todo: google test random string ? 27 | ByteBuffer msg = rand.next_string(rand.rand_number(50, 300)); 28 | 29 | auto res = mss.append(msg); 30 | cur_sz += msg.size(); 31 | 32 | if (!res) { 33 | ASSERT_TRUE(cur_sz + sizeof(MsgsHeader) > 1024); 34 | break; 35 | } else { 36 | // we really push the message, so add it to the ground-truth 37 | ground_truth.push_back(msg); 38 | } 39 | } 40 | 41 | RDMA_LOG(4) << "total " << mss.num_msg() << " test msgs added"; 42 | 43 | // now we parse the msg content 44 | auto &copied_msg = *(mss.buf); 45 | RDMA_LOG(4) << "copied msg's sz: " << copied_msg.size(); 46 | auto mss_2 = TestMsg::create_from(copied_msg).value(); 47 | ASSERT_EQ(mss_2.num_msg(),mss.num_msg()); 48 | 49 | // iterate through the msgs to check contents 50 | 51 | // finally we check the msg content 52 | usize iter_count = 0; 53 | for (MsgsIter iter(mss_2); iter.valid(); iter.next()) { 54 | ASSERT_TRUE(iter_count < ground_truth.size()); 55 | ASSERT_EQ(iter.cur_msg().compare(ground_truth[iter_count]),0); 56 | ASSERT_EQ(iter.cur_msg().compare(mss_2.query_one(iter_count).value()), 0); 57 | iter_count += 1; 58 | } 59 | 60 | ASSERT_EQ(iter_count,ground_truth.size()); 61 | } 62 | 63 | } // namespace test 64 | -------------------------------------------------------------------------------- /xcomm/tests/test_local_rw.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../src/atomic_rw/local_rw_op.hh" 4 | #include "../src/atomic_rw/wrapper_type.hh" 5 | #include "../src/atomic_rw/unwrapper_type.hh" 6 | 7 | #include "./utils.hh" 8 | 9 | namespace test { 10 | 11 | using namespace xstore::xcomm::rw; 12 | 13 | TEST(AtomicRW, basic_rw) { 14 | auto src_str = random_string(1024); 15 | auto dest_str = std::string(1024,'\0'); 16 | 17 | ASSERT_NE(0, dest_str.compare(src_str)); 18 | 19 | // read src into dest 20 | r2::MemBlock src((void *)src_str.data(), src_str.size()); 21 | r2::MemBlock dest((void *)dest_str.data(), dest_str.size()); 22 | 23 | LocalRWOp().read(src,dest); 24 | ASSERT_EQ(0, dest_str.compare(src_str)); 25 | 26 | inplace_rand_str((char *)dest.mem_ptr,dest.sz); 27 | ASSERT_NE(0, dest_str.compare(src_str)); 28 | 29 | // now write 30 | LocalRWOp().write(dest,src); 31 | ASSERT_EQ(0, dest_str.compare(src_str)); 32 | 33 | // test wrapped rw 34 | inplace_rand_str((char *)dest.mem_ptr, dest.sz); 35 | ASSERT_NE(0, dest_str.compare(src_str)); 36 | 37 | OrderedRWOp().write(dest, src); 38 | ASSERT_EQ(0, dest_str.compare(src_str)); 39 | } 40 | 41 | TEST(AtomicRW, wrapped_type_create) { 42 | using WT = WrappedType; 43 | WT x(5); 44 | x.begin_write(); 45 | *(x.get_payload_ptr()) += 1; 46 | ASSERT_FALSE(x.consistent()); // should be inconsistent during the write 47 | x.done_write(); 48 | 49 | // should be consistent after the done_write 50 | ASSERT_TRUE(x.consistent()); 51 | // now the value should eq to 6 52 | ASSERT_EQ(*x.get_payload_ptr(), 6); 53 | } 54 | 55 | TEST(AtomicRW, unwrapper_type) { 56 | using WT = WrappedType; 57 | using UWT = UWrappedType; 58 | ASSERT_NE(sizeof(WT), sizeof(UWT)); 59 | } 60 | 61 | } // namespace test 62 | 63 | int main(int argc, char **argv) { 64 | ::testing::InitGoogleTest(&argc, argv); 65 | return RUN_ALL_TESTS(); 66 | } 67 | -------------------------------------------------------------------------------- /xutils/atomic.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace xstore { 6 | 7 | namespace util { 8 | 9 | #ifndef xglue 10 | #define xglue(a, b) a##b 11 | #endif 12 | #ifndef glue 13 | #define glue(a, b) xglue(a, b) 14 | #endif 15 | 16 | #ifndef LOCK_PREFIX 17 | #define LOCK_PREFIX "lock; " 18 | #endif 19 | 20 | #define xstr(s) #s 21 | #define sstr(s) xstr(s) 22 | 23 | // Is this the correct way to detect 64 system? 24 | #if (__LP64__ == 1) 25 | /* Compares the value in rdx:rax to value in memp, if equal load rcx:rbx into 26 | * memp, else load value into rdx:rax. 27 | * Return 1 on success, 0 otherwise. */ 28 | static __inline__ uint8_t atomic_cmpxchg16b(uint64_t *memp, uint64_t old0, 29 | uint64_t old1, uint64_t new0, 30 | uint64_t new1) { 31 | uint8_t z; 32 | asm volatile("lock; cmpxchg16b %3\n\t" 33 | "setz %2\n\t" 34 | : "+a"(old0), "+d"(old1), "=r"(z), "+m"(*memp) 35 | : "b"(new0), "c"(new1) 36 | : "memory", "cc"); 37 | return z; 38 | } 39 | #endif 40 | 41 | static __inline__ uint8_t atomic_cmpxchg8b(uint32_t *memp, uint32_t old0, 42 | uint32_t old1, uint32_t new0, 43 | uint32_t new1) { 44 | uint8_t z; 45 | asm volatile("lock; cmpxchg8b %3\n\t" 46 | "setz %2\n\t" 47 | : "+a"(old0), "+d"(old1), "=r"(z), "+m"(*memp) 48 | : "b"(new0), "c"(new1) 49 | : "memory", "cc"); 50 | return z; 51 | } 52 | 53 | #define DATA_BITS 8 54 | #include "./atomic-template.h" 55 | 56 | #define DATA_BITS 16 57 | #include "./atomic-template.h" 58 | 59 | #define DATA_BITS 32 60 | #include "./atomic-template.h" 61 | 62 | #define DATA_BITS 64 63 | #include "./atomic-template.h" 64 | 65 | } // namespace xutil 66 | 67 | } // namespace xstore 68 | -------------------------------------------------------------------------------- /deps/rlib/tests/fast_random.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../core/common.hh" 6 | 7 | namespace test { 8 | 9 | using namespace rdmaio; 10 | 11 | // taken from java: 12 | // http://developer.classpath.org/doc/java/util/Random-source.html 13 | class FastRandom { 14 | public: 15 | FastRandom(unsigned long seed) : seed(0) { set_seed0(seed); } 16 | 17 | FastRandom() : seed(0) { set_seed0(seed); } 18 | 19 | inline unsigned long next() { 20 | return ((unsigned long)next(32) << 32) + next(32); 21 | } 22 | 23 | inline uint32_t next_u32() { return next(32); } 24 | 25 | inline uint16_t next_u16() { return next(16); } 26 | 27 | /** [0.0, 1.0) */ 28 | inline double next_uniform() { 29 | return (((unsigned long)next(26) << 27) + next(27)) / (double)(1L << 53); 30 | } 31 | 32 | inline char next_char() { return next(8) % 256; } 33 | 34 | inline std::string next_string(size_t len) { 35 | std::string s(len, 0); 36 | for (size_t i = 0; i < len; i++) 37 | s[i] = next_char(); 38 | return s; 39 | } 40 | 41 | inline unsigned long get_seed() { return seed; } 42 | 43 | inline void set_seed(unsigned long seed) { this->seed = seed; } 44 | 45 | inline void set_seed0(unsigned long seed) { 46 | this->seed = (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1); 47 | } 48 | 49 | template inline i64 rand_number(T min, T max) { 50 | return check_between_inclusive( 51 | (i64)(next_uniform() * (max - min + 1) + min), min, max); 52 | } 53 | 54 | inline i64 check_between_inclusive(i64 v, i64 min, i64 max) { 55 | assert(v >= min); 56 | assert(v <= max); 57 | return v; 58 | } 59 | 60 | private: 61 | inline unsigned long next(unsigned int bits) { 62 | seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1); 63 | return (unsigned long)(seed >> (48 - bits)); 64 | } 65 | 66 | unsigned long seed; 67 | }; 68 | 69 | } // namespace test 70 | -------------------------------------------------------------------------------- /deps/r2/src/ring_msg/ring.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "rlib/core/rmem/handler.hh" 4 | 5 | #include "../mem_block.hh" 6 | 7 | namespace r2 { 8 | 9 | namespace ring_msg { 10 | 11 | using namespace rdmaio::rmem; 12 | 13 | /*! 14 | Remote ring store remote ring buffer information 15 | */ 16 | template struct RemoteRing { 17 | usize tailer = 0; 18 | usize base_addr = 0; 19 | u32 mem_key = 0; 20 | 21 | explicit RemoteRing(const usize &base_addr, const u32 &key) 22 | : base_addr(base_addr), mem_key(key) {} 23 | 24 | RemoteRing() = default; 25 | 26 | usize next_addr(const usize &sz) { 27 | auto ret = tailer; 28 | tailer = (tailer + sz) % kRingSz; 29 | return ret + base_addr; 30 | } 31 | }; 32 | 33 | /*! 34 | Local ring store local ring information 35 | R: The size of the ring buffer 36 | */ 37 | template 38 | struct LocalRing { 39 | MemBlock local_mem; 40 | usize tailer = 0; 41 | usize header = 0; 42 | 43 | explicit LocalRing(const MemBlock &mem) : local_mem(mem) { 44 | ASSERT(mem.sz >= R); 45 | } 46 | 47 | LocalRing() : LocalRing(MemBlock(nullptr, 0)) {} 48 | ~LocalRing() = default; 49 | 50 | inline Option cur_msg(const usize &sz) { 51 | if (unlikely(sz + tailer > local_mem.sz)) { 52 | return {}; 53 | } 54 | auto temp = increment_tailer(sz); 55 | return MemBlock((char *)(local_mem.mem_ptr) + temp, sz); 56 | } 57 | 58 | u64 convert_to_rdma_addr(const RegAttr &attr) const { 59 | // invariant checks 60 | ASSERT((u64)attr.buf <= (u64)local_mem.mem_ptr); 61 | ASSERT((u64)local_mem.mem_ptr + local_mem.sz <= 62 | (u64)attr.buf + (u64)attr.sz); 63 | return (u64)local_mem.mem_ptr - (u64)attr.buf; 64 | } 65 | 66 | private: 67 | // wo check, so it's private 68 | usize increment_tailer(const usize &sz) { 69 | auto cur_tailer = tailer; 70 | tailer = (tailer + sz) % R; 71 | return cur_tailer; 72 | } 73 | }; 74 | } // namespace ring_msg 75 | 76 | } // namespace r2 77 | -------------------------------------------------------------------------------- /deps/rlib/README.md: -------------------------------------------------------------------------------- 1 | RLib provides several new abstractions for easier use of RDMA. 2 | It is a header-only library with minimal dependices, i.e., `ibverbs`. 3 | 4 | Please find examples in `./examples` for how to use RLib. 5 | For detailed documentations or benchmark results (including code and scripts), 6 | please check `docs`. 7 | 8 | ## Example 9 | 10 | Here is a simplified example of using RLib to implement an one-sided READ: 11 | ```c++ 12 | Arc qp; // some pre-initialized QP 13 | 14 | // An example of using Op to post an one-sided RDMA read. 15 | ::rdmaio::qp::Op op; 16 | op.set_rdma_rbuf(rmr.buf + 0xc, rmr.key).set_read(); 17 | op.set_payload((u64)(lmr.buf), sizeof(u64), lmr.key) 18 | 19 | // post the requests 20 | auto ret = op.execute(qp, IBV_SEND_SIGNALED); 21 | RDMA_ASSERT(ret == IOCode::Ok); 22 | 23 | // wait for the completion 24 | auto res = qp->wait_one_comp(); 25 | RDMA_ASSERT(res == IOCode::Ok) << "req error: " << res.desc; 26 | 27 | ``` 28 | 29 | For more examples, please check the `examples` folder. 30 | There is a description of the examples in `docs/examples/` . 31 | 32 | ## License 33 | 34 | RLib is released under the [Apache 2.0 license](http://www.apache.org/licenses/LICENSE-2.0.html). 35 | 36 | As RLib is the refined execution framework of DrTM+H, 37 | if you use RLib in your research, please cite our paper: 38 | 39 | @inproceedings {drtmhosdi18, 40 | author = {Xingda Wei and Zhiyuan Dong and Rong Chen and Haibo Chen}, 41 | title = {Deconstructing RDMA-enabled Distributed Transactions: Hybrid is Better!}, 42 | booktitle = {13th {USENIX} Symposium on Operating Systems Design and Implementation ({OSDI} 18)}, 43 | year = {2018}, 44 | isbn = {978-1-939133-08-3}, 45 | address = {Carlsbad, CA}, 46 | pages = {233--251}, 47 | url = {https://www.usenix.org/conference/osdi18/presentation/wei}, 48 | publisher = {{USENIX} Association}, 49 | month = oct, 50 | } 51 | -------------------------------------------------------------------------------- /deps/r2/tests/test_srop.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "rlib/core/lib.hh" 4 | #include "../src/rdma/sop.hh" 5 | 6 | namespace test 7 | { 8 | 9 | using namespace rdmaio; 10 | using namespace r2::rdma; 11 | using namespace r2; 12 | 13 | TEST(RDMA, sop) 14 | { 15 | auto res = RNicInfo::query_dev_names(); 16 | ASSERT_FALSE(res.empty()); 17 | auto nic = std::make_shared(res[0]); 18 | ASSERT_TRUE(nic->valid()); 19 | 20 | auto config = QPConfig(); 21 | auto qpp = RC::create(nic, config).value(); 22 | ASSERT_TRUE(qpp->valid()); 23 | 24 | // try send an RDMA request 25 | // init the memory 26 | auto mem = Arc(new RMem(1024)); // allocate a memory with 1K bytes 27 | ASSERT_TRUE(mem->valid()); 28 | 29 | // register it to the Nic 30 | RegHandler handler(mem, nic); 31 | ASSERT_TRUE(handler.valid()); 32 | 33 | auto mr = handler.get_reg_attr().value(); 34 | 35 | RC &qp = *qpp; 36 | qp.bind_remote_mr(mr); 37 | qp.bind_local_mr(mr); 38 | 39 | // finally connect to myself 40 | auto res_c = qp.connect(qp.my_attr()); 41 | RDMA_ASSERT(res_c == IOCode::Ok); 42 | 43 | u64 *test_loc = reinterpret_cast(mem->raw_ptr); 44 | *test_loc = 73; 45 | ASSERT_NE(73, test_loc[1]); // use the next entry to store the read value 46 | 47 | SROp op; 48 | op.set_payload(&test_loc[1],sizeof(u64)).set_remote_addr(0x0).set_read(); 49 | 50 | auto ret = op.execute_sync(qpp,IBV_SEND_SIGNALED); 51 | ASSERT(ret == IOCode::Ok); 52 | ASSERT_EQ(test_loc[1],73); 53 | 54 | // now we test async op 55 | bool runned = false; 56 | SScheduler ssched; 57 | ssched.spawn([qpp, test_loc, &op, &runned](R2_ASYNC) { 58 | op.set_write(); 59 | test_loc[1] = 52; 60 | ASSERT_NE(test_loc[0], 52); 61 | auto ret = op.execute(qpp, IBV_SEND_SIGNALED, R2_ASYNC_WAIT); 62 | R2_YIELD; 63 | ASSERT(ret == IOCode::Ok); 64 | ASSERT_EQ(test_loc[0], 52); 65 | runned = true; 66 | 67 | R2_STOP(); 68 | R2_RET; 69 | }); 70 | ssched.run(); 71 | ASSERT_TRUE(runned); 72 | } 73 | } // namespace test 74 | -------------------------------------------------------------------------------- /deps/r2/src/linked_list.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../src/common.hh" 4 | 5 | namespace r2 { 6 | 7 | template struct Node { 8 | T val; 9 | 10 | Node *prev_p = nullptr; 11 | Node *next_p = nullptr; 12 | 13 | explicit Node(const T &val) : val(val) {} 14 | 15 | template Node(Args... args) : val(args...) {} 16 | 17 | ~Node() { 18 | } 19 | 20 | Node *set_prev(Node *p) { 21 | this->prev_p = p; 22 | return this; 23 | } 24 | 25 | Node *set_next(Node *p) { 26 | this->next_p = p; 27 | return this; 28 | } 29 | }; 30 | 31 | template class LinkedList { 32 | public: 33 | Node *header_p = nullptr; 34 | Node *tailer_p = nullptr; 35 | 36 | bool null() const { return header_p == nullptr; } 37 | 38 | inline Node *add(Node *n) { 39 | auto prev = tailer_p; 40 | 41 | if (unlikely(null())) { 42 | tailer_p = (header_p = n); 43 | prev = n; 44 | } else { 45 | assert(tailer_p != nullptr); 46 | assert(tailer_p->next_p == header_p); 47 | } 48 | tailer_p->set_next(n); 49 | tailer_p = n; 50 | 51 | // reset n's position 52 | n->set_prev(prev)->set_next(header_p); 53 | 54 | return n; 55 | } 56 | 57 | /*! 58 | \note: the n must be in the list 59 | \ret: the next element 60 | TODO: what if there is only one coroutine ? 61 | */ 62 | inline Node *leave_one(Node *n) { 63 | auto next = n->next_p; 64 | n->prev_p->set_next(next); 65 | n->next_p->set_prev(n->prev_p); 66 | 67 | if (tailer_p == n) { 68 | tailer_p = n->prev_p; 69 | } 70 | n->set_prev(nullptr)->set_next(nullptr); 71 | return next; 72 | } 73 | 74 | /*! 75 | Peek the first node from the list 76 | */ 77 | inline Option *> peek() { 78 | if (unlikely(null())) 79 | return {}; 80 | auto res = header_p; 81 | if (unlikely(header_p->next_p == header_p)) 82 | header_p = nullptr; 83 | else 84 | header_p = header_p->next_p; 85 | 86 | return res; 87 | } 88 | }; 89 | 90 | } // namespace r2 91 | -------------------------------------------------------------------------------- /xcomm/src/atomic_rw/wrapper_type.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../../deps/r2/src/common.hh" 4 | #include "./rw_trait.hh" 5 | 6 | #include "./ptr.hh" 7 | 8 | namespace xstore { 9 | 10 | namespace xcomm { 11 | 12 | namespace rw { 13 | 14 | using namespace r2; 15 | 16 | const u32 kInvalidSeq = 0; 17 | 18 | template struct __attribute__((packed)) WrappedType { 19 | // when the seq equals invalid seq, then it is being written 20 | volatile u32 seq = kInvalidSeq + 1; 21 | T payload; 22 | volatile u32 seq_check; 23 | 24 | public: 25 | WrappedType() = default; 26 | 27 | WrappedType(const T &p) : payload(p) { 28 | this->init(); 29 | } 30 | 31 | void init() { 32 | this->seq = kInvalidSeq + 1; 33 | this->seq_check = this->seq; 34 | } 35 | 36 | /*! 37 | reset the content of the wrapped type 38 | */ 39 | void reset(const T &t) { 40 | this->init(); 41 | this->payload = t; 42 | } 43 | 44 | T &get_payload() { return payload; } 45 | 46 | T *get_payload_ptr() { return &payload; } 47 | 48 | // sz of the meta data, namely, two seqs 49 | static auto meta_sz() -> usize { 50 | return sizeof(seq) + sizeof(seq_check); 51 | } 52 | 53 | inline bool consistent() const { 54 | return (this->seq == this->seq_check) && (this->seq != kInvalidSeq); 55 | } 56 | 57 | /* 58 | To perform an update on the object atomically, 59 | one must first call the before write, and then call the done write 60 | */ 61 | inline auto begin_write() -> u32 { 62 | auto ret = this->seq_check; 63 | this->seq_check = kInvalidSeq; 64 | this->seq = kInvalidSeq; 65 | ::r2::compile_fence(); 66 | return ret; 67 | } 68 | 69 | // seq must be the return value of begin_write 70 | inline void done_write(const u32 &seq) { 71 | // the update of *seqs* should after previous writes 72 | ::r2::compile_fence(); 73 | this->seq = seq + 1; 74 | this->seq_check = this->seq; 75 | ::r2::compile_fence(); 76 | } 77 | } __attribute__((aligned(64))); 78 | 79 | } // namespace rw 80 | } // namespace xcomm 81 | } // namespace xstore 82 | -------------------------------------------------------------------------------- /xcomm/src/batch_rw_op.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "./lib.hh" 4 | 5 | #include "../../deps/rlib/core/qps/op.hh" 6 | #include "../../deps/r2/src/rdma/async_op.hh" 7 | 8 | namespace xstore { 9 | 10 | namespace xcomm { 11 | 12 | using namespace rdmaio; 13 | using namespace qp; 14 | using namespace r2; 15 | 16 | template struct BatchOp { 17 | ::rdmaio::qp::Op<1> ops[N]; 18 | int cur_idx; 19 | 20 | BatchOp() : ops(), cur_idx(-1) { 21 | for (uint i = 0; i < N; ++i) { 22 | ops[i].set_next(&ops[i + 1]); 23 | } 24 | } 25 | 26 | auto emplace() { cur_idx += 1; } 27 | 28 | auto get_cur_op() -> ::rdmaio::qp::Op<1> & { return ops[cur_idx]; } 29 | 30 | auto reset() { cur_idx = -1; } 31 | 32 | /*! 33 | \note: Assumption!!!! 34 | we assumes all ops are unsignaled. 35 | We will manually signal the last op. 36 | */ 37 | auto execute_async(const Arc &qp, R2_ASYNC) -> Result { 38 | ::r2::rdma::AsyncOp<> dummy; 39 | RC *qp_ptr = ({ // unsafe code 40 | RC *temp = qp.get(); 41 | temp; 42 | }); 43 | 44 | ibv_wc wc; 45 | if (unlikely(cur_idx < 0)) { 46 | // trivial 47 | return ::rdmaio::Ok(wc); 48 | } 49 | 50 | // sanity check 51 | ASSERT(cur_idx < N); 52 | 53 | // set the flag 54 | auto &op = this->get_cur_op(); 55 | int temp_flag = op.wr.send_flags; 56 | op.set_flags(temp_flag | IBV_SEND_SIGNALED); 57 | op.wr.next = nullptr; 58 | op.wr.wr_id = qp_ptr->encode_my_wr(R2_COR_ID(),cur_idx + 1); 59 | 60 | // 2. send the doorbell 61 | struct ibv_send_wr *bad_sr = nullptr; 62 | auto rc = ibv_post_send(qp_ptr->qp, &(this->ops[0].wr), &bad_sr); 63 | if (unlikely(rc != 0)) { 64 | return ::rdmaio::Err(wc); 65 | } 66 | qp_ptr->out_signaled += 1; 67 | 68 | auto ret = dummy.wait_one(qp, R2_ASYNC_WAIT); 69 | 70 | // reset 71 | op.set_next(&ops[cur_idx + 1]); 72 | op.wr.send_flags = temp_flag; 73 | 74 | // should be invalid 75 | this->reset(); 76 | 77 | return ret; 78 | } 79 | }; 80 | 81 | } // namespace xcomm 82 | } // namespace xstore 83 | -------------------------------------------------------------------------------- /rolex/remote_requests.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lib.hh" /// Arc 4 | #include "r2/src/libroutine.hh" 5 | #include "r2/src/rdma/async_op.hh" /// AsyncOp 6 | #include "rlib/core/qps/rc.hh" /// RC 7 | #include "xcomm/src/batch_rw_op.hh" /// BatchOp 8 | 9 | #include "trait.hpp" 10 | 11 | 12 | using namespace r2; 13 | using namespace r2::rdma; 14 | using namespace rdma::qp; 15 | using namespace xstore::xcomm; 16 | using namespace xstore; 17 | 18 | namespace rolex { 19 | 20 | // calculate the offsets of the leaf 21 | inline auto remote_leaf_offsets(u64 num) -> u64 { return sizeof(u64)*2 + num*sizeof(leaf_t); } 22 | 23 | void get_remote_leaf(const u64 &leaf_num, const ::xstore::Arc& data_rc, 24 | char* local_data_buf) 25 | { 26 | Op<> leaf_op; 27 | leaf_op.set_rdma_addr(remote_leaf_offsets(leaf_num), data_rc->remote_mr.value()) 28 | .set_read() 29 | .set_payload(local_data_buf, sizeof(leaf_t), data_rc->local_mr.value().lkey); 30 | RDMA_ASSERT(leaf_op.execute(data_rc, IBV_SEND_SIGNALED) == IOCode::Ok); 31 | RDMA_ASSERT(data_rc->wait_one_comp() == IOCode::Ok); 32 | 33 | leaf_t* leaf = reinterpret_cast(local_data_buf); 34 | leaf->print(); 35 | leaf->insert_not_full(3, 3); 36 | leaf->print(); 37 | 38 | leaf_op.set_rdma_addr(remote_leaf_offsets(leaf_num), data_rc->remote_mr.value()) 39 | .set_write() 40 | .set_payload(local_data_buf, sizeof(leaf_t), data_rc->local_mr.value().lkey); 41 | RDMA_ASSERT(leaf_op.execute(data_rc, IBV_SEND_SIGNALED) == IOCode::Ok); 42 | RDMA_ASSERT(data_rc->wait_one_comp() == IOCode::Ok); 43 | } 44 | 45 | 46 | void write_remote_leaf(const u64 &leaf_num, const ::xstore::Arc& data_rc, 47 | char* local_data_buf) 48 | { 49 | Op<> leaf_op; 50 | leaf_op.set_rdma_addr(remote_leaf_offsets(leaf_num), data_rc->remote_mr.value()) 51 | .set_write() 52 | .set_payload(local_data_buf, sizeof(leaf_t), data_rc->local_mr.value().lkey); 53 | RDMA_ASSERT(leaf_op.execute(data_rc, IBV_SEND_SIGNALED) == IOCode::Ok); 54 | RDMA_ASSERT(data_rc->wait_one_comp() == IOCode::Ok); 55 | } 56 | 57 | 58 | } // namespace rolex -------------------------------------------------------------------------------- /deps/rlib/examples/rc_write/server.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../../core/lib.hh" 4 | 5 | DEFINE_int64(port, 8888, "Server listener (UDP) port."); 6 | DEFINE_int64(use_nic_idx, 0, "Which NIC to create QP"); 7 | DEFINE_int64(reg_nic_name, 73, "The name to register an opened NIC at rctrl."); 8 | DEFINE_int64(reg_mem_name, 73, "The name to register an MR at rctrl."); 9 | DEFINE_uint64(magic_num, 0xdeadbeaf, "The magic number read by the client"); 10 | 11 | using namespace rdmaio; 12 | using namespace rdmaio::rmem; 13 | 14 | int main(int argc, char **argv) { 15 | 16 | gflags::ParseCommandLineFlags(&argc, &argv, true); 17 | 18 | // start a controler, so that others may access it using UDP based channel 19 | RCtrl ctrl(FLAGS_port); 20 | RDMA_LOG(4) << "Pingping server listenes at localhost:" << FLAGS_port; 21 | 22 | // first we open the NIC 23 | { 24 | auto nic = 25 | RNic::create(RNicInfo::query_dev_names().at(FLAGS_use_nic_idx)).value(); 26 | 27 | // register the nic with name 0 to the ctrl 28 | RDMA_ASSERT(ctrl.opened_nics.reg(FLAGS_reg_nic_name, nic)); 29 | } 30 | 31 | { 32 | // allocate a memory (with 1024 bytes) so that remote QP can access it 33 | RDMA_ASSERT(ctrl.registered_mrs.create_then_reg( 34 | FLAGS_reg_mem_name, Arc(new RMem(1024)), 35 | ctrl.opened_nics.query(FLAGS_reg_nic_name).value())); 36 | } 37 | 38 | // initialzie the value so as client can sanity check its content 39 | u64 *reg_mem = (u64 *)(ctrl.registered_mrs.query(FLAGS_reg_mem_name) 40 | .value() 41 | ->get_reg_attr() 42 | .value() 43 | .buf); 44 | memcpy(reg_mem, "Hello world", strlen("Hello world")); 45 | // start the listener thread so that client can communicate w it 46 | ctrl.start_daemon(); 47 | 48 | RDMA_LOG(2) << "RC pingpong server started!"; 49 | // run for 20 seconds 50 | for (uint i = 0;i < 20; ++i) { 51 | // server does nothing because it is RDMA 52 | // client will read the reg_mem using RDMA 53 | RDMA_LOG(4) << "check content: " << (char *)reg_mem; 54 | sleep(1); 55 | } 56 | RDMA_LOG(4) << "server exit!"; 57 | } 58 | -------------------------------------------------------------------------------- /deps/rlib/tests/test_channel.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../core/bootstrap/channel.hh" 4 | 5 | namespace test { 6 | 7 | using namespace rdmaio; 8 | using namespace rdmaio::bootstrap; 9 | 10 | TEST(Channel, Naming) { 11 | auto host = "localhost"; 12 | auto ip = IPNameHelper::host2ip(host); 13 | RDMA_ASSERT(ip == IOCode::Ok); 14 | RDMA_LOG(4) << "parsed ip: " << ip.desc; 15 | //auto ip1 = IPNameHelper::host2ip("val02"); 16 | auto ip1 = IPNameHelper::host2ip("192.168.3.101"); 17 | RDMA_ASSERT(ip1 == IOCode::Ok); 18 | RDMA_LOG(4) << "parsed ip for val02: " << ip1.desc; 19 | 20 | auto ip3 = IPNameHelper::host2ip(" 192.168.3.101 "); 21 | RDMA_ASSERT(ip3 == IOCode::Ok) 22 | << "get ip3 code: " << ip3.code.name() << " " << ip3.desc; 23 | ASSERT_EQ(ip3.desc, ip1.desc); 24 | } 25 | 26 | TEST(Channel, Basic) { 27 | const usize total_sent = 12; 28 | 29 | auto send_c = SendChannel::create("localhost:7777").value(); 30 | RDMA_LOG(2) << "create send channel done"; 31 | 32 | auto recv_c = RecvChannel::create(7777).value(); 33 | RDMA_LOG(2) << "create recv channel done"; 34 | 35 | //auto recv_c_fail = RecvChannel::create(8888); 36 | //ASSERT_FALSE(recv_c_fail); 37 | 38 | for (uint i = 0; i < total_sent; ++i) { 39 | auto b = Marshal::dump(i + 73); 40 | send_c->send(b); 41 | } 42 | 43 | RDMA_LOG(2) << "send all done"; 44 | 45 | usize count = 0; 46 | for (recv_c->start(); recv_c->has_msg(); recv_c->next(), count += 1) { 47 | auto &msg = recv_c->cur(); 48 | u64 val = Marshal::dedump(msg).value(); 49 | ASSERT_EQ(val, count + 73); 50 | 51 | // now prepare the reply 52 | auto reply = Marshal::dump(count + 75); 53 | recv_c->reply_cur(reply); 54 | } 55 | 56 | ASSERT_EQ(count, total_sent); 57 | 58 | RDMA_LOG(2) << "start sanity check replies"; 59 | 60 | // finally we check the reply 61 | for (uint i = 0; i < total_sent; ++i) { 62 | auto reply_res = send_c->recv(); 63 | RDMA_ASSERT(reply_res == IOCode::Ok); 64 | auto &msg = reply_res.desc; 65 | u64 val = Marshal::dedump(msg).value(); 66 | ASSERT_EQ(val, i + 75); 67 | } 68 | RDMA_LOG(2) << "check replies done, ok"; 69 | } 70 | 71 | } // namespace test 72 | -------------------------------------------------------------------------------- /deps/rlib/core/utils/marshal.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../common.hh" 6 | 7 | namespace rdmaio { 8 | 9 | using ByteBuffer = std::string; 10 | 11 | /*! 12 | A simple, basic use of helper methods for marshaling/unmarshaling data from 13 | byte buffer. 14 | A bytebuffer is basically a c++ string. Any alternative containiner is also 15 | suitable. 16 | 17 | Example: 18 | 1. get a u8 buf initialized with 0. 19 | ` auto buf = Marshal::alloc(size);` 20 | 2. Dump a struct to a buf, and dedump it to get it. 21 | ` struct __attribute__((packed)) A { // note struct must be packed 22 | u8 a; 23 | u64 b; 24 | }; 25 | A temp; 26 | ByteBuffer buf = Marshal::dump(temp); 27 | assert(Marshal::dedump(buf).value() == temp); // note this is an option. 28 | ` 29 | */ 30 | class Marshal { 31 | public: 32 | static ByteBuffer alloc(usize size) { return ByteBuffer(size, '0'); } 33 | 34 | /*! 35 | Subtract the current buffer at offset. 36 | If offset is smaller than the buf.size(), then return an ByteBuffer. 37 | Otherwise, return {}. 38 | */ 39 | static Option forward(const ByteBuffer &buf, usize off) { 40 | if (off < buf.size()) { 41 | return Option(buf.substr(off, buf.size() - off)); 42 | } 43 | return {}; 44 | } 45 | 46 | static bool safe_set_byte(ByteBuffer &buf, usize off, u8 data) { 47 | if (off < buf.size()) { 48 | *((u8 *)(buf.data() + off)) = data; // unsafe code 49 | return true; 50 | } 51 | return false; 52 | } 53 | 54 | // dump a type with its default constructor 55 | template static ByteBuffer dump_null() { 56 | T t; 57 | return dump(t); 58 | } 59 | 60 | template static ByteBuffer dump(const T &t) { 61 | auto buf = alloc(sizeof(T)); 62 | memcpy((void *)buf.data(), &t, sizeof(T)); // unsafe code 63 | return buf; 64 | } 65 | 66 | template static Option dedump(const ByteBuffer &b) { 67 | if (b.size() >= sizeof(T)) { 68 | T res; 69 | memcpy((char *)(&res), b.data(), sizeof(T)); 70 | return Option(res); 71 | } 72 | return {}; 73 | } 74 | }; 75 | 76 | } // namespace rdmaio 77 | -------------------------------------------------------------------------------- /deps/rlib/tests/random.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../core/common.hh" 6 | 7 | namespace test 8 | { 9 | 10 | using namespace rdmaio; 11 | 12 | // taken from java: 13 | // http://developer.classpath.org/doc/java/util/Random-source.html 14 | class FastRandom 15 | { 16 | public: 17 | FastRandom(usize seed) 18 | : seed(0) 19 | { 20 | set_seed0(seed); 21 | } 22 | 23 | FastRandom() : seed(0) 24 | { 25 | set_seed0(seed); 26 | } 27 | 28 | inline unsigned long next() 29 | { 30 | return ((unsigned long)next(32) << 32) + next(32); 31 | } 32 | 33 | inline uint32_t next_u32() 34 | { 35 | return next(32); 36 | } 37 | 38 | inline uint16_t next_u16() 39 | { 40 | return next(16); 41 | } 42 | 43 | /** [0.0, 1.0) */ 44 | inline double next_uniform() 45 | { 46 | return (((unsigned long)next(26) << 27) + next(27)) / (double)(1L << 53); 47 | } 48 | 49 | inline char next_char() 50 | { 51 | return next(8) % 256; 52 | } 53 | 54 | inline std::string next_string(size_t len) 55 | { 56 | std::string s(len, 0); 57 | for (size_t i = 0; i < len; i++) 58 | s[i] = next_char(); 59 | return s; 60 | } 61 | 62 | inline unsigned long get_seed() 63 | { 64 | return seed; 65 | } 66 | 67 | inline void set_seed(unsigned long seed) 68 | { 69 | this->seed = seed; 70 | } 71 | 72 | inline void set_seed0(unsigned long seed) 73 | { 74 | this->seed = (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1); 75 | } 76 | 77 | template 78 | inline i64 rand_number(T min, T max) 79 | { 80 | return check_between_inclusive((i64)(next_uniform() * (max - min + 1) + min), min, max); 81 | } 82 | 83 | inline i64 check_between_inclusive(i64 v, i64 min, i64 max) 84 | { 85 | assert(v >= min); 86 | assert(v <= max); 87 | return v; 88 | } 89 | 90 | private: 91 | inline unsigned long 92 | next(unsigned int bits) 93 | { 94 | seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1); 95 | return (unsigned long)(seed >> (48 - bits)); 96 | } 97 | 98 | unsigned long seed; 99 | }; 100 | 101 | 102 | } 103 | -------------------------------------------------------------------------------- /deps/rlib/examples/rc_pingpong/server.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../../core/lib.hh" 4 | 5 | DEFINE_int64(port, 8888, "Server listener (UDP) port."); 6 | DEFINE_int64(use_nic_idx, 0, "Which NIC to create QP"); 7 | DEFINE_int64(reg_nic_name, 73, "The name to register an opened NIC at rctrl."); 8 | DEFINE_int64(reg_mem_name, 73, "The name to register an MR at rctrl."); 9 | DEFINE_uint64(magic_num, 0xdeadbeaf, "The magic number read by the client"); 10 | 11 | using namespace rdmaio; 12 | using namespace rdmaio::rmem; 13 | 14 | int main(int argc, char **argv) { 15 | 16 | gflags::ParseCommandLineFlags(&argc, &argv, true); 17 | 18 | // start a controler, so that others may access it using UDP based channel 19 | RCtrl ctrl(FLAGS_port); 20 | RDMA_LOG(4) << "Pingping server listenes at localhost:" << FLAGS_port; 21 | 22 | // first we open the NIC 23 | { 24 | auto nic = 25 | RNic::create(RNicInfo::query_dev_names().at(FLAGS_use_nic_idx)).value(); 26 | 27 | // register the nic with name 0 to the ctrl 28 | RDMA_ASSERT(ctrl.opened_nics.reg(FLAGS_reg_nic_name, nic)); 29 | } 30 | 31 | { 32 | // allocate a memory (with 1024 bytes) so that remote QP can access it 33 | RDMA_ASSERT(ctrl.registered_mrs.create_then_reg( 34 | FLAGS_reg_mem_name, Arc(new RMem(1024)), 35 | ctrl.opened_nics.query(FLAGS_reg_nic_name).value())); 36 | } 37 | 38 | // initialzie the value so as client can sanity check its content 39 | u64 *reg_mem = (u64 *)(ctrl.registered_mrs.query(FLAGS_reg_mem_name) 40 | .value() 41 | ->get_reg_attr() 42 | .value() 43 | .buf); 44 | // setup the value 45 | for(uint i = 0;i < 12;++i) { 46 | reg_mem[i] = FLAGS_magic_num + i; 47 | asm volatile("" ::: "memory"); 48 | } 49 | 50 | // start the listener thread so that client can communicate w it 51 | ctrl.start_daemon(); 52 | 53 | RDMA_LOG(2) << "RC pingpong server started!"; 54 | // run for 20 seconds 55 | for (uint i = 0;i < 20; ++i) { 56 | // server does nothing because it is RDMA 57 | // client will read the reg_mem using RDMA 58 | sleep(1); 59 | } 60 | RDMA_LOG(4) << "server exit!"; 61 | } 62 | -------------------------------------------------------------------------------- /deps/rlib/benchs/reporter.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../core/utils/timer.hh" 6 | 7 | #include "./statics.hh" 8 | 9 | namespace rdmaio { 10 | 11 | struct Reporter { 12 | static double report_thpt(std::vector &statics, int epoches) { 13 | 14 | std::vector old_statics(statics.size()); 15 | 16 | Timer timer; 17 | for (int epoch = 0; epoch < epoches; epoch += 1) { 18 | sleep(1); 19 | 20 | u64 sum = 0; 21 | // now report the throughput 22 | for (uint i = 0; i < statics.size(); ++i) { 23 | auto temp = statics[i].data.counter; 24 | sum += (temp - old_statics[i].data.counter); 25 | old_statics[i].data.counter = temp; 26 | } 27 | 28 | double passed_msec = timer.passed_msec(); 29 | double res = static_cast(sum) / passed_msec * 1000000.0; 30 | ::rdmaio::compile_fence(); 31 | timer.reset(); 32 | 33 | RDMA_LOG(2) << "epoch @ " << epoch << ": thpt: " << res << " reqs/sec." 34 | << passed_msec << " msec passed since last epoch."; 35 | } 36 | return 0.0; 37 | } 38 | 39 | static double report_bandwidth(std::vector &statics, int epoches, const usize &payload_per_req) { 40 | 41 | std::vector old_statics(statics.size()); 42 | 43 | Timer timer; 44 | for (int epoch = 0; epoch < epoches; epoch += 1) { 45 | sleep(1); 46 | 47 | u64 sum = 0; 48 | // now report the throughput 49 | for (uint i = 0; i < statics.size(); ++i) { 50 | auto temp = statics[i].data.counter; 51 | sum += (temp - old_statics[i].data.counter); 52 | old_statics[i].data.counter = temp; 53 | } 54 | 55 | double passed_msec = timer.passed_msec(); 56 | double res = static_cast(sum) / passed_msec * 1000000.0; 57 | 58 | double bw = res * payload_per_req; 59 | ::rdmaio::compile_fence(); 60 | timer.reset(); 61 | 62 | RDMA_LOG(2) << "epoch @ " << epoch << ": thpt: " << res << " reqs/sec, " 63 | << "bandwidht: " << bw / (1024L * 1024 * 1024) * 8 << " Gbps;" 64 | << passed_msec << " msec passed since last epoch."; 65 | } 66 | return 0.0; 67 | } 68 | }; 69 | 70 | } // namespace rdmaio 71 | -------------------------------------------------------------------------------- /deps/rlib/docs/examples/TUTORIALS.md: -------------------------------------------------------------------------------- 1 | # Benchmark Tutorials 2 | 3 | ## Table of Contents 4 | 5 | * [rc_pingpong](#rcpp) 6 | * [ud_pingpong](#udpp) 7 | * [rc_overflow](#rcof) 8 | * [ud_overflow](#udof) 9 | 10 | 11 | 12 | ## rc_pingpong 13 | * A simple example of how to use **RDMA read** to get server message from its memory. 14 | 15 | ```bash 16 | $cd scripts/ 17 | $./bootstrap.py -f make.toml 18 | $./bootstrap.py -f run.toml 19 | ``` 20 | 21 | 22 | 23 | ## ud_pingpong 24 | * A simple example of how to use **two-sided RDMA** to send & recv ud message. 25 | You can type message to send in console when running client and it will be received by server. 26 | 27 | *P.S. Do not use scripts.* 28 | 29 | 30 | 31 | 32 | ## rc_overflow 33 | * An example to show what will happen by using **RC** transport mode when server's memory buffer is overflowed. 34 | * Server will record how many messages it actually receives and compare it with how many messages client has sent. They are equal as follow. 35 | 36 | ```bash 37 | $cd scripts/ 38 | $./bootstrap.py -f examples/rc_overflow/make.toml 39 | $./bootstrap.py -f examples/rc_overflow/run.toml 40 | 41 | [server.cc:52] (RC) Pingping server listenes at localhost:8888 42 | [server.cc:68] Register test_channel 43 | [client.cc:49] rc client ready to send message to the server! 44 | [client.cc:73] rc client send 10000 msg in 177121 msec 45 | [server.cc:98] rc server receive 10000 msg, all 10000 msg 46 | [rctrl.hh:91] stop with :3 processed. 47 | ``` 48 | 49 | 50 | 51 | ## ud_overflow 52 | * An example to show what will happen by using **UD** transport mode when server's memory buffer is overflowed. 53 | * Server will record how many messages it actually receives and compare it with how many messages client has sent. They are not equal because of ud as follow. 54 | 55 | ```bash 56 | $cd scripts/ 57 | $./bootstrap.py -f examples/ud_overflow/make.toml 58 | $./bootstrap.py -f examples/ud_overflow/run.toml 59 | 60 | [server.cc:76] server wake up 61 | [client.cc:49] ud client ready to send message to the server! 62 | [client.cc:73] ud client send 10000 msg in 9751 msec 63 | [server.cc:98] ud server receive 128 msg, all 10000 msg 64 | [rctrl.hh:91] stop with :2 processed. 65 | ``` -------------------------------------------------------------------------------- /deps/r2/src/rdma/async_op.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../libroutine.hh" 4 | #include "rlib/core/qps/op.hh" 5 | 6 | namespace r2 { 7 | 8 | namespace rdma { 9 | 10 | using namespace rdmaio; 11 | using namespace rdmaio::qp; 12 | 13 | template 14 | struct AsyncOp : Op { 15 | double timeout_usec = 1000000; 16 | 17 | public: 18 | AsyncOp() = default; 19 | 20 | inline AsyncOp &set_timeout_usec(const double &tu) { 21 | this->timeout_usec = tu; 22 | return *this; 23 | } 24 | 25 | inline auto execute_async(const Arc &qp, int flags, R2_ASYNC) 26 | -> Result { 27 | ibv_wc wc; 28 | auto ret_s = this->execute(qp, flags, R2_COR_ID()); 29 | if (unlikely(ret_s != IOCode::Ok)) return ::rdmaio::transfer(ret_s, wc); 30 | 31 | if (flags & IBV_SEND_SIGNALED) { 32 | return wait_one(qp, R2_ASYNC_WAIT); 33 | } 34 | return ::rdmaio::Ok(wc); 35 | } 36 | 37 | inline auto wait_one(const Arc &qp, R2_ASYNC) -> Result { 38 | // to avoid performance overhead of Arc, we first extract QP's raw pointer 39 | // out 40 | RC *qp_ptr = ({ // unsafe code 41 | RC *temp = qp.get(); 42 | temp; 43 | }); 44 | 45 | ibv_wc wc; 46 | auto id = R2_COR_ID(); 47 | 48 | poll_func_t poll_future = 49 | [qp_ptr, id]() -> Result> { 50 | auto wr_wc = qp_ptr->poll_rc_comp(); 51 | if (wr_wc) { 52 | ::r2::Routine::id_t polled_cid = 53 | static_cast<::r2::Routine::id_t>(std::get<0>(wr_wc.value())); 54 | // wc = std::get<1>(wr_wc.value()); 55 | auto wc = std::get<1>(wr_wc.value()); 56 | 57 | if (wc.status == IBV_WC_SUCCESS) { 58 | auto ret = std::make_pair(polled_cid, 1u); 59 | return ::rdmaio::Ok(ret); 60 | } else { 61 | return ::rdmaio::Err(std::make_pair<::r2::Routine::id_t>(id, 1u)); 62 | } 63 | } 64 | // we still need to poll this future 65 | return NotReady(std::make_pair<::r2::Routine::id_t>(0u, 0u)); 66 | }; 67 | 68 | // end spawning future 69 | auto ret = R2_PAUSE_WAIT(poll_future, 1); 70 | return ::rdmaio::transfer(ret, wc); 71 | } 72 | }; // namespace rdma 73 | } // namespace rdma 74 | 75 | } // namespace r2 76 | -------------------------------------------------------------------------------- /xcomm/src/rpc/reply_station.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../../../deps/r2/src/mem_block.hh" 6 | 7 | /*! 8 | Data structure for recording the replies 9 | */ 10 | 11 | namespace xstore { 12 | 13 | namespace rpc { 14 | 15 | using namespace r2; 16 | 17 | struct ReplyEntry 18 | { 19 | usize pending_replies = 0; 20 | MemBlock reply_buf; 21 | char* cur_ptr; 22 | 23 | ReplyEntry(const MemBlock& reply_buf) 24 | : pending_replies(1) 25 | , reply_buf(reply_buf) 26 | , cur_ptr(reinterpret_cast(reply_buf.mem_ptr)) 27 | {} 28 | 29 | ReplyEntry() = default; 30 | }; 31 | 32 | /*! 33 | Record the reply entries of all coroutines. 34 | Currently, we assume fixed coroutines stored using vector. 35 | The number of coroutines must be passed priori to the creation of the station. 36 | */ 37 | struct ReplyStation 38 | { 39 | // TODO: reply vector with T, which implements a mapping from corid -> 40 | // ReplyEntry 41 | std::vector cor_replies; 42 | 43 | explicit ReplyStation(int num_cors) 44 | : cor_replies(num_cors) 45 | {} 46 | 47 | /*! 48 | return whether there are pending replies 49 | */ 50 | auto add_pending_reply(const int& cor_id, const ReplyEntry& reply) -> bool 51 | { 52 | ASSERT(cor_id < cor_replies.size()); 53 | if (cor_replies[cor_id].pending_replies > 0) { 54 | return false; 55 | } 56 | cor_replies[cor_id] = reply; 57 | return true; 58 | } 59 | 60 | auto cor_ready(const int& cor_id) -> bool 61 | { 62 | return cor_replies[cor_id].pending_replies == 0; 63 | } 64 | 65 | /*! 66 | \ret: whether append reply is ok 67 | */ 68 | auto append_reply(const int& cor_id, const MemBlock& payload) -> bool 69 | { 70 | if (unlikely(this->cor_ready(cor_id))) { 71 | return false; 72 | } 73 | 74 | auto& r = this->cor_replies[cor_id]; 75 | ASSERT(r.cur_ptr + payload.sz <= 76 | (char*)r.reply_buf.mem_ptr + r.reply_buf.sz) 77 | << "overflow reply sz: " << payload.sz 78 | << "; total reply: " << r.reply_buf.sz; 79 | memcpy(r.cur_ptr, payload.mem_ptr, payload.sz); 80 | r.cur_ptr += payload.sz; 81 | 82 | r.pending_replies -= 1; 83 | return true; 84 | } 85 | }; 86 | } // namespace rpc 87 | } // namespace xstore 88 | -------------------------------------------------------------------------------- /deps/rlib/docs/benchs/op_performance.md: -------------------------------------------------------------------------------- 1 | # Benchmark Performance 2 | 3 | > Doorbell batching reqeusts can easily get the peek of total throughput. 4 | Thus, we use it to evaluate RDMA performance with different operation types. 5 | 6 | ## Table of Contents 7 | 8 | * [RO Doorbell Batching](#ro_db) 9 | * [WO Doorbell Batching](#wo_db) 10 | * [CAS Doorbell Batching](#cas_db) 11 | * [FAA Doorbell Batching](#faa_db) 12 | 13 | 14 | 15 | 16 | ## RO Doorbell Batching 17 | 18 | ```bash 19 | $make db_client 20 | $./db_client -client_name val08 -threads 12 -op_type 0 21 | ``` 22 | 23 | | Setup | per-thread | peek | 24 | | ----------------------- | ---------- | ------- | 25 | | 1 clients * 12 threads | 5.5M | 66M | 26 | | 2 clients * 12 threads | 5.5M | 132M | 27 | | 3 clients * 12 threads | 3.75M | 135M | 28 | 29 | 30 | 31 | 32 | ## WO Doorbell Batching 33 | 34 | ```bash 35 | $make db_client 36 | $./db_client -client_name val08 -threads 12 -op_type 1 37 | ``` 38 | 39 | | Setup | per-thread | peek | 40 | | ----------------------- | ---------- | ------- | 41 | | 1 clients * 12 threads | 4.75M | 57M | 42 | | 2 clients * 12 threads | 4.66M | 112M | 43 | | 3 clients * 12 threads | 3.41M | 123M | 44 | 45 | 46 | 47 | 48 | ## CAS Doorbell Batching 49 | 50 | ```bash 51 | $make db_client 52 | $./db_client -client_name val08 -threads 12 -op_type 2 53 | ``` 54 | 55 | | Setup | per-thread | peek | 56 | | ----------------------- | ---------- | ------- | 57 | | 1 clients * 12 threads | 2.08M | 25M | 58 | | 2 clients * 12 threads | 1.83M | 44M | 59 | | 3 clients * 12 threads | 1.33M | 48M | 60 | 61 | 62 | 63 | 64 | 65 | ## FAA Doorbell Batching 66 | 67 | ```bash 68 | $make db_client 69 | $./db_client -client_name val08 -threads 12 -op_type 3 70 | ``` 71 | 72 | | Setup | per-thread | peek | 73 | | ----------------------- | ---------- | ------- | 74 | | 1 clients * 12 threads | 1.66M | 20M | 75 | | 2 clients * 12 threads | 1.66M | 40M | 76 | | 3 clients * 12 threads | 1.33M | 48M | -------------------------------------------------------------------------------- /deps/rlib/tests/test_rc.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../core/qps/mod.hh" 4 | #include "../core/nicinfo.hh" 5 | 6 | #include "../core/utils/marshal.hh" 7 | 8 | namespace test { 9 | 10 | using namespace rdmaio::qp; 11 | using namespace rdmaio; 12 | 13 | TEST(RRC, basic) { 14 | 15 | auto res = RNicInfo::query_dev_names(); 16 | ASSERT_FALSE(res.empty()); 17 | auto nic = std::make_shared(res[0]); 18 | ASSERT_TRUE(nic->valid()); 19 | 20 | auto config = QPConfig(); 21 | auto qpp = RC::create(nic,config).value(); 22 | ASSERT_TRUE(qpp->valid()); 23 | 24 | // try send an RDMA request 25 | // init the memory 26 | auto mem = Arc(new RMem(1024)); // allocate a memory with 1K bytes 27 | ASSERT_TRUE(mem->valid()); 28 | 29 | // register it to the Nic 30 | RegHandler handler(mem, nic); 31 | ASSERT_TRUE(handler.valid()); 32 | 33 | auto mr = handler.get_reg_attr().value(); 34 | 35 | RC &qp = *qpp; 36 | qp.bind_remote_mr(mr); 37 | qp.bind_local_mr(mr); 38 | 39 | // finally connect to myself 40 | auto res_c = qp.connect(qp.my_attr()); 41 | RDMA_ASSERT(res_c == IOCode::Ok); 42 | 43 | u64 *test_loc = reinterpret_cast(mem->raw_ptr); 44 | *test_loc = 73; 45 | ASSERT_NE(73,test_loc[1]); // use the next entry to store the read value 46 | 47 | auto res_s = qp.send_normal({.op = IBV_WR_RDMA_READ, 48 | .flags = IBV_SEND_SIGNALED, 49 | .len = sizeof(u64), 50 | .wr_id = 0}, 51 | { 52 | .local_addr = reinterpret_cast(test_loc + 1), 53 | .remote_addr = 0, 54 | .imm_data = 0 55 | }); 56 | RDMA_ASSERT(res_s == IOCode::Ok); 57 | auto res_p = qp.wait_one_comp(); 58 | RDMA_ASSERT(res_p == IOCode::Ok); 59 | ASSERT_EQ(test_loc[1],73); 60 | } 61 | 62 | TEST(RRC, Factory) { 63 | 64 | ::rdmaio::qp::RCFactory factory; 65 | 66 | auto res = RNicInfo::query_dev_names(); 67 | ASSERT_FALSE(res.empty()); 68 | 69 | auto nic = RNic::create(res[0]).value(); 70 | 71 | auto qp_res = factory.create_then_reg(12,nic,QPConfig()).value(); 72 | ASSERT_TRUE(std::get<0>(qp_res)->valid()); 73 | } 74 | 75 | } // namespace test 76 | -------------------------------------------------------------------------------- /xutils/rtm.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "./spin_lock.hh" 6 | 7 | namespace xstore { 8 | 9 | namespace util { 10 | 11 | // constants for tuning RTM performance 12 | const usize max_abort_capacity = 1; 13 | const usize max_abort_nested = 0; 14 | const usize max_abort_zero = 0; 15 | const usize max_abort_conflict = 10; 16 | 17 | // magic numbers 18 | const usize magic_explict_abort_flag = 0x73; 19 | 20 | struct RTMScope { 21 | SpinLock *fallback_lock = nullptr; 22 | 23 | // used to record RTM abort data 24 | int retry = 0; 25 | int conflict = 0; 26 | int capacity = 0; 27 | int nested = 0; 28 | int zero = 0; 29 | 30 | explicit RTMScope(SpinLock *l) : fallback_lock(l) { 31 | 32 | while (true) { 33 | unsigned stat; 34 | stat = _xbegin(); 35 | if (stat == _XBEGIN_STARTED) { 36 | // Put the global lock into read set 37 | if (fallback_lock && fallback_lock->is_locked()) { 38 | _xabort(0xff); 39 | } 40 | return; 41 | 42 | } else { 43 | // retry 44 | retry++; 45 | if ((stat & _XABORT_NESTED) != 0) 46 | nested++; 47 | else if (stat == 0) 48 | zero++; 49 | else if ((stat & _XABORT_CONFLICT) != 0) { 50 | conflict++; 51 | } else if ((stat & _XABORT_CAPACITY) != 0) 52 | capacity++; 53 | 54 | if ((stat & _XABORT_EXPLICIT) && 55 | _XABORT_CODE(stat) == magic_explict_abort_flag) { 56 | while (fallback_lock && fallback_lock->is_locked()) { 57 | _mm_pause(); 58 | } 59 | } 60 | 61 | int step = 1; 62 | 63 | if (nested > max_abort_nested) 64 | break; 65 | if (zero > max_abort_zero / step) { 66 | break; 67 | } 68 | 69 | if (capacity > max_abort_capacity / step) { 70 | break; 71 | } 72 | if (conflict > max_abort_conflict / step) { 73 | break; 74 | } 75 | } 76 | } 77 | fallback_lock->lock(); 78 | } 79 | 80 | inline ~RTMScope(){ 81 | if (_xtest()) { 82 | _xend(); 83 | return; 84 | } 85 | 86 | if (fallback_lock && fallback_lock->is_locked()) { 87 | fallback_lock->unlock(); 88 | } 89 | } 90 | }; 91 | 92 | } // namespace util 93 | 94 | } // namespace xstore 95 | -------------------------------------------------------------------------------- /benchs/reporter.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include // std::setprecision 8 | 9 | #include "./statics.hh" 10 | 11 | #include "r2/src/timer.hh" 12 | 13 | namespace rolex { 14 | 15 | namespace bench { 16 | 17 | template 18 | std::string 19 | format_value(T value, int precission = 4) 20 | { 21 | std::stringstream ss; 22 | ss.imbue(std::locale("")); 23 | ss << std::fixed << std::setprecision(precission) << value; 24 | return ss.str(); 25 | } 26 | 27 | class Reporter 28 | { 29 | public: 30 | static double report_thpt(std::vector& statics, 31 | int epoches, 32 | ::r2::Option log_file = {}) 33 | { 34 | 35 | std::vector old_statics(statics.size()); 36 | 37 | std::ofstream outfile; 38 | if (log_file) { 39 | outfile.open(log_file.value(), std::ios::out | std::ios::trunc); 40 | } 41 | 42 | r2::Timer timer; 43 | for (int epoch = 0; epoch < epoches; epoch += 1) { 44 | sleep(1); 45 | 46 | u64 sum = 0; 47 | u64 sum1 = 0; 48 | 49 | // now report the throughput 50 | for (uint i = 0; i < statics.size(); ++i) { 51 | auto temp = statics[i].data.counter; 52 | sum += (temp - old_statics[i].data.counter); 53 | old_statics[i].data.counter = temp; 54 | 55 | temp = statics[i].data.counter1; 56 | sum1 += (temp - old_statics[i].data.counter1); 57 | old_statics[i].data.counter1 = temp; 58 | 59 | // lat 60 | } 61 | 62 | double passed_msec = timer.passed_msec(); 63 | double res = static_cast(sum) / passed_msec * 1000000.0; 64 | double res1 = static_cast(sum1) / passed_msec * 1000000.0; 65 | r2::compile_fence(); 66 | timer.reset(); 67 | 68 | LOG(2) << "epoch @ " << epoch << ": thpt: " << format_value(res, 0) 69 | << " reqs/sec;" 70 | << "second: " << format_value(res1, 0) << " reqs/sec" 71 | << "; lat: " << statics[0].data.lat << " us"; 72 | 73 | if (log_file) { 74 | outfile << format_value(res, 0) << "\n"; 75 | } 76 | } 77 | if (log_file) { 78 | outfile.close(); 79 | } 80 | return 0.0; 81 | } 82 | }; 83 | 84 | } // namespace bench 85 | 86 | } // namespace xstore 87 | -------------------------------------------------------------------------------- /deps/r2/src/random.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "common.hh" 6 | 7 | namespace r2 8 | { 9 | 10 | namespace util 11 | { 12 | 13 | // taken from a java-version implementation: 14 | // http://developer.classpath.org/doc/java/util/Random-source.html 15 | class FastRandom 16 | { 17 | public: 18 | FastRandom(unsigned long seed) 19 | : seed(0) 20 | { 21 | set_seed0(seed); 22 | } 23 | 24 | FastRandom() : seed(0) 25 | { 26 | set_seed0(seed); 27 | } 28 | 29 | inline unsigned long next() 30 | { 31 | return ((unsigned long)next(32) << 32) + next(32); 32 | } 33 | 34 | inline uint32_t next_u32() 35 | { 36 | return next(32); 37 | } 38 | 39 | inline uint16_t next_u16() 40 | { 41 | return next(16); 42 | } 43 | 44 | /** [0.0, 1.0) */ 45 | inline double next_uniform() 46 | { 47 | return (((unsigned long)next(26) << 27) + next(27)) / (double)(1L << 53); 48 | } 49 | 50 | inline char next_char() 51 | { 52 | return next(8) % 256; 53 | } 54 | 55 | inline std::string next_string(size_t len) 56 | { 57 | std::string s(len, 0); 58 | for (size_t i = 0; i < len; i++) 59 | s[i] = next_char(); 60 | return s; 61 | } 62 | 63 | inline unsigned long get_seed() 64 | { 65 | return seed; 66 | } 67 | 68 | inline void set_seed(unsigned long seed) 69 | { 70 | this->seed = seed; 71 | } 72 | 73 | inline void set_seed0(unsigned long seed) 74 | { 75 | this->seed = (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1); 76 | } 77 | 78 | template 79 | inline T rand_number(T min, T max) 80 | { 81 | assert(max >= min); 82 | return check_between_inclusive( 83 | static_cast(next_uniform() * (max - min + 1)) + min, min, max); 84 | } 85 | 86 | template 87 | inline T check_between_inclusive(T v, T min, T max) 88 | { 89 | assert(v >= min); 90 | assert(v <= max); 91 | return v; 92 | } 93 | 94 | private: 95 | inline unsigned long 96 | next(unsigned int bits) 97 | { 98 | seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1); 99 | return (unsigned long)(seed >> (48 - bits)); 100 | } 101 | 102 | unsigned long seed; 103 | }; 104 | 105 | } // namespace util 106 | 107 | } // end namespace r2 108 | -------------------------------------------------------------------------------- /deps/r2/src/scheduler.cc: -------------------------------------------------------------------------------- 1 | #include "scheduler.hpp" 2 | 3 | namespace r2 4 | { 5 | 6 | static constexpr int scheduler_cid = 0; 7 | 8 | RScheduler::RScheduler(const routine_t &f) 9 | : RExecutor(), pending_futures_(1, 0) 10 | { 11 | spawnr(f); 12 | } 13 | 14 | RScheduler::RScheduler() 15 | : RScheduler([](handler_t &yield, RScheduler &coro) { 16 | /* This is a reactor, which polls RPC in-coming reqs 17 | */ 18 | while (coro.is_running()) 19 | { 20 | // poll the completion events 21 | coro.poll_all(); 22 | 23 | if (coro.next_id() != coro.cur_id()) 24 | { 25 | coro.yield_to_next(yield); 26 | } 27 | } 28 | routine_ret(yield, coro); 29 | }) 30 | { 31 | } 32 | 33 | int RScheduler::spawnr(const RScheduler::routine_t &func) 34 | { 35 | auto ret = RExecutor::spawn(func); 36 | pending_futures_.push_back(0); 37 | return ret; 38 | } 39 | 40 | void RScheduler::stop_schedule() 41 | { 42 | // To ask, why poll_futures_.size() == 1? 43 | // if(running_ && poll_futures_.size() == 1) { 44 | if (running_) 45 | { 46 | // ASSERT(cur_routine_ != &(routines_[scheduler_cid])); 47 | routines_[scheduler_cid].leave(chain_); 48 | running_ = false; 49 | } 50 | } 51 | 52 | using namespace rdmaio; 53 | 54 | void RScheduler::poll_all() 55 | { 56 | 57 | for (auto it = poll_futures_.begin(); it != poll_futures_.end();) 58 | { 59 | 60 | auto res = (*it)(pending_futures_); 61 | auto ret = std::get<0>(res); 62 | auto cor_id = std::get<1>(res); 63 | 64 | switch (ret) 65 | { 66 | case SUCC: 67 | add(cor_id, SUCC); // add the coroutine back to the scheduler 68 | // status_[cor_id] = SUCC; 69 | case EJECT: 70 | it = poll_futures_.erase(it); // eject this future from the list 71 | break; 72 | case ERROR: 73 | add(cor_id, ERR); 74 | break; 75 | case NOT_READY: 76 | // pass, do nothing 77 | it++; 78 | break; 79 | default: 80 | ASSERT(false) << "poll an invalid future return value: " << ret; 81 | } 82 | } // end iterate all pending futures 83 | 84 | // now we check timeout events 85 | #if 0 86 | TMIter it(tm, read_tsc()); 87 | while (it.valid()) 88 | { 89 | add(it.next(), TIMEOUT); 90 | } 91 | #endif 92 | } // end poll_all 93 | 94 | } // end namespace r2 95 | -------------------------------------------------------------------------------- /deps/progress-cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14 FATAL_ERROR) 2 | 3 | # ---- Project ---- 4 | 5 | # Note: update this to your new project's name and version 6 | project(progresscpp 7 | VERSION 1.0 8 | LANGUAGES CXX 9 | ) 10 | 11 | # ---- Include guards ---- 12 | 13 | if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) 14 | message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there.") 15 | endif() 16 | 17 | # ---- Add dependencies via CPM ---- 18 | # see https://github.com/TheLartians/CPM.cmake for more info 19 | 20 | include(cmake/CPM.cmake) 21 | 22 | # PackageProject.cmake will be used to make our target installable 23 | CPMAddPackage( 24 | NAME PackageProject.cmake 25 | GITHUB_REPOSITORY TheLartians/PackageProject.cmake 26 | VERSION 1.0 27 | ) 28 | 29 | # ---- Add source files ---- 30 | 31 | # Note: globbing sources is considered bad practice as CMake's generators may not detect new files automatically. 32 | # Keep that in mind when changing files, or explicitly mention them here. 33 | FILE(GLOB_RECURSE headers CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/**/*.h") 34 | 35 | # ---- Create library ---- 36 | 37 | # Note: for header-only libraries change all PUBLIC flags to INTERFACE and create an interface target: 38 | add_library(progresscpp INTERFACE ${headers}) 39 | set_target_properties(progresscpp PROPERTIES INTERFACE_COMPILE_FEATURES cxx_std_11) 40 | 41 | # beeing a cross-platform target, we enforce enforce standards conformance on MSVC 42 | target_compile_options(progresscpp INTERFACE "$<$:/permissive->") 43 | 44 | # Link dependencies (if required) 45 | # target_link_libraries(Greeter PUBLIC cxxopts) 46 | 47 | target_include_directories(progresscpp 48 | INTERFACE 49 | $ 50 | $ 51 | ) 52 | 53 | # ---- Create an installable target ---- 54 | # this allows users to install and find the library via `find_package()`. 55 | 56 | packageProject( 57 | NAME ${PROJECT_NAME} 58 | VERSION ${PROJECT_VERSION} 59 | BINARY_DIR ${PROJECT_BINARY_DIR} 60 | INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include 61 | INCLUDE_DESTINATION include/${PROJECT_NAME}-${PROJECT_VERSION} 62 | ) 63 | -------------------------------------------------------------------------------- /xcomm/tests/test_ud_transport.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../src/transport/rdma_ud_t.hh" 4 | 5 | #include "./transport_util.hh" 6 | 7 | using namespace xstore::transport; 8 | 9 | namespace test { 10 | 11 | RCtrl ctrl(8888); 12 | 13 | class TransporTest : public testing::Test { 14 | protected: 15 | virtual void SetUp() override { 16 | nic_for_recv = RNic::create(RNicInfo::query_dev_names().at(0)).value(); 17 | qp_recv = UD::create(nic_for_recv, QPConfig()).value(); 18 | 19 | ctrl.registered_qps.reg("test_server", qp_recv); 20 | ctrl.start_daemon(); 21 | } 22 | 23 | Arc nic_for_recv; 24 | Arc nic_for_send; 25 | 26 | Arc qp_recv; 27 | }; 28 | 29 | TEST_F(TransporTest, UDBasic) { 30 | 31 | // prepare UD recv buffer 32 | auto mem_region = HugeRegion::create(64 * 1024 * 1024).value(); 33 | auto mem = mem_region->convert_to_rmem().value(); 34 | 35 | auto handler = RegHandler::create(mem, nic_for_recv).value(); 36 | SimpleAllocator alloc(mem, handler->get_reg_attr().value()); 37 | 38 | auto recv_rs = RecvEntriesFactory::create(alloc); 39 | { 40 | auto res = qp_recv->post_recvs(*recv_rs, 2048); 41 | RDMA_ASSERT(res == IOCode::Ok); 42 | } 43 | 44 | // prepare the sender 45 | auto nic_for_sender = RNic::create(RNicInfo::query_dev_names().at(0)).value(); 46 | auto qp = UD::create(nic_for_sender, QPConfig()).value(); 47 | 48 | UDTransport t; 49 | ASSERT(t.connect("localhost:8888","test_server",73, qp) == IOCode::Ok) << " connect failure"; 50 | 51 | auto ret = t.send(MemBlock((void *)"hello", 6)); 52 | ASSERT(ret == IOCode::Ok); 53 | 54 | int count = 0; 55 | 56 | while (count < 40960) { 57 | UDRecvTransport<2048> recv(qp_recv, recv_rs); 58 | for (; recv.has_msgs(); recv.next()) { 59 | auto msg = recv.cur_msg(); 60 | LOG(0) << "Recv: " << (char *)msg.mem_ptr << " " << count << " ; pending: " << qp->pending_reqs; 61 | count += 1; 62 | auto ret = t.send(MemBlock((void *)"hello", 6)); 63 | ASSERT(ret == IOCode::Ok) << "reset error at: " << count << " " << ret.code.name() 64 | << "; detailed:" << ret.desc << "; " << qp->pending_reqs; 65 | } 66 | } 67 | LOG(4) << "UD recv passes"; 68 | } 69 | 70 | } // end namespace test 71 | 72 | int main(int argc, char **argv) { 73 | ::testing::InitGoogleTest(&argc, argv); 74 | return RUN_ALL_TESTS(); 75 | } 76 | -------------------------------------------------------------------------------- /deps/rlib/core/qps/recv_iter.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "./recv_helper.hh" 4 | 5 | namespace rdmaio { 6 | 7 | namespace qp { 8 | 9 | /*! 10 | RecvIter helps traversing two-sided messages, using recv_cq. 11 | 12 | \note: we donot store the smart pointer for the performance reason 13 | 14 | Example: 15 | ` 16 | Arc ud; // we have an UD 17 | RecvEntries<12> entries; 18 | 19 | for(RecvIter iter(ud, entries); iter.has_msgs(); iter.next()) { 20 | auto imm_data, msg_buf = iter.cur_msg(); // relax some syntax to fetch pair 21 | // do with imm_data and msg_buf 22 | } 23 | ` 24 | */ 25 | template class RecvIter { 26 | QP *qp = nullptr; 27 | RecvEntries *entries = nullptr; 28 | ibv_wc *wcs; 29 | 30 | int idx = 0; 31 | int total_msgs = -1; 32 | static int total; 33 | 34 | public: 35 | RecvIter() = default; 36 | 37 | RecvIter(ibv_cq *cq, ibv_wc *wcs) 38 | : wcs(wcs), total_msgs(ibv_poll_cq(cq, es, wcs)) {} 39 | 40 | RecvIter(Arc &qp, ibv_wc *wcs) 41 | : qp(qp.get()), wcs(wcs), total_msgs(ibv_poll_cq(qp->recv_cq, es, wcs)) {} 42 | 43 | RecvIter(Arc &qp, Arc> &e) : RecvIter(qp, e->wcs) { 44 | entries = e.get(); 45 | } 46 | 47 | auto set_meta(Arc &qp, Arc> &e) { 48 | this->entries = e.get(); 49 | this->qp = qp.get(); 50 | this->wcs = e->wcs; 51 | } 52 | 53 | void begin(Arc &qp, ibv_wc *wcs) { 54 | this->total_msgs = ibv_poll_cq(qp->recv_cq, es, wcs); 55 | this->idx = 0; 56 | } 57 | 58 | /*! 59 | \ret (imm_data, recv_buffer) 60 | */ 61 | Option> cur_msg() const { 62 | if (has_msgs()) { 63 | auto buf = reinterpret_cast(wcs[idx].wr_id); 64 | return std::make_pair(wcs[idx].imm_data, buf); 65 | } 66 | return {}; 67 | } 68 | 69 | inline void next() { idx += 1; } 70 | 71 | inline bool has_msgs() const { return idx < total_msgs; } 72 | 73 | void clear() { 74 | if (total_msgs > 0 && qp != nullptr && entries != nullptr) { 75 | auto res = qp->post_recvs(*entries, total_msgs); 76 | if (unlikely(res != IOCode::Ok)) 77 | RDMA_LOG(4) << "post recv error: " << strerror(res.desc); 78 | } 79 | this->total_msgs = -1; 80 | } 81 | 82 | ~RecvIter() { 83 | // post recvs 84 | this->clear(); 85 | } 86 | }; 87 | 88 | } // namespace qp 89 | } // namespace rdmaio 90 | -------------------------------------------------------------------------------- /deps/rlib/core/utils/marshal.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.hpp" 4 | 5 | namespace rdmaio 6 | { 7 | 8 | struct ReplyHeader 9 | { 10 | uint16_t reply_status; 11 | uint16_t reply_payload; 12 | }; 13 | 14 | struct RequestHeader 15 | { 16 | uint16_t req_type; 17 | uint16_t req_payload; 18 | }; 19 | 20 | typedef std::string Buf_t; 21 | 22 | class Marshal 23 | { 24 | public: 25 | static Buf_t get_buffer(int size) 26 | { 27 | return std::string(size, '0'); 28 | } 29 | 30 | static Buf_t forward(const Buf_t &b, int pos, int size) 31 | { 32 | return b.substr(pos, size); 33 | } 34 | 35 | static Buf_t direct_forward(const Buf_t &b,int size) 36 | { 37 | return forward(b,size,b.size() - size); 38 | } 39 | 40 | template 41 | static void *serialize_to_buf(const T &t, const void *buf) 42 | { 43 | memcpy((void *)buf, &t, sizeof(T)); 44 | return static_cast((char *)buf + sizeof(T)); 45 | } 46 | 47 | template 48 | static Buf_t serialize_to_buf(const T &t) 49 | { 50 | auto res = get_buffer(sizeof(T)); 51 | serialize_to_buf(t, res.data()); 52 | return res; 53 | } 54 | 55 | template 56 | static bool deserialize(const Buf_t &buf, T &t) 57 | { 58 | if (buf.size() < sizeof(T)) 59 | return false; 60 | memcpy((char *)(&t), buf.data(), sizeof(T)); 61 | return true; 62 | } 63 | 64 | template 65 | static T deserialize(const Buf_t &buf) 66 | { 67 | T res; 68 | memcpy((char *)(&res), (char *)buf.data(), std::min(buf.size(), sizeof(T))); 69 | return res; 70 | } 71 | 72 | template 73 | static void *deserialize(const void *buf, T &t) 74 | { 75 | memcpy((char *)(&t), buf, sizeof(T)); 76 | return static_cast((char *)buf + sizeof(T)); 77 | } 78 | 79 | template 80 | static T deserialize(const void *buf) 81 | { 82 | T ret; 83 | deserialize(buf, ret); 84 | return ret; 85 | } 86 | 87 | static Buf_t null_req() 88 | { 89 | RequestHeader req = {.req_type = 0, .req_payload = 0}; 90 | return serialize_to_buf(req); 91 | } 92 | 93 | static Buf_t null_reply() 94 | { 95 | ReplyHeader reply = {.reply_status = ERR, .reply_payload = 0}; 96 | return serialize_to_buf(reply); 97 | } 98 | }; 99 | 100 | } // end namespace rdmaio 101 | -------------------------------------------------------------------------------- /deps/rlib/core/bootstrap/proto.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../rmem/handler.hh" 4 | #include "../qps/mod.hh" 5 | 6 | namespace rdmaio { 7 | 8 | namespace proto { 9 | 10 | using rpc_id_t = u8; 11 | 12 | /*! 13 | RPC ids used for the callbacks 14 | */ 15 | enum RCtrlBinderIdType : rpc_id_t { 16 | HeartBeat = 0, // ping whether RCtrl is started 17 | FetchMr, // fetch remote MR 18 | CreateRC, // create an RC for connect (for one-sided) 19 | CreateRCM, // create an RC which uses message (for two-sided) 20 | DeleteRC, 21 | FetchQPAttr, // fetch a created QP's attr. useful for UD QP 22 | Reserved, 23 | }; 24 | 25 | enum CallbackStatus : u8 { 26 | Ok = 0, 27 | Err = 1, 28 | NotFound, 29 | WrongArg, 30 | ConnectErr, 31 | AuthErr, 32 | }; 33 | 34 | /*! 35 | Req/Reply for handling MR requests 36 | */ 37 | struct __attribute__((packed)) MRReq { 38 | ::rdmaio::rmem::register_id_t id; 39 | // maybe for future extensions, like permission, etc 40 | }; 41 | 42 | struct __attribute__((packed)) MRReply { 43 | CallbackStatus status; 44 | ::rdmaio::rmem::RegAttr attr; 45 | }; 46 | 47 | /*******************************************/ 48 | 49 | struct __attribute__((packed)) QPReq { 50 | char name[::rdmaio::qp::kMaxQPNameLen + 1]; 51 | u64 key; 52 | }; 53 | 54 | /*! 55 | Req/Reply for creating ~(RC) QPs 56 | */ 57 | struct __attribute__((packed)) RCReq { 58 | 59 | RCReq() = default; 60 | 61 | // parameter for querying the QP 62 | char name[::rdmaio::qp::kMaxQPNameLen + 1]; 63 | char name_recv[::rdmaio::qp::kMaxQPNameLen + 1]; // the name used to create recv_cqs 64 | 65 | u8 whether_create = 0; // 1: create the QP, 0 only query the QP attr 66 | u8 whether_recv = 0; // 1: create with the recv_cq specified by the *name_recv*, 0 not 67 | 68 | // if whether_create = 1, uses the following parameter to create the QP 69 | ::rdmaio::nic_id_t nic_id; 70 | ::rdmaio::qp::QPConfig config; 71 | ::rdmaio::qp::QPAttr attr; // the attr used for connect 72 | 73 | u64 max_recv_sz = 4096; 74 | }; 75 | 76 | struct __attribute__((packed)) RCReply { 77 | CallbackStatus status; 78 | ::rdmaio::qp::QPAttr attr; 79 | u64 key; 80 | }; 81 | 82 | struct __attribute__((packed)) DelRCReq { 83 | // parameter for querying the QP 84 | char name[::rdmaio::qp::kMaxQPNameLen + 1]; 85 | 86 | u64 key; 87 | }; 88 | 89 | /*******************************************/ 90 | 91 | } // namespace proto 92 | 93 | } // namespace rdmaio 94 | -------------------------------------------------------------------------------- /deps/rlib/benchs/bench_server.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../core/lib.hh" 4 | 5 | DEFINE_int64(port, 8888, "Server listener (UDP) port."); 6 | DEFINE_int64(use_nic_idx, 0, "Which NIC to create QP"); 7 | DEFINE_int64(reg_nic_name, 73, "The name to register an opened NIC at rctrl."); 8 | DEFINE_int64(reg_mem_name, 73, "The name to register an MR at rctrl."); 9 | DEFINE_uint64(magic_num, 0xdeadbeaf, "The magic number read by the client"); 10 | 11 | using namespace rdmaio; 12 | using namespace rdmaio::rmem; 13 | 14 | int main(int argc, char **argv) { 15 | gflags::ParseCommandLineFlags(&argc, &argv, true); 16 | 17 | // start a controler, so that others may access it using UDP based channel 18 | RCtrl ctrl(FLAGS_port); 19 | RDMA_LOG(4) << "Pingping server listenes at localhost:" << FLAGS_port; 20 | 21 | // first we open the NIC 22 | { 23 | for (uint i = 0; i < RNicInfo::query_dev_names().size(); ++i) { 24 | auto nic = 25 | RNic::create(RNicInfo::query_dev_names().at(i)) 26 | .value(); 27 | 28 | // register the nic with name 0 to the ctrl 29 | RDMA_ASSERT(ctrl.opened_nics.reg(i, nic)); 30 | } 31 | } 32 | 33 | { 34 | for (uint i = 0; i < RNicInfo::query_dev_names().size(); ++i) 35 | // allocate a memory (with 20M) so that remote QP can access it 36 | RDMA_ASSERT(ctrl.registered_mrs.create_then_reg( 37 | i, Arc(new RMem(1024 * 1024 * 64)), 38 | ctrl.opened_nics.query(i).value())) << "reg mem at: " << i << " error"; 39 | } 40 | 41 | // initialzie the value so as client can sanity check its content 42 | u64 *reg_mem = (u64 *)(ctrl.registered_mrs.query(0) 43 | .value() 44 | ->get_reg_attr() 45 | .value() 46 | .buf); 47 | // setup the value 48 | for (uint i = 0; i < 10000; ++i) { 49 | reg_mem[i] = FLAGS_magic_num + i; 50 | asm volatile("" ::: "memory"); 51 | } 52 | 53 | // start the listener thread so that client can communicate w it 54 | ctrl.start_daemon(); 55 | 56 | RDMA_LOG(2) << "thpt bench server started!"; 57 | // run for 20 sec 58 | for (uint i = 0; i < 600; ++i) { 59 | // server does nothing because it is RDMA 60 | // client will read the reg_mem using RDMA 61 | sleep(1); 62 | } 63 | RDMA_LOG(4) << "server exit!"; 64 | } 65 | -------------------------------------------------------------------------------- /benchs/load_config.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #include "statics.hh" 7 | 8 | namespace rolex { 9 | 10 | namespace bench { 11 | 12 | 13 | DEFINE_uint64(reg_leaf_region, 101, "The name to register an MR at rctrl for data nodes."); 14 | // load datasets 15 | DEFINE_uint64(nkeys, 100000, "Number of keys to load"); 16 | DEFINE_uint64(non_nkeys, 100000, "Number of non_keys for inserting"); 17 | DEFINE_string(workloads, "normal", "The workloads for evaluation"); 18 | // test config 19 | DEFINE_uint64(mem_threads, 3, "Server threads."); 20 | DEFINE_uint64(threads, 24, "Server threads."); 21 | DEFINE_int32(coros, 10, "num client coroutine used per threads"); 22 | DEFINE_double(read_ratio, 1, "The ratio for reading"); 23 | DEFINE_double(insert_ratio, 0, "The ratio for writing"); 24 | DEFINE_double(update_ratio, 0, "The ratio for updating"); 25 | 26 | 27 | enum WORKLOAD{ 28 | YCSB_A, YCSB_B, YCSB_C, YCSB_D, YCSB_E, YCSB_F, NORMAL, LOGNORMAL, WEBLOG, DOCID 29 | }; 30 | 31 | struct BenchmarkConfig { 32 | u64 nkeys; 33 | u64 non_nkeys; 34 | i32 workloads; 35 | 36 | u64 mem_threads; 37 | u64 threads; 38 | i32 coros; 39 | double read_ratio; 40 | double insert_ratio; 41 | double update_ratio; 42 | std::vector statics; 43 | }BenConfig; 44 | 45 | 46 | void load_benchmark_config() { 47 | BenConfig.nkeys = FLAGS_nkeys; 48 | BenConfig.non_nkeys = FLAGS_non_nkeys; 49 | std::map workloads_map = { 50 | { "ycsba", YCSB_A }, 51 | { "ycsbb", YCSB_B }, 52 | { "ycsbc", YCSB_C }, 53 | { "ycsbd", YCSB_D }, 54 | { "ycsbe", YCSB_E }, 55 | { "ycsbf", YCSB_F }, 56 | { "normal", NORMAL }, 57 | { "lognormal", LOGNORMAL }, 58 | { "weblog", WEBLOG }, 59 | { "docid", DOCID } 60 | }; 61 | ASSERT (workloads_map.find(FLAGS_workloads) != workloads_map.end()) 62 | << "unsupported workload type: " << FLAGS_workloads; 63 | BenConfig.workloads = workloads_map[FLAGS_workloads]; 64 | 65 | BenConfig.mem_threads = FLAGS_mem_threads; 66 | BenConfig.threads = FLAGS_threads; 67 | BenConfig.coros = FLAGS_coros; 68 | BenConfig.read_ratio = FLAGS_read_ratio; 69 | BenConfig.insert_ratio = FLAGS_insert_ratio; 70 | BenConfig.update_ratio = FLAGS_update_ratio; 71 | 72 | BenConfig.statics.reserve(FLAGS_threads); 73 | } 74 | 75 | 76 | } // namespace bench 77 | 78 | } // namespace rolex -------------------------------------------------------------------------------- /benchs/rolex_util_back.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "r2/src/logging.hh" 8 | 9 | #define NS_PER_S 1000000000.0 10 | #define TIMER_DECLARE(n) struct timespec b##n,e##n 11 | #define TIMER_BEGIN(n) clock_gettime(CLOCK_MONOTONIC, &b##n) 12 | #define TIMER_END_NS(n,t) clock_gettime(CLOCK_MONOTONIC, &e##n); \ 13 | (t)=(e##n.tv_sec-b##n.tv_sec)*NS_PER_S+(e##n.tv_nsec-b##n.tv_nsec) 14 | #define TIMER_END_S(n,t) clock_gettime(CLOCK_MONOTONIC, &e##n); \ 15 | (t)=(e##n.tv_sec-b##n.tv_sec)+(e##n.tv_nsec-b##n.tv_nsec)/NS_PER_S 16 | 17 | 18 | namespace rolex { 19 | 20 | using namespace r2; 21 | 22 | // 8-byte value 23 | using KeyType = u64; 24 | using ValType = u64; 25 | 26 | /** 27 | * @brief The id of RPCs in RPCCOre 28 | * 29 | */ 30 | enum RPCId { 31 | GET = 0, PUT, UPDATE, DELETE, SCAN 32 | }; 33 | 34 | struct __attribute__((packed)) ReplyValue { 35 | bool status; /// The queried data exists? or other operation success? 36 | ValType val; /// The returned value 37 | }; 38 | 39 | #define CACHELINE_SIZE (1 << 6) 40 | struct alignas(CACHELINE_SIZE) ThreadParam { 41 | uint64_t throughput; 42 | uint32_t thread_id; 43 | }; 44 | using thread_param_t = ThreadParam; 45 | 46 | 47 | 48 | 49 | struct MonitorParam { 50 | pthread_t proc_n; // the thread number 51 | int interval; // the time of interval 52 | }; 53 | using monitor_param_t = MonitorParam; 54 | 55 | /** 56 | * @brief monitor the cpu utilization 57 | * 58 | * @param argv monitor_param_t 59 | */ 60 | void* cpu_monitor(void *argv) { 61 | monitor_param_t param = *(monitor_param_t*)argv; 62 | LOG(3) << "Hello cpu_monitor"; 63 | char cmd[1024]; 64 | sprintf(cmd, "ps -p %d -o %%cpu,%%mem | awk NR==2>>log", (unsigned int)param.proc_n); 65 | //system("echo > log"); 66 | while(1) { 67 | //system(cmd); 68 | sleep(param.interval); 69 | } 70 | /* 71 | unsigned int proc_n = *(unsigned int*)argv; 72 | FILE *fp = NULL; 73 | char cmd[1024]; 74 | char buf[1024]; 75 | char result[4096]; 76 | sprintf(cmd, "echo > cpu_log; watch -n1 -t 'ps -p %d -o %%cpu,%%mem | awk NR==2>>cpu_log' ", proc_n); 77 | if( (fp = popen(cmd, "r")) != NULL) 78 | { 79 | while(fgets(buf, 1024, fp) != NULL) 80 | { 81 | strcat(result, buf); 82 | } 83 | pclose(fp); 84 | fp = NULL; 85 | }*/ 86 | } 87 | 88 | } // namespace rolex -------------------------------------------------------------------------------- /deps/r2/benchs/bench_server.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "rlib/core/lib.hh" 4 | 5 | #include "./huge_region.hh" 6 | using namespace r2::bench; 7 | 8 | DEFINE_int64(port, 8888, "Server listener (UDP) port."); 9 | DEFINE_int64(use_nic_idx, 0, "Which NIC to create QP"); 10 | DEFINE_int64(reg_nic_name, 73, "The name to register an opened NIC at rctrl."); 11 | DEFINE_int64(reg_mem_name, 73, "The name to register an MR at rctrl."); 12 | DEFINE_uint64(magic_num, 0xdeadbeaf, "The magic number read by the client"); 13 | 14 | using namespace rdmaio; 15 | using namespace rdmaio::rmem; 16 | 17 | int main(int argc, char **argv) { 18 | gflags::ParseCommandLineFlags(&argc, &argv, true); 19 | 20 | // start a controler, so that others may access it using UDP based channel 21 | RCtrl ctrl(FLAGS_port); 22 | RDMA_LOG(4) << "Pingping server listenes at localhost:" << FLAGS_port; 23 | 24 | // first we open the NIC 25 | { 26 | auto nic = 27 | RNic::create(RNicInfo::query_dev_names().at(FLAGS_use_nic_idx)).value(); 28 | 29 | // register the nic with name 0 to the ctrl 30 | RDMA_ASSERT(ctrl.opened_nics.reg(FLAGS_reg_nic_name, nic)); 31 | } 32 | 33 | { 34 | auto mem = HugeRegion::create(20 * 1024 * 1024).value(); 35 | ctrl.registered_mrs.create_then_reg( 36 | FLAGS_reg_mem_name, mem->convert_to_rmem().value(), 37 | ctrl.opened_nics.query(FLAGS_reg_nic_name).value()); 38 | // allocate a memory (with 20M) so that remote QP can access it 39 | //RDMA_ASSERT(ctrl.registered_mrs.create_then_reg( 40 | //FLAGS_reg_mem_name, Arc(new RMem(1024 * 1024 * 20)), 41 | //ctrl.opened_nics.query(FLAGS_reg_nic_name).value())); 42 | 43 | } 44 | 45 | // initialzie the value so as client can sanity check its content 46 | u64 *reg_mem = (u64 *)(ctrl.registered_mrs.query(FLAGS_reg_mem_name) 47 | .value() 48 | ->get_reg_attr() 49 | .value() 50 | .buf); 51 | // setup the value 52 | for (uint i = 0; i < 10000; ++i) { 53 | reg_mem[i] = FLAGS_magic_num + i; 54 | asm volatile("" ::: "memory"); 55 | } 56 | 57 | // start the listener thread so that client can communicate w it 58 | ctrl.start_daemon(); 59 | 60 | RDMA_LOG(2) << "thpt bench server started!"; 61 | // run for 20 sec 62 | for (uint i = 0; i < 20; ++i) { 63 | // server does nothing because it is RDMA 64 | // client will read the reg_mem using RDMA 65 | sleep(1); 66 | } 67 | RDMA_LOG(4) << "server exit!"; 68 | } 69 | -------------------------------------------------------------------------------- /deps/rlib/docs/benchs/ro_performance.md: -------------------------------------------------------------------------------- 1 | # Benchmark Performance 2 | 3 | ## Table of Contents 4 | 5 | * [RO Basic](#ro_basic) 6 | * [RO Flying request](#ro_fly) 7 | * [RO Outstanding request](#ro_or) 8 | * [RO Doorbell Batching](#ro_db) 9 | * [RO Coroutine](#ro_co) 10 | 11 | 12 | 13 | 14 | ## RO Basic 15 | 16 | ```bash 17 | $make bench_client 18 | $./bench_client -client_name val08 -threads 12 19 | ``` 20 | 21 | 22 | | Setup | per-thread | peek | 23 | | ----------------------- | ---------- | ------- | 24 | | 1 clients * 12 threads | 0.48M | 5.8M | 25 | | 2 clients * 12 threads | 0.475M | 11.4 M | 26 | | 3 clients * 12 threads | 0.467M | 16.8M | 27 | 28 | 29 | 30 | 31 | ## RO Flying request 32 | 33 | ```bash 34 | $make fly_client 35 | $./fly_client -client_name val08 -threads 12 36 | ``` 37 | 38 | | Setup | per-thread | peek | 39 | | ----------------------- | ---------- | ------- | 40 | | 1 clients * 12 threads | 2.5M | 30M | 41 | | 2 clients * 12 threads | 2.5M | 60M | 42 | | 3 clients * 12 threads | 2.5M | 90M | 43 | 44 | 45 | 46 | ## RO Outstanding request 47 | 48 | ```bash 49 | $make or_client 50 | $./or_client -client_name val08 -threads 12 51 | ``` 52 | 53 | | Setup | per-thread | peek | 54 | | ----------------------- | ---------- | ------- | 55 | | 1 clients * 12 threads | 3.67M | 44M | 56 | | 2 clients * 12 threads | 3.62M | 87M | 57 | | 3 clients * 12 threads | 3.44M | 124M | 58 | 59 | 60 | 61 | ## RO Doorbell Batching 62 | 63 | ```bash 64 | $make db_client 65 | $./db_client -client_name val08 -threads 12 66 | ``` 67 | 68 | | Setup | per-thread | peek | 69 | | ----------------------- | ---------- | ------- | 70 | | 1 clients * 12 threads | 5.5M | 66M | 71 | | 2 clients * 12 threads | 5.5M | 132M | 72 | | 3 clients * 12 threads | 3.75M | 135M | 73 | 74 | 75 | 76 | 77 | ## RO Coroutine 78 | 79 | ```bash 80 | $cd r2 81 | $make co_client 82 | $./co_client -client_name val08 -threads 12 -coroutines 10 83 | ``` 84 | 85 | | Setup | per-thread | peek | 86 | | ----------------------- | ---------- | ------ | 87 | | 1 clients * 12 threads | 2.25M | 27M | 88 | | 2 clients * 12 threads | 2.25M | 54M | 89 | | 3 clients * 12 threads | 2.25M | 81M | -------------------------------------------------------------------------------- /deps/rlib/core/result.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace rdmaio { 7 | 8 | struct __attribute__((packed)) IOCode { 9 | enum Code { 10 | Ok = 0, 11 | Err = 1, 12 | Timeout = 2, 13 | NearOk = 3, // there is some error, but may be tolerated 14 | NotReady = 4, 15 | }; 16 | 17 | Code c; 18 | 19 | explicit IOCode(const Code &c) : c(c) {} 20 | 21 | std::string name() { 22 | switch (c) { 23 | case Ok: 24 | return "Ok"; 25 | case Err: 26 | return "Err"; 27 | case Timeout: 28 | return "Timeout"; 29 | case NearOk: 30 | return "NearOk"; 31 | case NotReady: 32 | return "NotReady"; 33 | default: 34 | assert(false); 35 | } 36 | return ""; 37 | } 38 | 39 | inline bool operator==(const Code &code) { return c == code; } 40 | 41 | inline bool operator!=(const Code &code) { return c != code; } 42 | }; 43 | 44 | struct __attribute__((packed)) DummyDesc { 45 | DummyDesc() = default; 46 | }; 47 | 48 | /*! 49 | The abstract result of IO request, with a code and detailed descrption if 50 | error happens. 51 | */ 52 | template struct Result { 53 | IOCode code; 54 | Desc desc; 55 | 56 | inline bool operator==(const IOCode::Code &c) { return code.c == c; } 57 | 58 | inline bool operator!=(const IOCode::Code &c) { return code.c != c; } 59 | }; 60 | 61 | /*! 62 | Some wrapper functions for help creating results 63 | Example: 64 | auto res = Ok(); 65 | assert(res == IOCode::Ok); 66 | */ 67 | template inline Result Ok(const D &d = D()) { 68 | return {.code = IOCode(IOCode::Ok), .desc = d}; 69 | } 70 | 71 | template inline Result NearOk(const D &d = D()) { 72 | return {.code = IOCode(IOCode::NearOk), .desc = d}; 73 | } 74 | 75 | template inline Result Err(const D &d = D()) { 76 | return {.code = IOCode(IOCode::Err), .desc = std::move(d)}; 77 | } 78 | 79 | template inline Result Timeout(const D &d = D()) { 80 | return {.code = IOCode(IOCode::Timeout), .desc = d}; 81 | } 82 | 83 | template inline Result NotReady(const D &d = D()) { 84 | return {.code = IOCode(IOCode::NotReady), .desc = d}; 85 | } 86 | 87 | template 88 | inline Result transfer(const Result &a, const B &d) { 89 | return {.code = a.code, .desc = d}; 90 | } 91 | 92 | template 93 | inline Result<> transfer_raw(const Result &a) { 94 | return {.code = a.code }; 95 | } 96 | 97 | } // namespace rdmaio 98 | -------------------------------------------------------------------------------- /xcomm/tests/test_remote_rw.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../src/atomic_rw/rdma_rw_op.hh" 4 | #include "../src/atomic_rw/rdma_async_rw_op.hh" 5 | #include "../../deps/rlib/core/lib.hh" 6 | 7 | #include "./utils.hh" 8 | 9 | namespace test { 10 | 11 | using namespace xstore::xcomm::rw; 12 | 13 | TEST(AtomicRW, BasicRemoteRW) { 14 | auto res = RNicInfo::query_dev_names(); 15 | ASSERT_FALSE(res.empty()); 16 | 17 | auto nic = std::make_shared(res[0]); 18 | ASSERT_TRUE(nic->valid()); 19 | 20 | auto config = QPConfig(); 21 | auto qpp = RC::create(nic, config).value(); 22 | ASSERT_TRUE(qpp->valid()); 23 | 24 | // try send an RDMA request 25 | // init the memory 26 | auto mem = Arc(new RMem(4096)); // allocate a memory with 1K bytes 27 | ASSERT_TRUE(mem->valid()); 28 | 29 | // register it to the Nic 30 | RegHandler handler(mem, nic); 31 | ASSERT_TRUE(handler.valid()); 32 | 33 | auto mr = handler.get_reg_attr().value(); 34 | 35 | RC &qp = *qpp; 36 | qp.bind_remote_mr(mr); 37 | qp.bind_local_mr(mr); 38 | 39 | // finally connect to myself 40 | auto res_c = qp.connect(qp.my_attr()); 41 | RDMA_ASSERT(res_c == IOCode::Ok); 42 | 43 | // now the real test 44 | char *src_loc = reinterpret_cast(mem->raw_ptr); 45 | char *dst_loc = src_loc + 2048; 46 | 47 | // we will test using 1024-bytes str 48 | r2::MemBlock src(0, 1024); // rdma_addr is 0 49 | r2::MemBlock dest((void *)dst_loc, src.sz); 50 | 51 | // main test body! 52 | ::test::inplace_rand_str(src_loc, 1024); 53 | 54 | // remote write 55 | auto ret = RDMARWOp(qpp).read(src, dest); 56 | ASSERT(ret == ::rdmaio::IOCode::Ok); 57 | ASSERT_EQ(0, memcmp(src_loc,dst_loc, dest.sz)); 58 | 59 | // test async 60 | const usize coroutines = 12; 61 | // first init buf 62 | for (uint i = 0;i < coroutines; ++i) { 63 | ::test::inplace_rand_str(src_loc + 64 * i, 64); 64 | } 65 | 66 | SScheduler ssched; 67 | for (uint i = 0; i < coroutines; ++i) { 68 | ssched.spawn([qpp, src_loc, dst_loc, i](R2_ASYNC) { 69 | r2::MemBlock src((void *)(i * 64), 64); // rdma_addr is 0 70 | r2::MemBlock dest((void *)(dst_loc + i * 64), src.sz); 71 | 72 | auto ret = AsyncRDMARWOp(qpp).read(src, dest,R2_ASYNC_WAIT); 73 | ASSERT(ret == ::rdmaio::IOCode::Ok); 74 | 75 | ASSERT_EQ(0,memcmp(src_loc + i * 64, dst_loc + i * 64, dest.sz)); 76 | 77 | if (i == coroutines - 1) { 78 | R2_STOP(); 79 | } 80 | R2_RET; 81 | }); 82 | } 83 | ssched.run(); 84 | } 85 | 86 | } 87 | 88 | int main(int argc, char **argv) { 89 | ::testing::InitGoogleTest(&argc, argv); 90 | return RUN_ALL_TESTS(); 91 | } 92 | -------------------------------------------------------------------------------- /xutils/tests/test_rtm.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../rtm.hh" 4 | 5 | #include "../../deps/r2/src/thread.hh" 6 | 7 | namespace test { 8 | 9 | using namespace xstore::util; 10 | 11 | using T = ::r2::Thread; 12 | 13 | TEST(Util, Should_fail) { 14 | 15 | usize a = 1000; 16 | usize b = 1000; 17 | const usize iters = 5000000; 18 | 19 | auto T0 = T([&a, &b]() -> usize { 20 | for (uint i = 0; i < iters; ++i) { 21 | auto val = 12; 22 | if ((a > b) && (a - b > 100)) { 23 | a -= val; 24 | b += val; 25 | } else { 26 | a += val; 27 | b -= val; 28 | } 29 | ASSERT(a >= val && b >= val) << a << " " << b << " " << val; 30 | } 31 | return 0; 32 | }); 33 | 34 | auto T1 = T([&a, &b]() -> usize { 35 | for (uint i = 0; i < iters; ++i) { 36 | auto val = 12; 37 | if ((a > b) && (a - b > 100)) { 38 | a -= val; 39 | b += val; 40 | } else { 41 | a += val; 42 | b -= val; 43 | } 44 | ASSERT(a >= val && b >= val) << a << " " << b; 45 | } 46 | return 0; 47 | }); 48 | 49 | T0.start(); 50 | T1.start(); 51 | 52 | T0.join(); 53 | T1.join(); 54 | 55 | ASSERT_NE(a + b, 2000); 56 | } 57 | 58 | TEST(Util, RTM) { 59 | 60 | usize a = 1000; 61 | usize b = 1000; 62 | const usize iters = 5000000; 63 | 64 | SpinLock fallback; 65 | 66 | auto T0 = T([&a, &b,&fallback]() -> usize { 67 | for (uint i = 0; i < iters; ++i) { 68 | auto val = 12; 69 | { 70 | RTMScope rtm(&fallback); 71 | if ((a > b) && (a - b > 100)) { 72 | a -= val; 73 | b += val; 74 | } else { 75 | a += val; 76 | b -= val; 77 | } 78 | } 79 | ASSERT(a >= val && b >= val); 80 | } 81 | return 0; 82 | }); 83 | 84 | auto T1 = T([&a, &b,&fallback]() -> usize { 85 | for (uint i = 0; i < iters; ++i) { 86 | auto val = 12; 87 | { 88 | RTMScope rtm(&fallback); 89 | if ((a > b) && (a - b > 100)) { 90 | a -= val; 91 | b += val; 92 | } else { 93 | a += val; 94 | b -= val; 95 | } 96 | } 97 | ASSERT(a >= val && b >= val) << a << " " << b; 98 | } 99 | return 0; 100 | }); 101 | 102 | T0.start(); 103 | T1.start(); 104 | 105 | T0.join(); 106 | T1.join(); 107 | 108 | ASSERT_EQ(a + b, 2000); 109 | } 110 | 111 | } // namespace test 112 | 113 | int main(int argc, char **argv) { 114 | ::testing::InitGoogleTest(&argc, argv); 115 | return RUN_ALL_TESTS(); 116 | } 117 | -------------------------------------------------------------------------------- /deps/r2/src/channel/mod.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../common.hpp" 4 | 5 | #include 6 | 7 | namespace r2 8 | { 9 | 10 | /*! 11 | TODO: add an example here 12 | */ 13 | template 14 | class Channel 15 | { 16 | public: 17 | Channel(u64 max_entry_num = 1) 18 | : max_entry_num(max_entry_num), head(0), tail(0) 19 | { 20 | ASSERT(!(max_entry_num & (max_entry_num - 1))); 21 | 22 | ring_buf = static_cast( 23 | ::aligned_alloc(kCacheLineSize, max_entry_num * sizeof(Entry))); 24 | ASSERT(ring_buf != nullptr); 25 | ASSERT((u64)ring_buf % ENTRY_SIZE == 0); 26 | } 27 | 28 | ~Channel() { free(ring_buf); } 29 | 30 | inline u64 size() const { return head - tail; } 31 | 32 | inline bool isEmpty() const { return head == tail; } 33 | 34 | inline bool enqueue(const T &value) 35 | { 36 | ASSERT(head >= tail); 37 | if (head == tail + max_entry_num) 38 | { 39 | return false; 40 | } 41 | else 42 | { 43 | u64 index = head & (max_entry_num - 1); 44 | 45 | ring_buf[index].value = value; 46 | __sync_fetch_and_add(&head, 1); 47 | return true; 48 | } 49 | } 50 | 51 | inline void enqueue_blocking(const T &value) 52 | { 53 | ASSERT(head >= tail); 54 | while (head == tail + max_entry_num) 55 | ; 56 | u64 index = head & (max_entry_num - 1); 57 | 58 | ring_buf[index].value = value; 59 | __sync_fetch_and_add(&head, 1); 60 | } 61 | 62 | inline T dequeue_blocking() 63 | { 64 | ASSERT(head >= tail); 65 | while (head == tail) 66 | ; 67 | u64 index = tail & (max_entry_num - 1); 68 | 69 | T ret = ring_buf[index].value; 70 | __sync_fetch_and_add(&tail, 1); 71 | return ret; 72 | } 73 | 74 | inline Option dequeue() 75 | { 76 | ASSERT(head >= tail); 77 | if (head == tail) 78 | { 79 | return {}; 80 | } 81 | else 82 | { 83 | u64 index = tail & (max_entry_num - 1); 84 | auto res = Option(ring_buf[index].value); 85 | ::r2::compile_fence(); 86 | __sync_fetch_and_add(&tail, 1); 87 | return res; 88 | } 89 | } 90 | 91 | private: 92 | static const u64 ENTRY_SIZE = kCacheLineSize; 93 | 94 | struct Entry 95 | { 96 | T value; 97 | } __attribute__((aligned(ENTRY_SIZE))); 98 | 99 | // XD: why public? 100 | public: 101 | volatile u64 __attribute__((aligned(kCacheLineSize))) head; 102 | volatile u64 __attribute__((aligned(kCacheLineSize))) tail; 103 | Entry *ring_buf; 104 | u64 max_entry_num; 105 | } __attribute__((aligned(kCacheLineSize))); 106 | 107 | } // end namespace r2 108 | -------------------------------------------------------------------------------- /deps/rlib/docs/benchs/TUTORIALS.md: -------------------------------------------------------------------------------- 1 | # Benchmark Tutorials 2 | 3 | ## Table of Contents 4 | 5 | * [Introduction](#intro) 6 | * [Building](#build) 7 | * [Running](#run) 8 | * [Performance](#perform) 9 | 10 | 11 | 12 | ## Introduction 13 | Codes in `rib\bench\` are used to evaluate **peak throughput** for one-sided **RDMA Read**. 14 | 15 | 16 | 17 | ## Building 18 | 19 | We use CMake to build rib and provide a script file `make.toml` to simplify the procedure. 20 | 21 | ```bash 22 | $cd scripts/ 23 | $./bootstrap.py -f benchs/rw_bench/make.toml 24 | ``` 25 | 26 | 27 | 28 | ## Running 29 | 30 | We provide a script file `run.toml` to simplify the procedure. 31 | 32 | ```bash 33 | $cd scripts/ 34 | $./bootstrap.py -f benchs/rw_bench/run.toml 35 | ``` 36 | 37 | The first host is used as server and the rest are clients. You can change `cmd` in `run.toml` to get running params. 38 | 39 | ```bash 40 | # server 41 | $cmd = 'cd rib/; ./bench_server -help' 42 | -magic_num (The magic number read by the client) type: uint64 43 | default: 3735928495 44 | -port (Server listener (UDP) port.) type: int64 default: 8888 45 | -reg_mem_name (The name to register an MR at rctrl.) type: int64 46 | default: 73 47 | -reg_nic_name (The name to register an opened NIC at rctrl.) type: int64 48 | default: 73 49 | -use_nic_idx (Which NIC to create QP) type: int64 default: 0 50 | ``` 51 | 52 | ```bash 53 | # client 54 | $cmd = 'cd rib/; ./bench_client -help' 55 | -addr (Server address to connect to.) type: string default: "val09:8888" 56 | -para_factor (#keep queries being processed.) type: int64 default: 20 57 | -reg_mem_name (The name to register an MR at rctrl.) type: int64 58 | default: 73 59 | -reg_nic_name (The name to register an opened NIC at rctrl.) type: int64 60 | default: 73 61 | -threads (#Threads used.) type: int64 default: 1 62 | -use_nic_idx (Which NIC to create QP) type: int64 default: 0 63 | ``` 64 | 65 | > Note: If you change server host, you must add server address parameter to client like this: 66 | 67 | ```bash 68 | # client 69 | $cmd = 'cd rib/; ./bench_client -addr [your server IP]' 70 | ``` 71 | 72 | 73 | 74 | ## Performance 75 | 76 | ```bash 77 | $cd scripts/ 78 | $./bootstrap.py -f benchs/make.toml 79 | $./bootstrap.py -f benchs/run.toml 80 | ... 81 | [reporter.hh:33] epoch @ 3: thpt: 2.79313e+06 reqs/sec.1.0001e+06 msec passed since last epoch. 82 | [reporter.hh:33] epoch @ 4: thpt: 2.80423e+06 reqs/sec.1.00007e+06 msec passed since last epoch. 83 | [reporter.hh:33] epoch @ 5: thpt: 2.79937e+06 reqs/sec.1.00008e+06 msec passed since last epoch. 84 | ... 85 | ``` 86 | 87 | -------------------------------------------------------------------------------- /deps/r2/src/ring_msg/cm.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "rlib/core/lib.hh" 4 | 5 | #include "./proto.hh" 6 | 7 | namespace r2 { 8 | 9 | namespace ring_msg { 10 | 11 | using namespace rdmaio; 12 | 13 | // add a connect ring message for CM 14 | class RingCM : public ConnectManager { 15 | public: 16 | // FIXME: I remember there is a simpler form 17 | explicit RingCM(const std::string &addr) : ConnectManager(addr) {} 18 | 19 | // FIXME: maybe handle error more transparently 20 | Result connect_for_ring(const std::string &qp_name, 21 | const std::string &channel_name, 22 | const usize &ring_sz, 23 | const Arc<::rdmaio::qp::RC> rc, 24 | const ::rdmaio::nic_id_t &nic_id, 25 | const ::rdmaio::qp::QPConfig &config, 26 | const double &timeout_usec = 1000000) { 27 | 28 | RingReply dummy_reply; 29 | 30 | u64 temp_key = 0; 31 | 32 | if (unlikely(qp_name.size() > ::rdmaio::qp::kMaxQPNameLen)) { 33 | goto ErrCase; 34 | } 35 | 36 | { 37 | proto::RCReq req = {}; 38 | memcpy(req.name, qp_name.data(), qp_name.size()); 39 | memcpy(req.name_recv, channel_name.data(), channel_name.size()); 40 | 41 | req.whether_create = 1; 42 | req.whether_recv = 1; 43 | 44 | req.nic_id = nic_id; 45 | req.config = config; 46 | req.attr = rc->my_attr(); 47 | req.max_recv_sz = ring_sz; 48 | 49 | auto res = rpc.call(proto::CreateRCM, 50 | ::rdmaio::Marshal::dump(req)); 51 | 52 | // FIXME: below are the same as cc_rc(); maybe refine in a more elegant 53 | // form 54 | if (unlikely(res != IOCode::Ok)) { 55 | goto ErrCase; 56 | } 57 | 58 | auto res_reply = rpc.receive_reply(timeout_usec); 59 | 60 | if (res_reply == IOCode::Ok) { 61 | try { 62 | auto qp_reply = 63 | ::rdmaio::Marshal::dedump(res_reply.desc).value(); 64 | switch (qp_reply.rc_reply.status) { 65 | case proto::CallbackStatus::Ok: { 66 | auto ret = rc->connect(qp_reply.rc_reply.attr); 67 | if (ret != IOCode::Ok) { 68 | goto ErrCase; 69 | } 70 | return ::rdmaio::Ok(qp_reply); 71 | } break; 72 | default: 73 | goto ErrCase; 74 | } 75 | } catch (std::exception &e) { 76 | } 77 | } 78 | } 79 | 80 | ErrCase: 81 | return ::rdmaio::Err(dummy_reply); 82 | } 83 | }; 84 | 85 | } // namespace ring_msg 86 | 87 | } // namespace r2 88 | -------------------------------------------------------------------------------- /deps/rlib/tests/test_cm.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../core/lib.hh" 4 | #include "../core/qps/mod.hh" 5 | 6 | namespace test { 7 | 8 | using namespace rdmaio; 9 | using namespace rdmaio::qp; 10 | 11 | TEST(CM, MR) { 12 | RCtrl ctrl(8889); 13 | ctrl.start_daemon(); 14 | 15 | // now we register the MR to the CM 16 | 17 | // 1. open an RNic handler 18 | auto res = RNicInfo::query_dev_names(); 19 | ASSERT_FALSE(res.empty()); // there has to be NIC on the host machine 20 | 21 | Arc nic = Arc(new RNic(res[0])); 22 | 23 | // 2. allocate a buffer, and register it 24 | // allocate a memory with 1024 bytes 25 | auto mr = Arc(new RegHandler(Arc(new RMem(1024)), nic)); 26 | ctrl.registered_mrs.reg(73,mr); 27 | 28 | // 3. fetch it through ethernet 29 | ConnectManager cm("localhost:8889"); 30 | if (cm.wait_ready(1000000,2) == 31 | IOCode::Timeout) // wait 1 second for server to ready, retry 2 times 32 | assert(false); 33 | 34 | auto fetch_res = cm.fetch_remote_mr(73); 35 | RDMA_ASSERT(fetch_res == IOCode::Ok) << std::get<0>(fetch_res.desc); 36 | auto attr = std::get<1>(fetch_res.desc); 37 | 38 | // 4. check the remote fetched one is the same as the local copy 39 | auto local_mr = mr->get_reg_attr().value(); 40 | ASSERT_EQ(local_mr.buf,attr.buf); 41 | ASSERT_EQ(local_mr.sz, attr.sz); 42 | ASSERT_EQ(local_mr.key,attr.key); 43 | 44 | ctrl.stop_daemon(); 45 | } 46 | 47 | TEST(CM, QP) { 48 | RCtrl ctrl(6666); 49 | ctrl.start_daemon(); 50 | 51 | auto res = RNicInfo::query_dev_names(); 52 | ASSERT_FALSE(res.empty()); // there has to be NIC on the host machine 53 | 54 | auto nic = RNic::create(res[0]).value(); 55 | auto ud = UD::create(nic,QPConfig().set_qkey(73)).value(); 56 | auto test_attr = ud->my_attr(); 57 | 58 | ctrl.registered_qps.reg("test_ud_qp", ud).value(); 59 | 60 | ConnectManager cm("localhost:6666"); 61 | if (cm.wait_ready(1000000, 2) == 62 | IOCode::Timeout) // wait 1 second for server to ready, retry 2 times 63 | assert(false); 64 | 65 | auto fetch_qp_attr_res = cm.fetch_qp_attr("test_ud_qp"); 66 | RDMA_ASSERT(fetch_qp_attr_res == IOCode::Ok) 67 | << "fetch qp attr error: " << std::get<0>(fetch_qp_attr_res.desc); 68 | auto fetched_attr = std::get<1>(fetch_qp_attr_res.desc); 69 | 70 | // check the fetched attr matches the test_attr 71 | ASSERT_EQ(test_attr.lid,fetched_attr.lid); 72 | ASSERT_EQ(test_attr.psn, fetched_attr.psn); 73 | ASSERT_EQ(test_attr.port_id, fetched_attr.port_id); 74 | ASSERT_EQ(test_attr.qpn, fetched_attr.qpn); 75 | ASSERT_EQ(test_attr.qkey, fetched_attr.qkey); 76 | ASSERT_EQ(fetched_attr.qkey,73); 77 | RDMA_LOG(2) << "qkey: " << 73; 78 | 79 | ctrl.stop_daemon(); 80 | } 81 | 82 | }// namespace test 83 | -------------------------------------------------------------------------------- /xcomm/src/transport/trait.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // Result<> to record whether the op is done 6 | #include "../../../deps/rlib/core/result.hh" 7 | 8 | // Memblock, which abstract away a raw pointer 9 | #include "../../../deps/r2/src/mem_block.hh" 10 | 11 | namespace xstore { 12 | 13 | namespace transport { 14 | 15 | using namespace rdmaio; 16 | using namespace r2; 17 | 18 | // Send Trait 19 | template struct STrait { 20 | public: 21 | // send 22 | template 23 | auto connect(const std::string &host, Args ... args) -> Result<> { 24 | return reinterpret_cast(this)->connect_impl(host,args...); 25 | } 26 | 27 | auto send(const MemBlock &msg, const double &timeout = 1000000) 28 | -> Result { 29 | return reinterpret_cast(this)->send_impl(msg, timeout); 30 | } 31 | 32 | // RDMA should pass a lkey so that the RNIC is able to access the message 33 | // leave an explict function to all it 34 | auto send_w_key(const MemBlock &msg, const u32 &lkey,const double &timeout = 1000000) 35 | -> Result { 36 | return reinterpret_cast(this)->send_w_key_impl(msg, lkey, timeout); 37 | } 38 | 39 | auto get_connect_data() -> r2::Option { 40 | return reinterpret_cast(this)->get_connect_data_impl(); 41 | } 42 | }; 43 | 44 | // Recv Trait 45 | // ST state for send_trait, because receive trait will return the current send session 46 | template struct RTrait { 47 | public: 48 | void begin() { reinterpret_cast(this)->begin_impl(); } 49 | 50 | void end() { 51 | reinterpret_cast(this)->end_impl(); 52 | } 53 | 54 | void next() { reinterpret_cast(this)->next_impl(); } 55 | 56 | auto has_msgs()->bool { 57 | return reinterpret_cast(this)->has_msgs_impl(); 58 | } 59 | 60 | auto cur_msg() -> MemBlock { 61 | return reinterpret_cast(this)->cur_msg_impl(); 62 | } 63 | 64 | auto cur_session_id() -> u32 { 65 | return reinterpret_cast(this)->cur_session_id_impl(); 66 | } 67 | 68 | // legacy API 69 | auto reply_entry() -> ST { 70 | return reinterpret_cast(this)->reply_entry_impl(); 71 | } 72 | }; 73 | 74 | template 75 | struct SessionManager { 76 | std::unordered_map> incoming_sesions; 77 | 78 | // TODO: how to delete? 79 | auto add_new_session(const u32 &id, const MemBlock &raw_connect_data, RecvTrait &recv_trait) -> Result<> { 80 | return reinterpret_cast(this)->add_impl(id, raw_connect_data, recv_trait); 81 | } 82 | }; 83 | 84 | } // namespace transport 85 | } // namespace xstore 86 | -------------------------------------------------------------------------------- /deps/rlib/tests/test_mem.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../core/nicinfo.hh" 4 | #include "../core/rmem/handler.hh" 5 | 6 | namespace test { 7 | 8 | using namespace rdmaio; 9 | using namespace rdmaio::rmem; 10 | 11 | TEST(RMEM, can_reg) { 12 | auto res = RNicInfo::query_dev_names(); 13 | ASSERT_FALSE(res.empty()); // there has to be NIC on the host machine 14 | 15 | Arc nic = Arc(new RNic(res[0])); 16 | { 17 | // use RMem to allocate and manage a region of memory on the heap, 18 | // with size 1024 19 | auto mem = Arc(new RMem(1024)); 20 | // the allocation must be succesful 21 | ASSERT_TRUE(mem->valid()); 22 | 23 | // register this rmem to the RDMA Nic specificed by the nic 24 | RegHandler handler(mem, nic); 25 | ASSERT_TRUE(handler.valid()); 26 | ASSERT_TRUE(handler.get_reg_attr()); 27 | 28 | auto mem_not_valid = Arc(new RMem( 29 | 1024, [](u64 sz) { return nullptr; }, [](RMem::raw_ptr_t p) {})); 30 | ASSERT_FALSE(mem_not_valid->valid()); 31 | 32 | RegHandler handler_not_valid(mem_not_valid, nic); 33 | ASSERT_FALSE(handler_not_valid.valid()); 34 | } 35 | } 36 | 37 | TEST(RMEM, factory) { 38 | auto res = RNicInfo::query_dev_names(); 39 | ASSERT_FALSE(res.empty()); // there has to be NIC on the host machine 40 | 41 | MRFactory factory; 42 | { 43 | // the nic's ownership will be passed to factory 44 | // with the registered mr. 45 | // so it will not free RDMA resource (ctx,pd) even it goes out of scope 46 | Arc nic = Arc(new RNic(res[0])); 47 | { 48 | auto mr = Arc(new RegHandler(Arc(new RMem(1024)), nic)); 49 | auto res = factory.reg(73, mr); 50 | RDMA_ASSERT(res); 51 | 52 | // test that we filter out duplicate registeration. 53 | auto res1 = factory.reg(73, mr); 54 | RDMA_ASSERT(!res1); 55 | 56 | // test that an invalid MR should not be registered 57 | auto mem_not_valid = Arc(new RMem( 58 | 1024, [](u64 sz) { return nullptr; }, [](RMem::raw_ptr_t p) {})); 59 | ASSERT_FALSE(mem_not_valid->valid()); 60 | 61 | // finally, test create and register the MR 62 | auto mr3_res = factory.create_then_reg(12,Arc(new RMem(1024)),nic); 63 | RDMA_ASSERT(mr3_res); 64 | auto mr3 = std::get<0>(mr3_res.value()); 65 | ASSERT_TRUE(mr3->valid()); 66 | } 67 | } 68 | } 69 | 70 | TEST(RMEM, Err) { 71 | #if 0 72 | // an example to show the error case of not using Arc 73 | auto res = RNicInfo::query_dev_names(); 74 | RNic nic(res[0]); 75 | char *buffer = new char[1024]; 76 | auto mr = ibv_reg_mr(nic.get_pd(), buffer, 1024, MemoryFlags().get_value()); 77 | ASSERT_NE(mr,nullptr); 78 | delete buffer; 79 | #endif 80 | } 81 | 82 | } // namespace test 83 | -------------------------------------------------------------------------------- /xutils/cdf.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "./dist_report.hh" 6 | 7 | namespace xstore { 8 | 9 | namespace util { 10 | 11 | template 12 | class CDF 13 | { 14 | public: 15 | const std::string name; 16 | 17 | std::vector all_data; 18 | 19 | CDF(const std::string& data_name) 20 | : name(data_name) 21 | {} 22 | 23 | DistReport others; 24 | 25 | V& operator[](uint i) { return all_data[index_transfer(i)]; } 26 | 27 | void insert(const V& v) 28 | { 29 | others.add(v); 30 | all_data.push_back(v); 31 | } 32 | 33 | void clear() 34 | { 35 | others = DistReport(); 36 | all_data.clear(); 37 | } 38 | 39 | auto finalize() -> CDF& 40 | { 41 | std::sort(all_data.begin(), all_data.end()); 42 | return *this; 43 | } 44 | 45 | /*! 46 | Dump the whole DataMap as the python numpy format, which has the following 47 | format: X = [1,2,...,100] Y = [1% data,2% data,...100% data] 48 | */ 49 | std::string dump_as_np_data(const std::string& ylabel = "Y", 50 | const std::string& xlabel = "X") const 51 | { 52 | if (all_data.size() == 0) 53 | return "[]"; 54 | 55 | std::ostringstream osx; 56 | osx << "X = ["; 57 | std::ostringstream osy; 58 | osy << "Y = ["; 59 | for (uint i = 1; i <= 99; ++i) { 60 | osx << i << ","; 61 | osy << all_data[index_transfer(i)] << ","; 62 | } 63 | osx << "]"; 64 | osy << "]"; 65 | osx << std::endl << osy.str(); 66 | osx << std::endl << "title = \"" << name << "\"" << std::endl; 67 | osx << "ylabel = \"" << ylabel << "\"" << std::endl; 68 | osx << "xlabel = \"" << xlabel << "\"" << std::endl; 69 | return osx.str(); 70 | } 71 | 72 | static std::string dump_from_vec(std::vector& data, 73 | const std::string& name, 74 | const std::string& ylabel = "Y", 75 | const std::string& xlabel = "X") 76 | { 77 | CDF temp(name); 78 | temp.all_data = std::move(data); 79 | temp.finalize(); 80 | return temp.dump_as_np_data(ylabel, xlabel); 81 | } 82 | 83 | /*! 84 | Transform the percentage ( 10%) to the position in the all_data. 85 | \param: percentage in the data. 86 | */ 87 | uint index_transfer(uint percentage) const 88 | { 89 | assert(percentage >= 0 && percentage <= 100); 90 | auto idx = 91 | std::floor((static_cast(percentage) / 100.0) * all_data.size()); 92 | if (idx >= all_data.size()) 93 | idx = all_data.size() - 1; 94 | return idx; 95 | } 96 | }; 97 | 98 | } // namespace util 99 | 100 | } // namespace xstore 101 | --------------------------------------------------------------------------------