From 2156e7ce858c62540c93de0ba8c0987518d0cddc Mon Sep 17 00:00:00 2001 From: Tomasz Gromadzki Date: Thu, 29 Aug 2024 13:47:16 +0200 Subject: [PATCH 1/8] Revert "ci: build the librpma fio engine" This reverts commit 4e2bd713356cfc89ea6c898985c492af93b34a5d. --- ci/actions-install.sh | 7 +------ ...ctions-install-librpma.sh => travis-install-librpma.sh} | 3 ++- 2 files changed, 3 insertions(+), 7 deletions(-) rename ci/{actions-install-librpma.sh => travis-install-librpma.sh} (74%) diff --git a/ci/actions-install.sh b/ci/actions-install.sh index 77c511af33..1895e519a5 100755 --- a/ci/actions-install.sh +++ b/ci/actions-install.sh @@ -54,8 +54,7 @@ DPKGCFG libiscsi-dev libnbd-dev libpmem-dev - libpmem2-dev - libprotobuf-c-dev + libpmemblk-dev librbd-dev libtcmalloc-minimal4 libibverbs-dev @@ -96,10 +95,6 @@ DPKGCFG sudo apt-get -qq update echo "Installing packages... ${pkgs[@]}" sudo apt-get install -o APT::Immediate-Configure=false --no-install-recommends -qq -y "${pkgs[@]}" - if [ "${CI_TARGET_ARCH}" == "x86_64" ]; then - # install librpma from sources - ci/actions-install-librpma.sh - fi } # Fedora and related distributions diff --git a/ci/actions-install-librpma.sh b/ci/travis-install-librpma.sh similarity index 74% rename from ci/actions-install-librpma.sh rename to ci/travis-install-librpma.sh index 31f9f71259..4e5ed21d4d 100755 --- a/ci/actions-install-librpma.sh +++ b/ci/travis-install-librpma.sh @@ -1,6 +1,7 @@ #!/bin/bash -e -LIBRPMA_VERSION="1.0.0" +# 11.02.2021 Merge pull request #866 from ldorau/rpma-mmap-memory-for-rpma_mr_reg-in-rpma_flush_apm_new +LIBRPMA_VERSION=fbac593917e98f3f26abf14f4fad5a832b330f5c ZIP_FILE=rpma.zip WORKDIR=$(pwd) From f87aa551edddd31863c50592a4158d76acf24643 Mon Sep 17 00:00:00 2001 From: Tomasz Gromadzki Date: Thu, 29 Aug 2024 13:47:36 +0200 Subject: [PATCH 2/8] Revert "rpma: simplify server_cmpl_process()" This reverts commit d3061c18e84c91a417f8832b1a7cc09b1d26d1ee. --- engines/librpma_gpspm.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/engines/librpma_gpspm.c b/engines/librpma_gpspm.c index 70116d0d6e..e751e302e8 100644 --- a/engines/librpma_gpspm.c +++ b/engines/librpma_gpspm.c @@ -700,25 +700,29 @@ static int server_cmpl_process(struct thread_data *td) ret = rpma_cq_get_wc(csd->cq, 1, wc, NULL); if (ret == RPMA_E_NO_COMPLETION) { - if (o->busy_wait_polling) - return 0; /* lack of completion is not an error */ - - ret = rpma_cq_wait(csd->cq); - if (ret == RPMA_E_NO_COMPLETION) - return 0; /* lack of completion is not an error */ - if (ret) { - librpma_td_verror(td, ret, "rpma_cq_wait"); - goto err_terminate; - } - - ret = rpma_cq_get_wc(csd->cq, 1, wc, NULL); - if (ret == RPMA_E_NO_COMPLETION) - return 0; /* lack of completion is not an error */ - if (ret) { - librpma_td_verror(td, ret, "rpma_cq_get_wc"); - goto err_terminate; + if (o->busy_wait_polling == 0) { + ret = rpma_cq_wait(csd->cq); + if (ret == RPMA_E_NO_COMPLETION) { + /* lack of completion is not an error */ + return 0; + } else if (ret != 0) { + librpma_td_verror(td, ret, "rpma_cq_wait"); + goto err_terminate; + } + + ret = rpma_cq_get_wc(csd->cq, 1, wc, NULL); + if (ret == RPMA_E_NO_COMPLETION) { + /* lack of completion is not an error */ + return 0; + } else if (ret != 0) { + librpma_td_verror(td, ret, "rpma_cq_get_wc"); + goto err_terminate; + } + } else { + /* lack of completion is not an error */ + return 0; } - } else if (ret) { + } else if (ret != 0) { librpma_td_verror(td, ret, "rpma_cq_get_wc"); goto err_terminate; } From 7dd515ecfbfef915e862bdeb4e9692859ec40342 Mon Sep 17 00:00:00 2001 From: Tomasz Gromadzki Date: Thu, 29 Aug 2024 13:47:49 +0200 Subject: [PATCH 3/8] Revert "rpma: RPMA engines require librpma>=v0.11.0 with rpma_cq_get_wc()" This reverts commit d479658a965ac17ff213d7ba506116f822cb3219. --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index f3cb18a0c4..30867ea9e6 100755 --- a/configure +++ b/configure @@ -1031,7 +1031,7 @@ print_config "rdmacm" "$rdmacm" ########################################## # librpma probe -# The librpma engines require librpma>=v0.11.0 with rpma_cq_get_wc(). +# The librpma engine requires librpma>=v0.10.0 with rpma_mr_advise(). if test "$librpma" != "yes" ; then librpma="no" fi @@ -1039,7 +1039,7 @@ cat > $TMPC << EOF #include int main(void) { - void *ptr = rpma_cq_get_wc; + void *ptr = rpma_mr_advise; (void) ptr; /* unused */ return 0; } From 02763f740d65ca7132ae15176481d5bc305bd563 Mon Sep 17 00:00:00 2001 From: Tomasz Gromadzki Date: Thu, 29 Aug 2024 13:48:03 +0200 Subject: [PATCH 4/8] Revert "rpma: RPMA engine requires librpma>=v0.10.0 with rpma_mr_advise()" This reverts commit e662bc9815de906e3498f4261ec5a28481872a18. --- configure | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/configure b/configure index 30867ea9e6..420ce42a3a 100755 --- a/configure +++ b/configure @@ -1031,16 +1031,17 @@ print_config "rdmacm" "$rdmacm" ########################################## # librpma probe -# The librpma engine requires librpma>=v0.10.0 with rpma_mr_advise(). if test "$librpma" != "yes" ; then librpma="no" fi cat > $TMPC << EOF +#include #include -int main(void) +int main(int argc, char **argv) { - void *ptr = rpma_mr_advise; - (void) ptr; /* unused */ + enum rpma_conn_event event = RPMA_CONN_REJECTED; + (void) event; /* unused */ + rpma_log_set_threshold(RPMA_LOG_THRESHOLD, RPMA_LOG_LEVEL_INFO); return 0; } EOF From 036cc506cfe6a1674753b01c2ccc96c3aa47c339 Mon Sep 17 00:00:00 2001 From: Tomasz Gromadzki Date: Thu, 29 Aug 2024 13:55:27 +0200 Subject: [PATCH 5/8] Revert "rpma: add librpma_apm_* and librpma_gpspm_* engines" This reverts commit e4c4625ff8368f7667b2fe81cd2040186d440c94. --- HOWTO.rst | 16 +- Makefile | 23 - ci/travis-install-librpma.sh | 22 - configure | 54 -- engines/librpma_apm.c | 254 ------- engines/librpma_fio.c | 1079 ---------------------------- engines/librpma_fio.h | 282 -------- engines/librpma_fio_pmem.h | 67 -- engines/librpma_fio_pmem2.h | 91 --- engines/librpma_gpspm.c | 788 -------------------- engines/librpma_gpspm_flush.pb-c.c | 214 ------ engines/librpma_gpspm_flush.pb-c.h | 120 ---- engines/librpma_gpspm_flush.proto | 15 - examples/librpma_apm-client.fio | 24 - examples/librpma_apm-client.png | Bin 53792 -> 0 bytes examples/librpma_apm-server.fio | 26 - examples/librpma_apm-server.png | Bin 42611 -> 0 bytes examples/librpma_gpspm-client.fio | 23 - examples/librpma_gpspm-client.png | Bin 56398 -> 0 bytes examples/librpma_gpspm-server.fio | 33 - examples/librpma_gpspm-server.png | Bin 53793 -> 0 bytes fio.1 | 12 +- optgroup.c | 4 - optgroup.h | 2 - options.c | 10 - 25 files changed, 2 insertions(+), 3157 deletions(-) delete mode 100755 ci/travis-install-librpma.sh delete mode 100644 engines/librpma_apm.c delete mode 100644 engines/librpma_fio.c delete mode 100644 engines/librpma_fio.h delete mode 100644 engines/librpma_fio_pmem.h delete mode 100644 engines/librpma_fio_pmem2.h delete mode 100644 engines/librpma_gpspm.c delete mode 100644 engines/librpma_gpspm_flush.pb-c.c delete mode 100644 engines/librpma_gpspm_flush.pb-c.h delete mode 100644 engines/librpma_gpspm_flush.proto delete mode 100644 examples/librpma_apm-client.fio delete mode 100644 examples/librpma_apm-client.png delete mode 100644 examples/librpma_apm-server.fio delete mode 100644 examples/librpma_apm-server.png delete mode 100644 examples/librpma_gpspm-client.fio delete mode 100644 examples/librpma_gpspm-client.png delete mode 100644 examples/librpma_gpspm-server.fio delete mode 100644 examples/librpma_gpspm-server.png diff --git a/HOWTO.rst b/HOWTO.rst index 11b1c66934..4ef7a41da4 100644 --- a/HOWTO.rst +++ b/HOWTO.rst @@ -2667,7 +2667,7 @@ with the caveat that when used on the command line, they must come after the this will be the starting port number since fio will use a range of ports. - [rdma], [librpma_*] + [rdma] The port to use for RDMA-CM communication. This should be the same value on the client and the server side. @@ -2678,20 +2678,6 @@ with the caveat that when used on the command line, they must come after the is a TCP listener or UDP reader, the hostname is not used and must be omitted unless it is a valid UDP multicast address. -.. option:: serverip=str : [librpma_*] - - The IP address to be used for RDMA-CM based I/O. - -.. option:: direct_write_to_pmem=bool : [librpma_*] - - Set to 1 only when Direct Write to PMem from the remote host is possible. - Otherwise, set to 0. - -.. option:: busy_wait_polling=bool : [librpma_*_server] - - Set to 0 to wait for completion instead of busy-wait polling completion. - Default: 1. - .. option:: interface=str : [netsplice] [net] The IP address of the network interface used to send or receive UDP diff --git a/Makefile b/Makefile index be57e29651..746a27d480 100644 --- a/Makefile +++ b/Makefile @@ -108,29 +108,6 @@ ifdef CONFIG_RDMA rdma_LIBS = -libverbs -lrdmacm ENGINES += rdma endif -ifdef CONFIG_LIBRPMA_APM - librpma_apm_SRCS = engines/librpma_apm.c - librpma_fio_SRCS = engines/librpma_fio.c - ifdef CONFIG_LIBPMEM2_INSTALLED - librpma_apm_LIBS = -lrpma -lpmem2 - else - librpma_apm_LIBS = -lrpma -lpmem - endif - ENGINES += librpma_apm -endif -ifdef CONFIG_LIBRPMA_GPSPM - librpma_gpspm_SRCS = engines/librpma_gpspm.c engines/librpma_gpspm_flush.pb-c.c - librpma_fio_SRCS = engines/librpma_fio.c - ifdef CONFIG_LIBPMEM2_INSTALLED - librpma_gpspm_LIBS = -lrpma -lpmem2 -lprotobuf-c - else - librpma_gpspm_LIBS = -lrpma -lpmem -lprotobuf-c - endif - ENGINES += librpma_gpspm -endif -ifdef librpma_fio_SRCS - SOURCE += $(librpma_fio_SRCS) -endif ifdef CONFIG_POSIXAIO SOURCE += engines/posixaio.c endif diff --git a/ci/travis-install-librpma.sh b/ci/travis-install-librpma.sh deleted file mode 100755 index 4e5ed21d4d..0000000000 --- a/ci/travis-install-librpma.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -e - -# 11.02.2021 Merge pull request #866 from ldorau/rpma-mmap-memory-for-rpma_mr_reg-in-rpma_flush_apm_new -LIBRPMA_VERSION=fbac593917e98f3f26abf14f4fad5a832b330f5c -ZIP_FILE=rpma.zip - -WORKDIR=$(pwd) - -# install librpma -wget -O $ZIP_FILE https://github.com/pmem/rpma/archive/${LIBRPMA_VERSION}.zip -unzip $ZIP_FILE -mkdir -p rpma-${LIBRPMA_VERSION}/build -cd rpma-${LIBRPMA_VERSION}/build -cmake .. -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=/usr \ - -DBUILD_DOC=OFF \ - -DBUILD_EXAMPLES=OFF \ - -DBUILD_TESTS=OFF -make -j"$(nproc)" -sudo make -j"$(nproc)" install -cd "$WORKDIR" -rm -rf $ZIP_FILE rpma-${LIBRPMA_VERSION} diff --git a/configure b/configure index 420ce42a3a..eb92cde322 100755 --- a/configure +++ b/configure @@ -1029,49 +1029,6 @@ if test "$disable_rdma" != "yes" && compile_prog "" "-lrdmacm" "rdma"; then fi print_config "rdmacm" "$rdmacm" -########################################## -# librpma probe -if test "$librpma" != "yes" ; then - librpma="no" -fi -cat > $TMPC << EOF -#include -#include -int main(int argc, char **argv) -{ - enum rpma_conn_event event = RPMA_CONN_REJECTED; - (void) event; /* unused */ - rpma_log_set_threshold(RPMA_LOG_THRESHOLD, RPMA_LOG_LEVEL_INFO); - return 0; -} -EOF -if test "$disable_rdma" != "yes" && compile_prog "" "-lrpma" "rpma"; then - librpma="yes" -fi -print_config "librpma" "$librpma" - -########################################## -# libprotobuf-c probe -if test "$libprotobuf_c" != "yes" ; then - libprotobuf_c="no" -fi -cat > $TMPC << EOF -#include -#include -#if !defined(PROTOBUF_C_VERSION_NUMBER) -# error PROTOBUF_C_VERSION_NUMBER is not defined! -#endif -int main(int argc, char **argv) -{ - (void)protobuf_c_message_check(NULL); - return 0; -} -EOF -if compile_prog "" "-lprotobuf-c" "protobuf_c"; then - libprotobuf_c="yes" -fi -print_config "libprotobuf_c" "$libprotobuf_c" - ########################################## # asprintf() and vasprintf() probes if test "$have_asprintf" != "yes" ; then @@ -3120,17 +3077,6 @@ fi if test "$libverbs" = "yes" -a "$rdmacm" = "yes" ; then output_sym "CONFIG_RDMA" fi -# librpma is supported on the 'x86_64' architecture for now -if test "$cpu" = "x86_64" -a "$libverbs" = "yes" -a "$rdmacm" = "yes" \ - -a "$librpma" = "yes" \ - && test "$libpmem" = "yes" -o "$libpmem2" = "yes" ; then - output_sym "CONFIG_LIBRPMA_APM" -fi -if test "$cpu" = "x86_64" -a "$libverbs" = "yes" -a "$rdmacm" = "yes" \ - -a "$librpma" = "yes" -a "$libprotobuf_c" = "yes" \ - && test "$libpmem" = "yes" -o "$libpmem2" = "yes" ; then - output_sym "CONFIG_LIBRPMA_GPSPM" -fi if test "$clock_gettime" = "yes" ; then output_sym "CONFIG_CLOCK_GETTIME" fi diff --git a/engines/librpma_apm.c b/engines/librpma_apm.c deleted file mode 100644 index 896240dd2a..0000000000 --- a/engines/librpma_apm.c +++ /dev/null @@ -1,254 +0,0 @@ -/* -* librpma_apm: IO engine that uses PMDK librpma to read and write data, - * based on Appliance Persistency Method - * - * Copyright 2020-2021, Intel Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License, - * version 2 as published by the Free Software Foundation.. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "librpma_fio.h" - -/* client side implementation */ - -static inline int client_io_flush(struct thread_data *td, - struct io_u *first_io_u, struct io_u *last_io_u, - unsigned long long int len); - -static int client_get_io_u_index(struct ibv_wc *wc, unsigned int *io_u_index); - -static int client_init(struct thread_data *td) -{ - struct librpma_fio_client_data *ccd; - unsigned int sq_size; - uint32_t cq_size; - struct rpma_conn_cfg *cfg = NULL; - struct rpma_peer_cfg *pcfg = NULL; - int ret; - - /* not supported readwrite = trim / randtrim / trimwrite */ - if (td_trim(td)) { - td_verror(td, EINVAL, "Not supported mode."); - return -1; - } - - /* - * Calculate the required queue sizes where: - * - the send queue (SQ) has to be big enough to accommodate - * all io_us (WRITEs) and all flush requests (FLUSHes) - * - the completion queue (CQ) has to be big enough to accommodate all - * success and error completions (cq_size = sq_size) - */ - if (td_random(td) || td_rw(td)) { - /* - * sq_size = max(rand_read_sq_size, rand_write_sq_size) - * where rand_read_sq_size < rand_write_sq_size because read - * does not require flush afterwards - * rand_write_sq_size = N * (WRITE + FLUSH) - * - * Note: rw is no different from random write since having - * interleaved reads with writes in extreme forces you to flush - * as often as when the writes are random. - */ - sq_size = 2 * td->o.iodepth; - } else if (td_write(td)) { - /* sequential TD_DDIR_WRITE only */ - if (td->o.sync_io) { - sq_size = 2; /* WRITE + FLUSH */ - } else { - /* - * N * WRITE + B * FLUSH where: - * - B == ceil(iodepth / iodepth_batch) - * which is the number of batches for N writes - */ - sq_size = td->o.iodepth + LIBRPMA_FIO_CEIL(td->o.iodepth, - td->o.iodepth_batch); - } - } else { - /* TD_DDIR_READ only */ - if (td->o.sync_io) { - sq_size = 1; /* READ */ - } else { - sq_size = td->o.iodepth; /* N x READ */ - } - } - cq_size = sq_size; - - /* create a connection configuration object */ - if ((ret = rpma_conn_cfg_new(&cfg))) { - librpma_td_verror(td, ret, "rpma_conn_cfg_new"); - return -1; - } - - /* apply queue sizes */ - if ((ret = rpma_conn_cfg_set_sq_size(cfg, sq_size))) { - librpma_td_verror(td, ret, "rpma_conn_cfg_set_sq_size"); - goto err_cfg_delete; - } - if ((ret = rpma_conn_cfg_set_cq_size(cfg, cq_size))) { - librpma_td_verror(td, ret, "rpma_conn_cfg_set_cq_size"); - goto err_cfg_delete; - } - - if (librpma_fio_client_init(td, cfg)) - goto err_cfg_delete; - - ccd = td->io_ops_data; - - if (ccd->server_mr_flush_type == RPMA_FLUSH_TYPE_PERSISTENT) { - if (!ccd->ws->direct_write_to_pmem) { - if (td->thread_number == 1) - log_err( - "Fio librpma engine will not work until the Direct Write to PMem on the server side is possible (direct_write_to_pmem)\n"); - goto err_cleanup_common; - } - - /* configure peer's direct write to pmem support */ - if ((ret = rpma_peer_cfg_new(&pcfg))) { - librpma_td_verror(td, ret, "rpma_peer_cfg_new"); - goto err_cleanup_common; - } - - if ((ret = rpma_peer_cfg_set_direct_write_to_pmem(pcfg, true))) { - librpma_td_verror(td, ret, - "rpma_peer_cfg_set_direct_write_to_pmem"); - (void) rpma_peer_cfg_delete(&pcfg); - goto err_cleanup_common; - } - - if ((ret = rpma_conn_apply_remote_peer_cfg(ccd->conn, pcfg))) { - librpma_td_verror(td, ret, - "rpma_conn_apply_remote_peer_cfg"); - (void) rpma_peer_cfg_delete(&pcfg); - goto err_cleanup_common; - } - - (void) rpma_peer_cfg_delete(&pcfg); - } else if (td->thread_number == 1) { - /* XXX log_info mixes with the JSON output */ - log_err( - "Note: Direct Write to PMem is not supported by default nor required if you use DRAM instead of PMem on the server side (direct_write_to_pmem).\n" - "Remember that flushing to DRAM does not make your data persistent and may be used only for experimental purposes.\n"); - } - - if ((ret = rpma_conn_cfg_delete(&cfg))) { - librpma_td_verror(td, ret, "rpma_conn_cfg_delete"); - /* non fatal error - continue */ - } - - ccd->flush = client_io_flush; - ccd->get_io_u_index = client_get_io_u_index; - - return 0; - -err_cleanup_common: - librpma_fio_client_cleanup(td); - -err_cfg_delete: - (void) rpma_conn_cfg_delete(&cfg); - - return -1; -} - -static void client_cleanup(struct thread_data *td) -{ - struct librpma_fio_client_data *ccd = td->io_ops_data; - - if (ccd == NULL) - return; - - free(ccd->client_data); - - librpma_fio_client_cleanup(td); -} - -static inline int client_io_flush(struct thread_data *td, - struct io_u *first_io_u, struct io_u *last_io_u, - unsigned long long int len) -{ - struct librpma_fio_client_data *ccd = td->io_ops_data; - size_t dst_offset = first_io_u->offset; - int ret; - - if ((ret = rpma_flush(ccd->conn, ccd->server_mr, dst_offset, len, - ccd->server_mr_flush_type, RPMA_F_COMPLETION_ALWAYS, - (void *)(uintptr_t)last_io_u->index))) { - librpma_td_verror(td, ret, "rpma_flush"); - return -1; - } - - return 0; -} - -static int client_get_io_u_index(struct ibv_wc *wc, unsigned int *io_u_index) -{ - memcpy(io_u_index, &wc->wr_id, sizeof(*io_u_index)); - - return 1; -} - -FIO_STATIC struct ioengine_ops ioengine_client = { - .name = "librpma_apm_client", - .version = FIO_IOOPS_VERSION, - .init = client_init, - .post_init = librpma_fio_client_post_init, - .get_file_size = librpma_fio_client_get_file_size, - .open_file = librpma_fio_file_nop, - .queue = librpma_fio_client_queue, - .commit = librpma_fio_client_commit, - .getevents = librpma_fio_client_getevents, - .event = librpma_fio_client_event, - .errdetails = librpma_fio_client_errdetails, - .close_file = librpma_fio_file_nop, - .cleanup = client_cleanup, - .flags = FIO_DISKLESSIO | FIO_ASYNCIO_SETS_ISSUE_TIME, - .options = librpma_fio_options, - .option_struct_size = sizeof(struct librpma_fio_options_values), -}; - -/* server side implementation */ - -static int server_open_file(struct thread_data *td, struct fio_file *f) -{ - return librpma_fio_server_open_file(td, f, NULL); -} - -static enum fio_q_status server_queue(struct thread_data *td, struct io_u *io_u) -{ - return FIO_Q_COMPLETED; -} - -FIO_STATIC struct ioengine_ops ioengine_server = { - .name = "librpma_apm_server", - .version = FIO_IOOPS_VERSION, - .init = librpma_fio_server_init, - .open_file = server_open_file, - .close_file = librpma_fio_server_close_file, - .queue = server_queue, - .invalidate = librpma_fio_file_nop, - .cleanup = librpma_fio_server_cleanup, - .flags = FIO_SYNCIO, - .options = librpma_fio_options, - .option_struct_size = sizeof(struct librpma_fio_options_values), -}; - -/* register both engines */ - -static void fio_init fio_librpma_apm_register(void) -{ - register_ioengine(&ioengine_client); - register_ioengine(&ioengine_server); -} - -static void fio_exit fio_librpma_apm_unregister(void) -{ - unregister_ioengine(&ioengine_client); - unregister_ioengine(&ioengine_server); -} diff --git a/engines/librpma_fio.c b/engines/librpma_fio.c deleted file mode 100644 index 4ccc6d0bee..0000000000 --- a/engines/librpma_fio.c +++ /dev/null @@ -1,1079 +0,0 @@ -/* - * librpma_fio: librpma_apm and librpma_gpspm engines' common part. - * - * Copyright 2021-2022, Intel Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License, - * version 2 as published by the Free Software Foundation.. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifdef CONFIG_LIBPMEM2_INSTALLED -#include "librpma_fio_pmem2.h" -#else -#include "librpma_fio_pmem.h" -#endif /* CONFIG_LIBPMEM2_INSTALLED */ - -struct fio_option librpma_fio_options[] = { - { - .name = "serverip", - .lname = "rpma_server_ip", - .type = FIO_OPT_STR_STORE, - .off1 = offsetof(struct librpma_fio_options_values, server_ip), - .help = "IP address the server is listening on", - .def = "", - .category = FIO_OPT_C_ENGINE, - .group = FIO_OPT_G_LIBRPMA, - }, - { - .name = "port", - .lname = "rpma_server port", - .type = FIO_OPT_STR_STORE, - .off1 = offsetof(struct librpma_fio_options_values, port), - .help = "port the server is listening on", - .def = "7204", - .category = FIO_OPT_C_ENGINE, - .group = FIO_OPT_G_LIBRPMA, - }, - { - .name = "direct_write_to_pmem", - .lname = "Direct Write to PMem (via RDMA) from the remote host is possible", - .type = FIO_OPT_BOOL, - .off1 = offsetof(struct librpma_fio_options_values, - direct_write_to_pmem), - .help = "Set to true ONLY when Direct Write to PMem from the remote host is possible (https://pmem.io/rpma/documentation/basic-direct-write-to-pmem.html)", - .def = "", - .category = FIO_OPT_C_ENGINE, - .group = FIO_OPT_G_LIBRPMA, - }, - { - .name = "busy_wait_polling", - .lname = "Set to 0 to wait for completion instead of busy-wait polling completion.", - .type = FIO_OPT_BOOL, - .off1 = offsetof(struct librpma_fio_options_values, - busy_wait_polling), - .help = "Set to false if you want to reduce CPU usage", - .def = "1", - .category = FIO_OPT_C_ENGINE, - .group = FIO_OPT_G_LIBRPMA, - }, - { - .name = NULL, - }, -}; - -int librpma_fio_td_port(const char *port_base_str, struct thread_data *td, - char *port_out) -{ - unsigned long int port_ul = strtoul(port_base_str, NULL, 10); - unsigned int port_new; - - port_out[0] = '\0'; - - if (port_ul == ULONG_MAX) { - td_verror(td, errno, "strtoul"); - return -1; - } - port_ul += td->thread_number - 1; - if (port_ul >= UINT_MAX) { - log_err("[%u] port number (%lu) bigger than UINT_MAX\n", - td->thread_number, port_ul); - return -1; - } - - port_new = port_ul; - snprintf(port_out, LIBRPMA_FIO_PORT_STR_LEN_MAX - 1, "%u", port_new); - - return 0; -} - -char *librpma_fio_allocate_dram(struct thread_data *td, size_t size, - struct librpma_fio_mem *mem) -{ - char *mem_ptr = NULL; - int ret; - - if ((ret = posix_memalign((void **)&mem_ptr, page_size, size))) { - log_err("fio: posix_memalign() failed\n"); - td_verror(td, ret, "posix_memalign"); - return NULL; - } - - mem->mem_ptr = mem_ptr; - mem->size_mmap = 0; - - return mem_ptr; -} - -char *librpma_fio_allocate_pmem(struct thread_data *td, struct fio_file *f, - size_t size, struct librpma_fio_mem *mem) -{ - size_t ws_offset; - mem->mem_ptr = NULL; - - if (size % page_size) { - log_err("fio: size (%zu) is not aligned to page size (%zu)\n", - size, page_size); - return NULL; - } - - if (f->filetype == FIO_TYPE_CHAR) { - /* Each thread uses a separate offset within DeviceDAX. */ - ws_offset = (td->thread_number - 1) * size; - } else { - /* Each thread uses a separate FileSystemDAX file. No offset is needed. */ - ws_offset = 0; - } - - if (!f->file_name) { - log_err("fio: filename is not set\n"); - return NULL; - } - - if (librpma_fio_pmem_map_file(f, size, mem, ws_offset)) { - log_err("fio: librpma_fio_pmem_map_file(%s) failed\n", - f->file_name); - return NULL; - } - - log_info("fio: size of memory mapped from the file %s: %zu\n", - f->file_name, mem->size_mmap); - - log_info("fio: library used to map PMem from file: %s\n", RPMA_PMEM_USED); - - return mem->mem_ptr ? mem->mem_ptr + ws_offset : NULL; -} - -void librpma_fio_free(struct librpma_fio_mem *mem) -{ - if (mem->size_mmap) - librpma_fio_unmap(mem); - else - free(mem->mem_ptr); -} - -#define LIBRPMA_FIO_RETRY_MAX_NO 10 -#define LIBRPMA_FIO_RETRY_DELAY_S 5 - -int librpma_fio_client_init(struct thread_data *td, - struct rpma_conn_cfg *cfg) -{ - struct librpma_fio_client_data *ccd; - struct librpma_fio_options_values *o = td->eo; - struct ibv_context *dev = NULL; - char port_td[LIBRPMA_FIO_PORT_STR_LEN_MAX]; - struct rpma_conn_req *req = NULL; - enum rpma_conn_event event; - struct rpma_conn_private_data pdata; - enum rpma_log_level log_level_aux = RPMA_LOG_LEVEL_WARNING; - int remote_flush_type; - int retry; - int ret; - - /* --debug=net sets RPMA_LOG_THRESHOLD_AUX to RPMA_LOG_LEVEL_INFO */ -#ifdef FIO_INC_DEBUG - if ((1UL << FD_NET) & fio_debug) - log_level_aux = RPMA_LOG_LEVEL_INFO; -#endif - - /* configure logging thresholds to see more details */ - rpma_log_set_threshold(RPMA_LOG_THRESHOLD, RPMA_LOG_LEVEL_INFO); - rpma_log_set_threshold(RPMA_LOG_THRESHOLD_AUX, log_level_aux); - - /* obtain an IBV context for a remote IP address */ - if ((ret = rpma_utils_get_ibv_context(o->server_ip, - RPMA_UTIL_IBV_CONTEXT_REMOTE, &dev))) { - librpma_td_verror(td, ret, "rpma_utils_get_ibv_context"); - return -1; - } - - /* allocate client's data */ - ccd = calloc(1, sizeof(*ccd)); - if (ccd == NULL) { - td_verror(td, errno, "calloc"); - return -1; - } - - /* allocate all in-memory queues */ - ccd->io_us_queued = calloc(td->o.iodepth, sizeof(*ccd->io_us_queued)); - if (ccd->io_us_queued == NULL) { - td_verror(td, errno, "calloc"); - goto err_free_ccd; - } - - ccd->io_us_flight = calloc(td->o.iodepth, sizeof(*ccd->io_us_flight)); - if (ccd->io_us_flight == NULL) { - td_verror(td, errno, "calloc"); - goto err_free_io_u_queues; - } - - ccd->io_us_completed = calloc(td->o.iodepth, - sizeof(*ccd->io_us_completed)); - if (ccd->io_us_completed == NULL) { - td_verror(td, errno, "calloc"); - goto err_free_io_u_queues; - } - - /* create a new peer object */ - if ((ret = rpma_peer_new(dev, &ccd->peer))) { - librpma_td_verror(td, ret, "rpma_peer_new"); - goto err_free_io_u_queues; - } - - /* create a connection request */ - if (librpma_fio_td_port(o->port, td, port_td)) - goto err_peer_delete; - - for (retry = 0; retry < LIBRPMA_FIO_RETRY_MAX_NO; retry++) { - if ((ret = rpma_conn_req_new(ccd->peer, o->server_ip, port_td, - cfg, &req))) { - librpma_td_verror(td, ret, "rpma_conn_req_new"); - goto err_peer_delete; - } - - /* - * Connect the connection request - * and obtain the connection object. - */ - if ((ret = rpma_conn_req_connect(&req, NULL, &ccd->conn))) { - librpma_td_verror(td, ret, "rpma_conn_req_connect"); - goto err_req_delete; - } - - /* wait for the connection to establish */ - if ((ret = rpma_conn_next_event(ccd->conn, &event))) { - librpma_td_verror(td, ret, "rpma_conn_next_event"); - goto err_conn_delete; - } else if (event == RPMA_CONN_ESTABLISHED) { - break; - } else if (event == RPMA_CONN_REJECTED) { - (void) rpma_conn_disconnect(ccd->conn); - (void) rpma_conn_delete(&ccd->conn); - if (retry < LIBRPMA_FIO_RETRY_MAX_NO - 1) { - log_err("Thread [%d]: Retrying (#%i) ...\n", - td->thread_number, retry + 1); - sleep(LIBRPMA_FIO_RETRY_DELAY_S); - } else { - log_err( - "Thread [%d]: The maximum number of retries exceeded. Closing.\n", - td->thread_number); - } - } else { - log_err( - "rpma_conn_next_event returned an unexptected event: (%s != RPMA_CONN_ESTABLISHED)\n", - rpma_utils_conn_event_2str(event)); - goto err_conn_delete; - } - } - - if (retry > 0) - log_err("Thread [%d]: Connected after retry #%i\n", - td->thread_number, retry); - - if (ccd->conn == NULL) - goto err_peer_delete; - - /* get the connection's main CQ */ - if ((ret = rpma_conn_get_cq(ccd->conn, &ccd->cq))) { - librpma_td_verror(td, ret, "rpma_conn_get_cq"); - goto err_conn_delete; - } - - /* get the connection's private data sent from the server */ - if ((ret = rpma_conn_get_private_data(ccd->conn, &pdata))) { - librpma_td_verror(td, ret, "rpma_conn_get_private_data"); - goto err_conn_delete; - } - - /* get the server's workspace representation */ - ccd->ws = pdata.ptr; - - /* create the server's memory representation */ - if ((ret = rpma_mr_remote_from_descriptor(&ccd->ws->descriptor[0], - ccd->ws->mr_desc_size, &ccd->server_mr))) { - librpma_td_verror(td, ret, "rpma_mr_remote_from_descriptor"); - goto err_conn_delete; - } - - /* get the total size of the shared server memory */ - if ((ret = rpma_mr_remote_get_size(ccd->server_mr, &ccd->ws_size))) { - librpma_td_verror(td, ret, "rpma_mr_remote_get_size"); - goto err_conn_delete; - } - - /* get flush type of the remote node */ - if ((ret = rpma_mr_remote_get_flush_type(ccd->server_mr, - &remote_flush_type))) { - librpma_td_verror(td, ret, "rpma_mr_remote_get_flush_type"); - goto err_conn_delete; - } - - ccd->server_mr_flush_type = - (remote_flush_type & RPMA_MR_USAGE_FLUSH_TYPE_PERSISTENT) ? - RPMA_FLUSH_TYPE_PERSISTENT : RPMA_FLUSH_TYPE_VISIBILITY; - - /* - * Assure an io_us buffer allocation is page-size-aligned which is required - * to register for RDMA. User-provided value is intentionally ignored. - */ - td->o.mem_align = page_size; - - td->io_ops_data = ccd; - - return 0; - -err_conn_delete: - (void) rpma_conn_disconnect(ccd->conn); - (void) rpma_conn_delete(&ccd->conn); - -err_req_delete: - (void) rpma_conn_req_delete(&req); - -err_peer_delete: - (void) rpma_peer_delete(&ccd->peer); - -err_free_io_u_queues: - free(ccd->io_us_queued); - free(ccd->io_us_flight); - free(ccd->io_us_completed); - -err_free_ccd: - free(ccd); - - return -1; -} - -void librpma_fio_client_cleanup(struct thread_data *td) -{ - struct librpma_fio_client_data *ccd = td->io_ops_data; - enum rpma_conn_event ev; - int ret; - - if (ccd == NULL) - return; - - /* delete the iou's memory registration */ - if ((ret = rpma_mr_dereg(&ccd->orig_mr))) - librpma_td_verror(td, ret, "rpma_mr_dereg"); - /* delete the iou's memory registration */ - if ((ret = rpma_mr_remote_delete(&ccd->server_mr))) - librpma_td_verror(td, ret, "rpma_mr_remote_delete"); - /* initiate disconnection */ - if ((ret = rpma_conn_disconnect(ccd->conn))) - librpma_td_verror(td, ret, "rpma_conn_disconnect"); - /* wait for disconnection to end up */ - if ((ret = rpma_conn_next_event(ccd->conn, &ev))) { - librpma_td_verror(td, ret, "rpma_conn_next_event"); - } else if (ev != RPMA_CONN_CLOSED) { - log_err( - "client_cleanup received an unexpected event (%s != RPMA_CONN_CLOSED)\n", - rpma_utils_conn_event_2str(ev)); - } - /* delete the connection */ - if ((ret = rpma_conn_delete(&ccd->conn))) - librpma_td_verror(td, ret, "rpma_conn_delete"); - /* delete the peer */ - if ((ret = rpma_peer_delete(&ccd->peer))) - librpma_td_verror(td, ret, "rpma_peer_delete"); - /* free the software queues */ - free(ccd->io_us_queued); - free(ccd->io_us_flight); - free(ccd->io_us_completed); - free(ccd); - td->io_ops_data = NULL; /* zero ccd */ -} - -int librpma_fio_file_nop(struct thread_data *td, struct fio_file *f) -{ - /* NOP */ - return 0; -} - -int librpma_fio_client_post_init(struct thread_data *td) -{ - struct librpma_fio_client_data *ccd = td->io_ops_data; - size_t io_us_size; - int ret; - - /* - * td->orig_buffer is not aligned. The engine requires aligned io_us - * so FIO aligns up the address using the formula below. - */ - ccd->orig_buffer_aligned = PTR_ALIGN(td->orig_buffer, page_mask) + - td->o.mem_align; - - /* - * td->orig_buffer_size beside the space really consumed by io_us - * has paddings which can be omitted for the memory registration. - */ - io_us_size = (unsigned long long)td_max_bs(td) * - (unsigned long long)td->o.iodepth; - - if ((ret = rpma_mr_reg(ccd->peer, ccd->orig_buffer_aligned, io_us_size, - RPMA_MR_USAGE_READ_DST | RPMA_MR_USAGE_READ_SRC | - RPMA_MR_USAGE_WRITE_DST | RPMA_MR_USAGE_WRITE_SRC | - RPMA_MR_USAGE_FLUSH_TYPE_PERSISTENT, &ccd->orig_mr))) - librpma_td_verror(td, ret, "rpma_mr_reg"); - return ret; -} - -int librpma_fio_client_get_file_size(struct thread_data *td, - struct fio_file *f) -{ - struct librpma_fio_client_data *ccd = td->io_ops_data; - - f->real_file_size = ccd->ws_size; - fio_file_set_size_known(f); - - return 0; -} - -static enum fio_q_status client_queue_sync(struct thread_data *td, - struct io_u *io_u) -{ - struct librpma_fio_client_data *ccd = td->io_ops_data; - struct ibv_wc wc; - unsigned io_u_index; - int ret; - - /* execute io_u */ - if (io_u->ddir == DDIR_READ) { - /* post an RDMA read operation */ - if (librpma_fio_client_io_read(td, io_u, - RPMA_F_COMPLETION_ALWAYS)) - goto err; - } else if (io_u->ddir == DDIR_WRITE) { - /* post an RDMA write operation */ - if (librpma_fio_client_io_write(td, io_u)) - goto err; - if (ccd->flush(td, io_u, io_u, io_u->xfer_buflen)) - goto err; - } else { - log_err("unsupported IO mode: %s\n", io_ddir_name(io_u->ddir)); - goto err; - } - - do { - /* get a completion */ - ret = rpma_cq_get_wc(ccd->cq, 1, &wc, NULL); - if (ret == RPMA_E_NO_COMPLETION) { - /* lack of completion is not an error */ - continue; - } else if (ret != 0) { - /* an error occurred */ - librpma_td_verror(td, ret, "rpma_cq_get_wc"); - goto err; - } - - /* if io_us has completed with an error */ - if (wc.status != IBV_WC_SUCCESS) - goto err; - - if (wc.opcode == IBV_WC_SEND) - ++ccd->op_send_completed; - else { - if (wc.opcode == IBV_WC_RECV) - ++ccd->op_recv_completed; - - break; - } - } while (1); - - if (ccd->get_io_u_index(&wc, &io_u_index) != 1) - goto err; - - if (io_u->index != io_u_index) { - log_err( - "no matching io_u for received completion found (io_u_index=%u)\n", - io_u_index); - goto err; - } - - /* make sure all SENDs are completed before exit - clean up SQ */ - if (librpma_fio_client_io_complete_all_sends(td)) - goto err; - - return FIO_Q_COMPLETED; - -err: - io_u->error = -1; - return FIO_Q_COMPLETED; -} - -enum fio_q_status librpma_fio_client_queue(struct thread_data *td, - struct io_u *io_u) -{ - struct librpma_fio_client_data *ccd = td->io_ops_data; - - if (ccd->io_u_queued_nr == (int)td->o.iodepth) - return FIO_Q_BUSY; - - if (td->o.sync_io) - return client_queue_sync(td, io_u); - - /* io_u -> queued[] */ - ccd->io_us_queued[ccd->io_u_queued_nr] = io_u; - ccd->io_u_queued_nr++; - - return FIO_Q_QUEUED; -} - -int librpma_fio_client_commit(struct thread_data *td) -{ - struct librpma_fio_client_data *ccd = td->io_ops_data; - int flags = RPMA_F_COMPLETION_ON_ERROR; - struct timespec now; - bool fill_time; - int i; - struct io_u *flush_first_io_u = NULL; - unsigned long long int flush_len = 0; - - if (!ccd->io_us_queued) - return -1; - - /* execute all io_us from queued[] */ - for (i = 0; i < ccd->io_u_queued_nr; i++) { - struct io_u *io_u = ccd->io_us_queued[i]; - - if (io_u->ddir == DDIR_READ) { - if (i + 1 == ccd->io_u_queued_nr || - ccd->io_us_queued[i + 1]->ddir == DDIR_WRITE) - flags = RPMA_F_COMPLETION_ALWAYS; - /* post an RDMA read operation */ - if (librpma_fio_client_io_read(td, io_u, flags)) - return -1; - } else if (io_u->ddir == DDIR_WRITE) { - /* post an RDMA write operation */ - if (librpma_fio_client_io_write(td, io_u)) - return -1; - - /* cache the first io_u in the sequence */ - if (flush_first_io_u == NULL) - flush_first_io_u = io_u; - - /* - * the flush length is the sum of all io_u's creating - * the sequence - */ - flush_len += io_u->xfer_buflen; - - /* - * if io_u's are random the rpma_flush is required - * after each one of them - */ - if (!td_random(td)) { - /* - * When the io_u's are sequential and - * the current io_u is not the last one and - * the next one is also a write operation - * the flush can be postponed by one io_u and - * cover all of them which build a continuous - * sequence. - */ - if ((i + 1 < ccd->io_u_queued_nr) && - (ccd->io_us_queued[i + 1]->ddir == DDIR_WRITE)) - continue; - } - - /* flush all writes which build a continuous sequence */ - if (ccd->flush(td, flush_first_io_u, io_u, flush_len)) - return -1; - - /* - * reset the flush parameters in preparation for - * the next one - */ - flush_first_io_u = NULL; - flush_len = 0; - } else { - log_err("unsupported IO mode: %s\n", - io_ddir_name(io_u->ddir)); - return -1; - } - } - - if ((fill_time = fio_fill_issue_time(td))) { - fio_gettime(&now, NULL); - - /* - * only used for iolog - */ - if (td->o.read_iolog_file) - memcpy(&td->last_issue, &now, sizeof(now)); - - } - /* move executed io_us from queued[] to flight[] */ - for (i = 0; i < ccd->io_u_queued_nr; i++) { - struct io_u *io_u = ccd->io_us_queued[i]; - - /* FIO does not do this if the engine is asynchronous */ - if (fill_time) - memcpy(&io_u->issue_time, &now, sizeof(now)); - - /* move executed io_us from queued[] to flight[] */ - ccd->io_us_flight[ccd->io_u_flight_nr] = io_u; - ccd->io_u_flight_nr++; - - /* - * FIO says: - * If an engine has the commit hook - * it has to call io_u_queued() itself. - */ - io_u_queued(td, io_u); - } - - /* FIO does not do this if an engine has the commit hook. */ - io_u_mark_submit(td, ccd->io_u_queued_nr); - ccd->io_u_queued_nr = 0; - - return 0; -} - -/* - * RETURN VALUE - * - > 0 - a number of completed io_us - * - 0 - when no complicitions received - * - (-1) - when an error occurred - */ -static int client_getevent_process(struct thread_data *td) -{ - struct librpma_fio_client_data *ccd = td->io_ops_data; - struct ibv_wc wc; - /* io_u->index of completed io_u (wc.wr_id) */ - unsigned int io_u_index; - /* # of completed io_us */ - int cmpl_num = 0; - /* helpers */ - struct io_u *io_u; - int i; - int ret; - - /* get a completion */ - if ((ret = rpma_cq_get_wc(ccd->cq, 1, &wc, NULL))) { - /* lack of completion is not an error */ - if (ret == RPMA_E_NO_COMPLETION) { - /* lack of completion is not an error */ - return 0; - } - - /* an error occurred */ - librpma_td_verror(td, ret, "rpma_cq_get_wc"); - return -1; - } - - /* if io_us has completed with an error */ - if (wc.status != IBV_WC_SUCCESS) { - td->error = wc.status; - return -1; - } - - if (wc.opcode == IBV_WC_SEND) - ++ccd->op_send_completed; - else if (wc.opcode == IBV_WC_RECV) - ++ccd->op_recv_completed; - - if ((ret = ccd->get_io_u_index(&wc, &io_u_index)) != 1) - return ret; - - /* look for an io_u being completed */ - for (i = 0; i < ccd->io_u_flight_nr; ++i) { - if (ccd->io_us_flight[i]->index == io_u_index) { - cmpl_num = i + 1; - break; - } - } - - /* if no matching io_u has been found */ - if (cmpl_num == 0) { - log_err( - "no matching io_u for received completion found (io_u_index=%u)\n", - io_u_index); - return -1; - } - - /* move completed io_us to the completed in-memory queue */ - for (i = 0; i < cmpl_num; ++i) { - /* get and prepare io_u */ - io_u = ccd->io_us_flight[i]; - - /* append to the queue */ - ccd->io_us_completed[ccd->io_u_completed_nr] = io_u; - ccd->io_u_completed_nr++; - } - - /* remove completed io_us from the flight queue */ - for (i = cmpl_num; i < ccd->io_u_flight_nr; ++i) - ccd->io_us_flight[i - cmpl_num] = ccd->io_us_flight[i]; - ccd->io_u_flight_nr -= cmpl_num; - - return cmpl_num; -} - -int librpma_fio_client_getevents(struct thread_data *td, unsigned int min, - unsigned int max, const struct timespec *t) -{ - struct librpma_fio_client_data *ccd = td->io_ops_data; - /* total # of completed io_us */ - int cmpl_num_total = 0; - /* # of completed io_us from a single event */ - int cmpl_num; - - do { - cmpl_num = client_getevent_process(td); - if (cmpl_num > 0) { - /* new completions collected */ - cmpl_num_total += cmpl_num; - } else if (cmpl_num == 0) { - /* - * It is required to make sure that CQEs for SENDs - * will flow at least at the same pace as CQEs for RECVs. - */ - if (cmpl_num_total >= min && - ccd->op_send_completed >= ccd->op_recv_completed) - break; - - /* - * To reduce CPU consumption one can use - * the rpma_cq_wait() function. - * Note this greatly increase the latency - * and make the results less stable. - * The bandwidth stays more or less the same. - */ - } else { - /* an error occurred */ - return -1; - } - - /* - * The expected max can be exceeded if CQEs for RECVs will come up - * faster than CQEs for SENDs. But it is required to make sure CQEs for - * SENDs will flow at least at the same pace as CQEs for RECVs. - */ - } while (cmpl_num_total < max || - ccd->op_send_completed < ccd->op_recv_completed); - - /* - * All posted SENDs are completed and RECVs for them (responses) are - * completed. This is the initial situation so the counters are reset. - */ - if (ccd->op_send_posted == ccd->op_send_completed && - ccd->op_send_completed == ccd->op_recv_completed) { - ccd->op_send_posted = 0; - ccd->op_send_completed = 0; - ccd->op_recv_completed = 0; - } - - return cmpl_num_total; -} - -struct io_u *librpma_fio_client_event(struct thread_data *td, int event) -{ - struct librpma_fio_client_data *ccd = td->io_ops_data; - struct io_u *io_u; - int i; - - /* get the first io_u from the queue */ - io_u = ccd->io_us_completed[0]; - - /* remove the first io_u from the queue */ - for (i = 1; i < ccd->io_u_completed_nr; ++i) - ccd->io_us_completed[i - 1] = ccd->io_us_completed[i]; - ccd->io_u_completed_nr--; - - dprint_io_u(io_u, "client_event"); - - return io_u; -} - -char *librpma_fio_client_errdetails(struct thread_data *td, struct io_u *io_u) -{ - /* get the string representation of an error */ - enum ibv_wc_status status = io_u->error; - const char *status_str = ibv_wc_status_str(status); - - char *details = strdup(status_str); - if (details == NULL) { - fprintf(stderr, "Error: %s\n", status_str); - fprintf(stderr, "Fatal error: out of memory. Aborting.\n"); - abort(); - } - - /* FIO frees the returned string when it becomes obsolete */ - return details; -} - -int librpma_fio_server_init(struct thread_data *td) -{ - struct librpma_fio_options_values *o = td->eo; - struct librpma_fio_server_data *csd; - struct ibv_context *dev = NULL; - enum rpma_log_level log_level_aux = RPMA_LOG_LEVEL_WARNING; - int ret = -1; - - /* --debug=net sets RPMA_LOG_THRESHOLD_AUX to RPMA_LOG_LEVEL_INFO */ -#ifdef FIO_INC_DEBUG - if ((1UL << FD_NET) & fio_debug) - log_level_aux = RPMA_LOG_LEVEL_INFO; -#endif - - /* configure logging thresholds to see more details */ - rpma_log_set_threshold(RPMA_LOG_THRESHOLD, RPMA_LOG_LEVEL_INFO); - rpma_log_set_threshold(RPMA_LOG_THRESHOLD_AUX, log_level_aux); - - - /* obtain an IBV context for a remote IP address */ - if ((ret = rpma_utils_get_ibv_context(o->server_ip, - RPMA_UTIL_IBV_CONTEXT_LOCAL, &dev))) { - librpma_td_verror(td, ret, "rpma_utils_get_ibv_context"); - return -1; - } - - /* allocate server's data */ - csd = calloc(1, sizeof(*csd)); - if (csd == NULL) { - td_verror(td, errno, "calloc"); - return -1; - } - - /* create a new peer object */ - if ((ret = rpma_peer_new(dev, &csd->peer))) { - librpma_td_verror(td, ret, "rpma_peer_new"); - goto err_free_csd; - } - - td->io_ops_data = csd; - - return 0; - -err_free_csd: - free(csd); - - return -1; -} - -void librpma_fio_server_cleanup(struct thread_data *td) -{ - struct librpma_fio_server_data *csd = td->io_ops_data; - int ret; - - if (csd == NULL) - return; - - /* free the peer */ - if ((ret = rpma_peer_delete(&csd->peer))) - librpma_td_verror(td, ret, "rpma_peer_delete"); - - free(csd); -} - -int librpma_fio_server_open_file(struct thread_data *td, struct fio_file *f, - struct rpma_conn_cfg *cfg) -{ - struct librpma_fio_server_data *csd = td->io_ops_data; - struct librpma_fio_options_values *o = td->eo; - enum rpma_conn_event conn_event = RPMA_CONN_UNDEFINED; - struct librpma_fio_workspace ws = {0}; - struct rpma_conn_private_data pdata; - uint32_t max_msg_num; - struct rpma_conn_req *conn_req; - struct rpma_conn *conn; - struct rpma_mr_local *mr; - char port_td[LIBRPMA_FIO_PORT_STR_LEN_MAX]; - struct rpma_ep *ep; - size_t mem_size = td->o.size; - size_t mr_desc_size; - void *ws_ptr; - bool is_dram; - int usage_mem_type; - int ret; - - if (!f->file_name) { - log_err("fio: filename is not set\n"); - return -1; - } - - /* start a listening endpoint at addr:port */ - if (librpma_fio_td_port(o->port, td, port_td)) - return -1; - - if ((ret = rpma_ep_listen(csd->peer, o->server_ip, port_td, &ep))) { - librpma_td_verror(td, ret, "rpma_ep_listen"); - return -1; - } - - is_dram = !strcmp(f->file_name, "malloc"); - if (is_dram) { - /* allocation from DRAM using posix_memalign() */ - ws_ptr = librpma_fio_allocate_dram(td, mem_size, &csd->mem); - usage_mem_type = RPMA_MR_USAGE_FLUSH_TYPE_VISIBILITY; - } else { - /* allocation from PMEM using pmem_map_file() */ - ws_ptr = librpma_fio_allocate_pmem(td, f, mem_size, &csd->mem); - usage_mem_type = RPMA_MR_USAGE_FLUSH_TYPE_PERSISTENT; - } - - if (ws_ptr == NULL) - goto err_ep_shutdown; - - f->real_file_size = mem_size; - - if ((ret = rpma_mr_reg(csd->peer, ws_ptr, mem_size, - RPMA_MR_USAGE_READ_DST | RPMA_MR_USAGE_READ_SRC | - RPMA_MR_USAGE_WRITE_DST | RPMA_MR_USAGE_WRITE_SRC | - usage_mem_type, &mr))) { - librpma_td_verror(td, ret, "rpma_mr_reg"); - goto err_free; - } - - if (!is_dram && f->filetype == FIO_TYPE_FILE) { - ret = rpma_mr_advise(mr, 0, mem_size, - IBV_ADVISE_MR_ADVICE_PREFETCH_WRITE, - IBV_ADVISE_MR_FLAG_FLUSH); - if (ret) { - librpma_td_verror(td, ret, "rpma_mr_advise"); - /* an invalid argument is an error */ - if (ret == RPMA_E_INVAL) - goto err_mr_dereg; - - /* log_err used instead of log_info to avoid corruption of the JSON output */ - log_err("Note: having rpma_mr_advise(3) failed because of RPMA_E_NOSUPP or RPMA_E_PROVIDER may come with a performance penalty, but it is not a blocker for running the benchmark.\n"); - } - } - - /* get size of the memory region's descriptor */ - if ((ret = rpma_mr_get_descriptor_size(mr, &mr_desc_size))) { - librpma_td_verror(td, ret, "rpma_mr_get_descriptor_size"); - goto err_mr_dereg; - } - - /* verify size of the memory region's descriptor */ - if (mr_desc_size > LIBRPMA_FIO_DESCRIPTOR_MAX_SIZE) { - log_err( - "size of the memory region's descriptor is too big (max=%i)\n", - LIBRPMA_FIO_DESCRIPTOR_MAX_SIZE); - goto err_mr_dereg; - } - - /* get the memory region's descriptor */ - if ((ret = rpma_mr_get_descriptor(mr, &ws.descriptor[0]))) { - librpma_td_verror(td, ret, "rpma_mr_get_descriptor"); - goto err_mr_dereg; - } - - if (cfg != NULL) { - if ((ret = rpma_conn_cfg_get_rq_size(cfg, &max_msg_num))) { - librpma_td_verror(td, ret, "rpma_conn_cfg_get_rq_size"); - goto err_mr_dereg; - } - - /* verify whether iodepth fits into uint16_t */ - if (max_msg_num > UINT16_MAX) { - log_err("fio: iodepth too big (%u > %u)\n", - max_msg_num, UINT16_MAX); - return -1; - } - - ws.max_msg_num = max_msg_num; - } - - /* prepare a workspace description */ - ws.direct_write_to_pmem = o->direct_write_to_pmem; - ws.mr_desc_size = mr_desc_size; - pdata.ptr = &ws; - pdata.len = sizeof(ws); - - /* receive an incoming connection request */ - if ((ret = rpma_ep_next_conn_req(ep, cfg, &conn_req))) { - librpma_td_verror(td, ret, "rpma_ep_next_conn_req"); - goto err_mr_dereg; - } - - if (csd->prepare_connection && csd->prepare_connection(td, conn_req)) - goto err_req_delete; - - /* accept the connection request and obtain the connection object */ - if ((ret = rpma_conn_req_connect(&conn_req, &pdata, &conn))) { - librpma_td_verror(td, ret, "rpma_conn_req_connect"); - goto err_req_delete; - } - - /* wait for the connection to be established */ - if ((ret = rpma_conn_next_event(conn, &conn_event))) { - librpma_td_verror(td, ret, "rpma_conn_next_event"); - goto err_conn_delete; - } else if (conn_event != RPMA_CONN_ESTABLISHED) { - log_err("rpma_conn_next_event returned an unexptected event\n"); - goto err_conn_delete; - } - - /* end-point is no longer needed */ - (void) rpma_ep_shutdown(&ep); - - csd->ws_mr = mr; - csd->ws_ptr = ws_ptr; - csd->conn = conn; - - /* get the connection's main CQ */ - if ((ret = rpma_conn_get_cq(csd->conn, &csd->cq))) { - librpma_td_verror(td, ret, "rpma_conn_get_cq"); - goto err_conn_delete; - } - - return 0; - -err_conn_delete: - (void) rpma_conn_delete(&conn); - -err_req_delete: - (void) rpma_conn_req_delete(&conn_req); - -err_mr_dereg: - (void) rpma_mr_dereg(&mr); - -err_free: - librpma_fio_free(&csd->mem); - -err_ep_shutdown: - (void) rpma_ep_shutdown(&ep); - - return -1; -} - -int librpma_fio_server_close_file(struct thread_data *td, struct fio_file *f) -{ - struct librpma_fio_server_data *csd = td->io_ops_data; - enum rpma_conn_event conn_event = RPMA_CONN_UNDEFINED; - int rv = 0; - int ret; - - /* wait for the connection to be closed */ - ret = rpma_conn_next_event(csd->conn, &conn_event); - if (!ret && conn_event != RPMA_CONN_CLOSED) { - log_err("rpma_conn_next_event returned an unexptected event\n"); - rv = -1; - } - - if ((ret = rpma_conn_disconnect(csd->conn))) { - librpma_td_verror(td, ret, "rpma_conn_disconnect"); - rv = -1; - } - - if ((ret = rpma_conn_delete(&csd->conn))) { - librpma_td_verror(td, ret, "rpma_conn_delete"); - rv = -1; - } - - if ((ret = rpma_mr_dereg(&csd->ws_mr))) { - librpma_td_verror(td, ret, "rpma_mr_dereg"); - rv = -1; - } - - librpma_fio_free(&csd->mem); - - return rv; -} diff --git a/engines/librpma_fio.h b/engines/librpma_fio.h deleted file mode 100644 index 2bcbb37876..0000000000 --- a/engines/librpma_fio.h +++ /dev/null @@ -1,282 +0,0 @@ -/* - * librpma_fio: librpma_apm and librpma_gpspm engines' common header. - * - * Copyright 2021-2022, Intel Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License, - * version 2 as published by the Free Software Foundation.. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef LIBRPMA_FIO_H -#define LIBRPMA_FIO_H 1 - -#include "../fio.h" -#include "../optgroup.h" - -#include - -/* servers' and clients' common */ - -#define librpma_td_verror(td, err, func) \ - td_vmsg((td), (err), rpma_err_2str(err), (func)) - -/* ceil(a / b) = (a + b - 1) / b */ -#define LIBRPMA_FIO_CEIL(a, b) (((a) + (b) - 1) / (b)) - -/* common option structure for server and client */ -struct librpma_fio_options_values { - /* - * FIO considers .off1 == 0 absent so the first meaningful field has to - * have padding ahead of it. - */ - void *pad; - char *server_ip; - /* base server listening port */ - char *port; - /* Direct Write to PMem is possible */ - unsigned int direct_write_to_pmem; - /* Set to 0 to wait for completion instead of busy-wait polling completion. */ - unsigned int busy_wait_polling; -}; - -extern struct fio_option librpma_fio_options[]; - -/* - * Limited by the maximum length of the private data - * for rdma_connect() in case of RDMA_PS_TCP (28 bytes). - */ -#define LIBRPMA_FIO_DESCRIPTOR_MAX_SIZE 24 - -struct librpma_fio_workspace { - uint16_t max_msg_num; /* # of RQ slots */ - uint8_t direct_write_to_pmem; /* Direct Write to PMem is possible */ - uint8_t mr_desc_size; /* size of mr_desc in descriptor[] */ - /* buffer containing mr_desc */ - char descriptor[LIBRPMA_FIO_DESCRIPTOR_MAX_SIZE]; -}; - -#define LIBRPMA_FIO_PORT_STR_LEN_MAX 12 - -int librpma_fio_td_port(const char *port_base_str, struct thread_data *td, - char *port_out); - -struct librpma_fio_mem { - /* memory buffer */ - char *mem_ptr; - - /* size of the mapped persistent memory */ - size_t size_mmap; - -#ifdef CONFIG_LIBPMEM2_INSTALLED - /* libpmem2 structure used for mapping PMem */ - struct pmem2_map *map; -#endif -}; - -char *librpma_fio_allocate_dram(struct thread_data *td, size_t size, - struct librpma_fio_mem *mem); - -char *librpma_fio_allocate_pmem(struct thread_data *td, struct fio_file *f, - size_t size, struct librpma_fio_mem *mem); - -void librpma_fio_free(struct librpma_fio_mem *mem); - -/* clients' common */ - -typedef int (*librpma_fio_flush_t)(struct thread_data *td, - struct io_u *first_io_u, struct io_u *last_io_u, - unsigned long long int len); - -/* - * RETURN VALUE - * - ( 1) - on success - * - ( 0) - skip - * - (-1) - on error - */ -typedef int (*librpma_fio_get_io_u_index_t)(struct ibv_wc *wc, - unsigned int *io_u_index); - -struct librpma_fio_client_data { - struct rpma_peer *peer; - struct rpma_conn *conn; - struct rpma_cq *cq; - - /* aligned td->orig_buffer */ - char *orig_buffer_aligned; - - /* ious's base address memory registration (cd->orig_buffer_aligned) */ - struct rpma_mr_local *orig_mr; - - struct librpma_fio_workspace *ws; - - /* a server's memory representation */ - struct rpma_mr_remote *server_mr; - enum rpma_flush_type server_mr_flush_type; - - /* remote workspace description */ - size_t ws_size; - - /* in-memory queues */ - struct io_u **io_us_queued; - int io_u_queued_nr; - struct io_u **io_us_flight; - int io_u_flight_nr; - struct io_u **io_us_completed; - int io_u_completed_nr; - - /* SQ control. Note: all of them have to be kept in sync. */ - uint32_t op_send_posted; - uint32_t op_send_completed; - uint32_t op_recv_completed; - - librpma_fio_flush_t flush; - librpma_fio_get_io_u_index_t get_io_u_index; - - /* engine-specific client data */ - void *client_data; -}; - -int librpma_fio_client_init(struct thread_data *td, - struct rpma_conn_cfg *cfg); -void librpma_fio_client_cleanup(struct thread_data *td); - -int librpma_fio_file_nop(struct thread_data *td, struct fio_file *f); -int librpma_fio_client_get_file_size(struct thread_data *td, - struct fio_file *f); - -int librpma_fio_client_post_init(struct thread_data *td); - -enum fio_q_status librpma_fio_client_queue(struct thread_data *td, - struct io_u *io_u); - -int librpma_fio_client_commit(struct thread_data *td); - -int librpma_fio_client_getevents(struct thread_data *td, unsigned int min, - unsigned int max, const struct timespec *t); - -struct io_u *librpma_fio_client_event(struct thread_data *td, int event); - -char *librpma_fio_client_errdetails(struct thread_data *td, struct io_u *io_u); - -static inline int librpma_fio_client_io_read(struct thread_data *td, - struct io_u *io_u, int flags) -{ - struct librpma_fio_client_data *ccd = td->io_ops_data; - size_t dst_offset = (char *)(io_u->xfer_buf) - ccd->orig_buffer_aligned; - size_t src_offset = io_u->offset; - int ret; - - if ((ret = rpma_read(ccd->conn, ccd->orig_mr, dst_offset, - ccd->server_mr, src_offset, io_u->xfer_buflen, - flags, (void *)(uintptr_t)io_u->index))) { - librpma_td_verror(td, ret, "rpma_read"); - return -1; - } - - return 0; -} - -static inline int librpma_fio_client_io_write(struct thread_data *td, - struct io_u *io_u) -{ - struct librpma_fio_client_data *ccd = td->io_ops_data; - size_t src_offset = (char *)(io_u->xfer_buf) - ccd->orig_buffer_aligned; - size_t dst_offset = io_u->offset; - int ret; - - if ((ret = rpma_write(ccd->conn, ccd->server_mr, dst_offset, - ccd->orig_mr, src_offset, io_u->xfer_buflen, - RPMA_F_COMPLETION_ON_ERROR, - (void *)(uintptr_t)io_u->index))) { - librpma_td_verror(td, ret, "rpma_write"); - return -1; - } - - return 0; -} - -static inline int librpma_fio_client_io_complete_all_sends( - struct thread_data *td) -{ - struct librpma_fio_client_data *ccd = td->io_ops_data; - struct ibv_wc wc; - int ret; - - while (ccd->op_send_posted != ccd->op_send_completed) { - /* get a completion */ - ret = rpma_cq_get_wc(ccd->cq, 1, &wc, NULL); - if (ret == RPMA_E_NO_COMPLETION) { - /* lack of completion is not an error */ - continue; - } else if (ret != 0) { - /* an error occurred */ - librpma_td_verror(td, ret, "rpma_cq_get_wc"); - break; - } - - if (wc.status != IBV_WC_SUCCESS) - return -1; - - if (wc.opcode == IBV_WC_SEND) - ++ccd->op_send_completed; - else { - log_err( - "A completion other than IBV_WC_SEND got during cleaning up the CQ from SENDs\n"); - return -1; - } - } - - /* - * All posted SENDs are completed and RECVs for them (responses) are - * completed. This is the initial situation so the counters are reset. - */ - if (ccd->op_send_posted == ccd->op_send_completed && - ccd->op_send_completed == ccd->op_recv_completed) { - ccd->op_send_posted = 0; - ccd->op_send_completed = 0; - ccd->op_recv_completed = 0; - } - - return 0; -} - -/* servers' common */ - -typedef int (*librpma_fio_prepare_connection_t)( - struct thread_data *td, - struct rpma_conn_req *conn_req); - -struct librpma_fio_server_data { - struct rpma_peer *peer; - - /* resources of an incoming connection */ - struct rpma_conn *conn; - struct rpma_cq *cq; - - char *ws_ptr; - struct rpma_mr_local *ws_mr; - struct librpma_fio_mem mem; - - /* engine-specific server data */ - void *server_data; - - librpma_fio_prepare_connection_t prepare_connection; -}; - -int librpma_fio_server_init(struct thread_data *td); - -void librpma_fio_server_cleanup(struct thread_data *td); - -int librpma_fio_server_open_file(struct thread_data *td, - struct fio_file *f, struct rpma_conn_cfg *cfg); - -int librpma_fio_server_close_file(struct thread_data *td, - struct fio_file *f); - -#endif /* LIBRPMA_FIO_H */ diff --git a/engines/librpma_fio_pmem.h b/engines/librpma_fio_pmem.h deleted file mode 100644 index 4854292c4a..0000000000 --- a/engines/librpma_fio_pmem.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * librpma_fio_pmem: allocates pmem using libpmem. - * - * Copyright 2022, Intel Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License, - * version 2 as published by the Free Software Foundation.. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include "librpma_fio.h" - -#define RPMA_PMEM_USED "libpmem" - -static int librpma_fio_pmem_map_file(struct fio_file *f, size_t size, - struct librpma_fio_mem *mem, size_t ws_offset) -{ - int is_pmem = 0; - size_t size_mmap = 0; - - /* map the file */ - mem->mem_ptr = pmem_map_file(f->file_name, 0 /* len */, 0 /* flags */, - 0 /* mode */, &size_mmap, &is_pmem); - if (mem->mem_ptr == NULL) { - /* pmem_map_file() sets errno on failure */ - log_err("fio: pmem_map_file(%s) failed: %s (errno %i)\n", - f->file_name, strerror(errno), errno); - return -1; - } - - /* pmem is expected */ - if (!is_pmem) { - log_err("fio: %s is not located in persistent memory\n", - f->file_name); - goto err_unmap; - } - - /* check size of allocated persistent memory */ - if (size_mmap < ws_offset + size) { - log_err( - "fio: %s is too small to handle so many threads (%zu < %zu)\n", - f->file_name, size_mmap, ws_offset + size); - goto err_unmap; - } - - log_info("fio: size of memory mapped from the file %s: %zu\n", - f->file_name, size_mmap); - - mem->size_mmap = size_mmap; - - return 0; - -err_unmap: - (void) pmem_unmap(mem->mem_ptr, size_mmap); - return -1; -} - -static inline void librpma_fio_unmap(struct librpma_fio_mem *mem) -{ - (void) pmem_unmap(mem->mem_ptr, mem->size_mmap); -} diff --git a/engines/librpma_fio_pmem2.h b/engines/librpma_fio_pmem2.h deleted file mode 100644 index 09a51f5f40..0000000000 --- a/engines/librpma_fio_pmem2.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * librpma_fio_pmem2: allocates pmem using libpmem2. - * - * Copyright 2022, Intel Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License, - * version 2 as published by the Free Software Foundation.. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include "librpma_fio.h" - -#define RPMA_PMEM_USED "libpmem2" - -static int librpma_fio_pmem_map_file(struct fio_file *f, size_t size, - struct librpma_fio_mem *mem, size_t ws_offset) -{ - int fd; - struct pmem2_config *cfg = NULL; - struct pmem2_map *map = NULL; - struct pmem2_source *src = NULL; - - size_t size_mmap; - - if((fd = open(f->file_name, O_RDWR)) < 0) { - log_err("fio: cannot open fio file\n"); - return -1; - } - - if (pmem2_source_from_fd(&src, fd) != 0) { - log_err("fio: pmem2_source_from_fd() failed\n"); - goto err_close; - } - - if (pmem2_config_new(&cfg) != 0) { - log_err("fio: pmem2_config_new() failed\n"); - goto err_source_delete; - } - - if (pmem2_config_set_required_store_granularity(cfg, - PMEM2_GRANULARITY_CACHE_LINE) != 0) { - log_err("fio: pmem2_config_set_required_store_granularity() failed: %s\n", pmem2_errormsg()); - goto err_config_delete; - } - - if (pmem2_map_new(&map, cfg, src) != 0) { - log_err("fio: pmem2_map_new(%s) failed: %s\n", f->file_name, pmem2_errormsg()); - goto err_config_delete; - } - - size_mmap = pmem2_map_get_size(map); - - /* check size of allocated persistent memory */ - if (size_mmap < ws_offset + size) { - log_err( - "fio: %s is too small to handle so many threads (%zu < %zu)\n", - f->file_name, size_mmap, ws_offset + size); - goto err_map_delete; - } - - mem->mem_ptr = pmem2_map_get_address(map); - mem->size_mmap = size_mmap; - mem->map = map; - pmem2_config_delete(&cfg); - pmem2_source_delete(&src); - close(fd); - - return 0; - -err_map_delete: - pmem2_map_delete(&map); -err_config_delete: - pmem2_config_delete(&cfg); -err_source_delete: - pmem2_source_delete(&src); -err_close: - close(fd); - - return -1; -} - -static inline void librpma_fio_unmap(struct librpma_fio_mem *mem) -{ - (void) pmem2_map_delete(&mem->map); -} diff --git a/engines/librpma_gpspm.c b/engines/librpma_gpspm.c deleted file mode 100644 index e751e302e8..0000000000 --- a/engines/librpma_gpspm.c +++ /dev/null @@ -1,788 +0,0 @@ -/* - * librpma_gpspm: IO engine that uses PMDK librpma to write data, - * based on General Purpose Server Persistency Method - * - * Copyright 2020-2022, Intel Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License, - * version 2 as published by the Free Software Foundation.. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "librpma_fio.h" - -#ifdef CONFIG_LIBPMEM2_INSTALLED -#include -#else -#include -#endif - -/* Generated by the protocol buffer compiler from: librpma_gpspm_flush.proto */ -#include "librpma_gpspm_flush.pb-c.h" - -#define MAX_MSG_SIZE (512) -#define IO_U_BUF_LEN (2 * MAX_MSG_SIZE) -#define SEND_OFFSET (0) -#define RECV_OFFSET (SEND_OFFSET + MAX_MSG_SIZE) - -#define GPSPM_FLUSH_REQUEST__LAST \ - { PROTOBUF_C_MESSAGE_INIT(&gpspm_flush_request__descriptor), 0, 0, 0 } - -/* - * 'Flush_req_last' is the last flush request - * the client has to send to server to indicate - * that the client is done. - */ -static const GPSPMFlushRequest Flush_req_last = GPSPM_FLUSH_REQUEST__LAST; - -#define IS_NOT_THE_LAST_MESSAGE(flush_req) \ - (flush_req->length != Flush_req_last.length || \ - flush_req->offset != Flush_req_last.offset) - -/* client side implementation */ - -/* get next io_u message buffer in the round-robin fashion */ -#define IO_U_NEXT_BUF_OFF_CLIENT(cd) \ - (IO_U_BUF_LEN * ((cd->msg_curr++) % cd->msg_num)) - -struct client_data { - /* memory for sending and receiving buffered */ - char *io_us_msgs; - - /* resources for messaging buffer */ - uint32_t msg_num; - uint32_t msg_curr; - struct rpma_mr_local *msg_mr; -}; - -static inline int client_io_flush(struct thread_data *td, - struct io_u *first_io_u, struct io_u *last_io_u, - unsigned long long int len); - -static int client_get_io_u_index(struct ibv_wc *wc, unsigned int *io_u_index); - -static int client_init(struct thread_data *td) -{ - struct librpma_fio_client_data *ccd; - struct client_data *cd; - uint32_t write_num; - struct rpma_conn_cfg *cfg = NULL; - int ret; - - /* - * not supported: - * - readwrite = read / trim / randread / randtrim / - * / rw / randrw / trimwrite - */ - if (td_read(td) || td_trim(td)) { - td_verror(td, EINVAL, "Not supported mode."); - return -1; - } - - /* allocate client's data */ - cd = calloc(1, sizeof(*cd)); - if (cd == NULL) { - td_verror(td, errno, "calloc"); - return -1; - } - - /* - * Calculate the required number of WRITEs and FLUSHes. - * - * Note: Each flush is a request (SEND) and response (RECV) pair. - */ - if (td_random(td)) { - write_num = td->o.iodepth; /* WRITE * N */ - cd->msg_num = td->o.iodepth; /* FLUSH * N */ - } else { - if (td->o.sync_io) { - write_num = 1; /* WRITE */ - cd->msg_num = 1; /* FLUSH */ - } else { - write_num = td->o.iodepth; /* WRITE * N */ - /* - * FLUSH * B where: - * - B == ceil(iodepth / iodepth_batch) - * which is the number of batches for N writes - */ - cd->msg_num = LIBRPMA_FIO_CEIL(td->o.iodepth, - td->o.iodepth_batch); - } - } - - /* create a connection configuration object */ - if ((ret = rpma_conn_cfg_new(&cfg))) { - librpma_td_verror(td, ret, "rpma_conn_cfg_new"); - goto err_free_cd; - } - - /* - * Calculate the required queue sizes where: - * - the send queue (SQ) has to be big enough to accommodate - * all io_us (WRITEs) and all flush requests (SENDs) - * - the receive queue (RQ) has to be big enough to accommodate - * all flush responses (RECVs) - * - the completion queue (CQ) has to be big enough to accommodate all - * success and error completions (sq_size + rq_size) - */ - if ((ret = rpma_conn_cfg_set_sq_size(cfg, write_num + cd->msg_num))) { - librpma_td_verror(td, ret, "rpma_conn_cfg_set_sq_size"); - goto err_cfg_delete; - } - if ((ret = rpma_conn_cfg_set_rq_size(cfg, cd->msg_num))) { - librpma_td_verror(td, ret, "rpma_conn_cfg_set_rq_size"); - goto err_cfg_delete; - } - if ((ret = rpma_conn_cfg_set_cq_size(cfg, write_num + cd->msg_num * 2))) { - librpma_td_verror(td, ret, "rpma_conn_cfg_set_cq_size"); - goto err_cfg_delete; - } - - if (librpma_fio_client_init(td, cfg)) - goto err_cfg_delete; - - ccd = td->io_ops_data; - - if (ccd->ws->direct_write_to_pmem && - ccd->server_mr_flush_type == RPMA_FLUSH_TYPE_PERSISTENT && - td->thread_number == 1) { - /* XXX log_info mixes with the JSON output */ - log_err( - "Note: The server side supports Direct Write to PMem and it is equipped with PMem (direct_write_to_pmem).\n" - "You can use librpma_client and librpma_server engines for better performance instead of GPSPM.\n"); - } - - /* validate the server's RQ capacity */ - if (cd->msg_num > ccd->ws->max_msg_num) { - log_err( - "server's RQ size (iodepth) too small to handle the client's workspace requirements (%u < %u)\n", - ccd->ws->max_msg_num, cd->msg_num); - goto err_cleanup_common; - } - - if ((ret = rpma_conn_cfg_delete(&cfg))) { - librpma_td_verror(td, ret, "rpma_conn_cfg_delete"); - /* non fatal error - continue */ - } - - ccd->flush = client_io_flush; - ccd->get_io_u_index = client_get_io_u_index; - ccd->client_data = cd; - - return 0; - -err_cleanup_common: - librpma_fio_client_cleanup(td); - -err_cfg_delete: - (void) rpma_conn_cfg_delete(&cfg); - -err_free_cd: - free(cd); - - return -1; -} - -static int client_post_init(struct thread_data *td) -{ - struct librpma_fio_client_data *ccd = td->io_ops_data; - struct client_data *cd = ccd->client_data; - unsigned int io_us_msgs_size; - int ret; - - /* message buffers initialization and registration */ - io_us_msgs_size = cd->msg_num * IO_U_BUF_LEN; - if ((ret = posix_memalign((void **)&cd->io_us_msgs, page_size, - io_us_msgs_size))) { - td_verror(td, ret, "posix_memalign"); - return ret; - } - if ((ret = rpma_mr_reg(ccd->peer, cd->io_us_msgs, io_us_msgs_size, - RPMA_MR_USAGE_SEND | RPMA_MR_USAGE_RECV, - &cd->msg_mr))) { - librpma_td_verror(td, ret, "rpma_mr_reg"); - return ret; - } - - return librpma_fio_client_post_init(td); -} - -static void client_cleanup(struct thread_data *td) -{ - struct librpma_fio_client_data *ccd = td->io_ops_data; - struct client_data *cd; - size_t flush_req_size; - size_t io_u_buf_off; - size_t send_offset; - void *send_ptr; - int ret; - - if (ccd == NULL) - return; - - cd = ccd->client_data; - if (cd == NULL) { - librpma_fio_client_cleanup(td); - return; - } - - /* - * Make sure all SEND completions are collected ergo there are free - * slots in the SQ for the last SEND message. - * - * Note: If any operation will fail we still can send the termination - * notice. - */ - (void) librpma_fio_client_io_complete_all_sends(td); - - /* prepare the last flush message and pack it to the send buffer */ - flush_req_size = gpspm_flush_request__get_packed_size(&Flush_req_last); - if (flush_req_size > MAX_MSG_SIZE) { - log_err( - "Packed flush request size is bigger than available send buffer space (%zu > %d\n", - flush_req_size, MAX_MSG_SIZE); - } else { - io_u_buf_off = IO_U_NEXT_BUF_OFF_CLIENT(cd); - send_offset = io_u_buf_off + SEND_OFFSET; - send_ptr = cd->io_us_msgs + send_offset; - (void) gpspm_flush_request__pack(&Flush_req_last, send_ptr); - - /* send the flush message */ - if ((ret = rpma_send(ccd->conn, cd->msg_mr, send_offset, - flush_req_size, RPMA_F_COMPLETION_ALWAYS, - NULL))) - librpma_td_verror(td, ret, "rpma_send"); - - ++ccd->op_send_posted; - - /* Wait for the SEND to complete */ - (void) librpma_fio_client_io_complete_all_sends(td); - } - - /* deregister the messaging buffer memory */ - if ((ret = rpma_mr_dereg(&cd->msg_mr))) - librpma_td_verror(td, ret, "rpma_mr_dereg"); - - free(ccd->client_data); - - librpma_fio_client_cleanup(td); -} - -static inline int client_io_flush(struct thread_data *td, - struct io_u *first_io_u, struct io_u *last_io_u, - unsigned long long int len) -{ - struct librpma_fio_client_data *ccd = td->io_ops_data; - struct client_data *cd = ccd->client_data; - size_t io_u_buf_off = IO_U_NEXT_BUF_OFF_CLIENT(cd); - size_t send_offset = io_u_buf_off + SEND_OFFSET; - size_t recv_offset = io_u_buf_off + RECV_OFFSET; - void *send_ptr = cd->io_us_msgs + send_offset; - void *recv_ptr = cd->io_us_msgs + recv_offset; - GPSPMFlushRequest flush_req = GPSPM_FLUSH_REQUEST__INIT; - size_t flush_req_size = 0; - int ret; - - /* prepare a response buffer */ - if ((ret = rpma_recv(ccd->conn, cd->msg_mr, recv_offset, MAX_MSG_SIZE, - recv_ptr))) { - librpma_td_verror(td, ret, "rpma_recv"); - return -1; - } - - /* prepare a flush message and pack it to a send buffer */ - flush_req.offset = first_io_u->offset; - flush_req.length = len; - flush_req.op_context = last_io_u->index; - flush_req_size = gpspm_flush_request__get_packed_size(&flush_req); - if (flush_req_size > MAX_MSG_SIZE) { - log_err( - "Packed flush request size is bigger than available send buffer space (%" - PRIu64 " > %d\n", flush_req_size, MAX_MSG_SIZE); - return -1; - } - (void) gpspm_flush_request__pack(&flush_req, send_ptr); - - /* send the flush message */ - if ((ret = rpma_send(ccd->conn, cd->msg_mr, send_offset, flush_req_size, - RPMA_F_COMPLETION_ALWAYS, NULL))) { - librpma_td_verror(td, ret, "rpma_send"); - return -1; - } - - ++ccd->op_send_posted; - - return 0; -} - -static int client_get_io_u_index(struct ibv_wc *wc, unsigned int *io_u_index) -{ - GPSPMFlushResponse *flush_resp; - - if (wc->opcode != IBV_WC_RECV) - return 0; - - /* unpack a response from the received buffer */ - flush_resp = gpspm_flush_response__unpack(NULL, - wc->byte_len, (void *)wc->wr_id); - if (flush_resp == NULL) { - log_err("Cannot unpack the flush response buffer\n"); - return -1; - } - - memcpy(io_u_index, &flush_resp->op_context, sizeof(*io_u_index)); - - gpspm_flush_response__free_unpacked(flush_resp, NULL); - - return 1; -} - -FIO_STATIC struct ioengine_ops ioengine_client = { - .name = "librpma_gpspm_client", - .version = FIO_IOOPS_VERSION, - .init = client_init, - .post_init = client_post_init, - .get_file_size = librpma_fio_client_get_file_size, - .open_file = librpma_fio_file_nop, - .queue = librpma_fio_client_queue, - .commit = librpma_fio_client_commit, - .getevents = librpma_fio_client_getevents, - .event = librpma_fio_client_event, - .errdetails = librpma_fio_client_errdetails, - .close_file = librpma_fio_file_nop, - .cleanup = client_cleanup, - .flags = FIO_DISKLESSIO | FIO_ASYNCIO_SETS_ISSUE_TIME, - .options = librpma_fio_options, - .option_struct_size = sizeof(struct librpma_fio_options_values), -}; - -/* server side implementation */ - -#define IO_U_BUFF_OFF_SERVER(i) (i * IO_U_BUF_LEN) - -typedef void (*librpma_fio_persist_fn)(const void *ptr, size_t size); - -struct server_data { - /* aligned td->orig_buffer */ - char *orig_buffer_aligned; - - /* resources for messaging buffer from DRAM allocated by fio */ - struct rpma_mr_local *msg_mr; - - uint32_t msg_sqe_available; /* # of free SQ slots */ - - /* in-memory queues */ - struct ibv_wc *msgs_queued; - uint32_t msg_queued_nr; - - librpma_fio_persist_fn persist; -}; - -static int server_init(struct thread_data *td) -{ - struct librpma_fio_server_data *csd; - struct server_data *sd; - int ret = -1; - - if ((ret = librpma_fio_server_init(td))) - return ret; - - csd = td->io_ops_data; - - /* allocate server's data */ - sd = calloc(1, sizeof(*sd)); - if (sd == NULL) { - td_verror(td, errno, "calloc"); - goto err_server_cleanup; - } - - /* allocate in-memory queue */ - sd->msgs_queued = calloc(td->o.iodepth, sizeof(*sd->msgs_queued)); - if (sd->msgs_queued == NULL) { - td_verror(td, errno, "calloc"); - goto err_free_sd; - } - -#ifdef CONFIG_LIBPMEM2_INSTALLED - /* get libpmem2 persist function from pmem2_map */ - sd->persist = pmem2_get_persist_fn(csd->mem.map); -#else - sd->persist = pmem_persist; -#endif - - /* - * Assure a single io_u buffer can store both SEND and RECV messages and - * an io_us buffer allocation is page-size-aligned which is required - * to register for RDMA. User-provided values are intentionally ignored. - */ - td->o.max_bs[DDIR_READ] = IO_U_BUF_LEN; - td->o.mem_align = page_size; - - csd->server_data = sd; - - return 0; - -err_free_sd: - free(sd); - -err_server_cleanup: - librpma_fio_server_cleanup(td); - - return -1; -} - -static int server_post_init(struct thread_data *td) -{ - struct librpma_fio_server_data *csd = td->io_ops_data; - struct server_data *sd = csd->server_data; - size_t io_us_size; - size_t io_u_buflen; - int ret; - - /* - * td->orig_buffer is not aligned. The engine requires aligned io_us - * so FIO aligns up the address using the formula below. - */ - sd->orig_buffer_aligned = PTR_ALIGN(td->orig_buffer, page_mask) + - td->o.mem_align; - - /* - * XXX - * Each io_u message buffer contains recv and send messages. - * Aligning each of those buffers may potentially give - * some performance benefits. - */ - io_u_buflen = td_max_bs(td); - - /* check whether io_u buffer is big enough */ - if (io_u_buflen < IO_U_BUF_LEN) { - log_err( - "blocksize too small to accommodate assumed maximal request/response pair size (%" PRIu64 " < %d)\n", - io_u_buflen, IO_U_BUF_LEN); - return -1; - } - - /* - * td->orig_buffer_size beside the space really consumed by io_us - * has paddings which can be omitted for the memory registration. - */ - io_us_size = (unsigned long long)io_u_buflen * - (unsigned long long)td->o.iodepth; - - if ((ret = rpma_mr_reg(csd->peer, sd->orig_buffer_aligned, io_us_size, - RPMA_MR_USAGE_SEND | RPMA_MR_USAGE_RECV, - &sd->msg_mr))) { - librpma_td_verror(td, ret, "rpma_mr_reg"); - return -1; - } - - return 0; -} - -static void server_cleanup(struct thread_data *td) -{ - struct librpma_fio_server_data *csd = td->io_ops_data; - struct server_data *sd; - int ret; - - if (csd == NULL) - return; - - sd = csd->server_data; - - if (sd != NULL) { - /* rpma_mr_dereg(messaging buffer from DRAM) */ - if ((ret = rpma_mr_dereg(&sd->msg_mr))) - librpma_td_verror(td, ret, "rpma_mr_dereg"); - - free(sd->msgs_queued); - free(sd); - } - - librpma_fio_server_cleanup(td); -} - -static int prepare_connection(struct thread_data *td, - struct rpma_conn_req *conn_req) -{ - struct librpma_fio_server_data *csd = td->io_ops_data; - struct server_data *sd = csd->server_data; - int ret; - int i; - - /* prepare buffers for a flush requests */ - sd->msg_sqe_available = td->o.iodepth; - for (i = 0; i < td->o.iodepth; i++) { - size_t offset_recv_msg = IO_U_BUFF_OFF_SERVER(i) + RECV_OFFSET; - if ((ret = rpma_conn_req_recv(conn_req, sd->msg_mr, - offset_recv_msg, MAX_MSG_SIZE, - (const void *)(uintptr_t)i))) { - librpma_td_verror(td, ret, "rpma_conn_req_recv"); - return ret; - } - } - - return 0; -} - -static int server_open_file(struct thread_data *td, struct fio_file *f) -{ - struct librpma_fio_server_data *csd = td->io_ops_data; - struct rpma_conn_cfg *cfg = NULL; - uint16_t max_msg_num = td->o.iodepth; - int ret; - - csd->prepare_connection = prepare_connection; - - /* create a connection configuration object */ - if ((ret = rpma_conn_cfg_new(&cfg))) { - librpma_td_verror(td, ret, "rpma_conn_cfg_new"); - return -1; - } - - /* - * Calculate the required queue sizes where: - * - the send queue (SQ) has to be big enough to accommodate - * all possible flush requests (SENDs) - * - the receive queue (RQ) has to be big enough to accommodate - * all flush responses (RECVs) - * - the completion queue (CQ) has to be big enough to accommodate - * all success and error completions (sq_size + rq_size) - */ - if ((ret = rpma_conn_cfg_set_sq_size(cfg, max_msg_num))) { - librpma_td_verror(td, ret, "rpma_conn_cfg_set_sq_size"); - goto err_cfg_delete; - } - if ((ret = rpma_conn_cfg_set_rq_size(cfg, max_msg_num))) { - librpma_td_verror(td, ret, "rpma_conn_cfg_set_rq_size"); - goto err_cfg_delete; - } - if ((ret = rpma_conn_cfg_set_cq_size(cfg, max_msg_num * 2))) { - librpma_td_verror(td, ret, "rpma_conn_cfg_set_cq_size"); - goto err_cfg_delete; - } - - ret = librpma_fio_server_open_file(td, f, cfg); - -err_cfg_delete: - (void) rpma_conn_cfg_delete(&cfg); - - return ret; -} - -static int server_qe_process(struct thread_data *td, struct ibv_wc *wc) -{ - struct librpma_fio_server_data *csd = td->io_ops_data; - struct server_data *sd = csd->server_data; - GPSPMFlushRequest *flush_req; - GPSPMFlushResponse flush_resp = GPSPM_FLUSH_RESPONSE__INIT; - size_t flush_resp_size = 0; - size_t send_buff_offset; - size_t recv_buff_offset; - size_t io_u_buff_offset; - void *send_buff_ptr; - void *recv_buff_ptr; - void *op_ptr; - int msg_index; - int ret; - - /* calculate SEND/RECV pair parameters */ - msg_index = (int)(uintptr_t)wc->wr_id; - io_u_buff_offset = IO_U_BUFF_OFF_SERVER(msg_index); - send_buff_offset = io_u_buff_offset + SEND_OFFSET; - recv_buff_offset = io_u_buff_offset + RECV_OFFSET; - send_buff_ptr = sd->orig_buffer_aligned + send_buff_offset; - recv_buff_ptr = sd->orig_buffer_aligned + recv_buff_offset; - - /* unpack a flush request from the received buffer */ - flush_req = gpspm_flush_request__unpack(NULL, wc->byte_len, - recv_buff_ptr); - if (flush_req == NULL) { - log_err("cannot unpack the flush request buffer\n"); - goto err_terminate; - } - - if (IS_NOT_THE_LAST_MESSAGE(flush_req)) { - op_ptr = csd->ws_ptr + flush_req->offset; - sd->persist(op_ptr, flush_req->length); - } else { - /* - * This is the last message - the client is done. - */ - gpspm_flush_request__free_unpacked(flush_req, NULL); - td->done = true; - return 0; - } - - /* initiate the next receive operation */ - if ((ret = rpma_recv(csd->conn, sd->msg_mr, recv_buff_offset, - MAX_MSG_SIZE, - (const void *)(uintptr_t)msg_index))) { - librpma_td_verror(td, ret, "rpma_recv"); - goto err_free_unpacked; - } - - /* prepare a flush response and pack it to a send buffer */ - flush_resp.op_context = flush_req->op_context; - flush_resp_size = gpspm_flush_response__get_packed_size(&flush_resp); - if (flush_resp_size > MAX_MSG_SIZE) { - log_err( - "Size of the packed flush response is bigger than the available space of the send buffer (%" - PRIu64 " > %i\n", flush_resp_size, MAX_MSG_SIZE); - goto err_free_unpacked; - } - - (void) gpspm_flush_response__pack(&flush_resp, send_buff_ptr); - - /* send the flush response */ - if ((ret = rpma_send(csd->conn, sd->msg_mr, send_buff_offset, - flush_resp_size, RPMA_F_COMPLETION_ALWAYS, NULL))) { - librpma_td_verror(td, ret, "rpma_send"); - goto err_free_unpacked; - } - --sd->msg_sqe_available; - - gpspm_flush_request__free_unpacked(flush_req, NULL); - - return 0; - -err_free_unpacked: - gpspm_flush_request__free_unpacked(flush_req, NULL); - -err_terminate: - td->terminate = true; - - return -1; -} - -static inline int server_queue_process(struct thread_data *td) -{ - struct librpma_fio_server_data *csd = td->io_ops_data; - struct server_data *sd = csd->server_data; - int ret; - int i; - - /* min(# of queue entries, # of SQ entries available) */ - uint32_t qes_to_process = min(sd->msg_queued_nr, sd->msg_sqe_available); - if (qes_to_process == 0) - return 0; - - /* process queued completions */ - for (i = 0; i < qes_to_process; ++i) { - if ((ret = server_qe_process(td, &sd->msgs_queued[i]))) - return ret; - } - - /* progress the queue */ - for (i = 0; i < sd->msg_queued_nr - qes_to_process; ++i) { - memcpy(&sd->msgs_queued[i], - &sd->msgs_queued[qes_to_process + i], - sizeof(sd->msgs_queued[i])); - } - - sd->msg_queued_nr -= qes_to_process; - - return 0; -} - -static int server_cmpl_process(struct thread_data *td) -{ - struct librpma_fio_server_data *csd = td->io_ops_data; - struct server_data *sd = csd->server_data; - struct ibv_wc *wc = &sd->msgs_queued[sd->msg_queued_nr]; - struct librpma_fio_options_values *o = td->eo; - int ret; - - ret = rpma_cq_get_wc(csd->cq, 1, wc, NULL); - if (ret == RPMA_E_NO_COMPLETION) { - if (o->busy_wait_polling == 0) { - ret = rpma_cq_wait(csd->cq); - if (ret == RPMA_E_NO_COMPLETION) { - /* lack of completion is not an error */ - return 0; - } else if (ret != 0) { - librpma_td_verror(td, ret, "rpma_cq_wait"); - goto err_terminate; - } - - ret = rpma_cq_get_wc(csd->cq, 1, wc, NULL); - if (ret == RPMA_E_NO_COMPLETION) { - /* lack of completion is not an error */ - return 0; - } else if (ret != 0) { - librpma_td_verror(td, ret, "rpma_cq_get_wc"); - goto err_terminate; - } - } else { - /* lack of completion is not an error */ - return 0; - } - } else if (ret != 0) { - librpma_td_verror(td, ret, "rpma_cq_get_wc"); - goto err_terminate; - } - - /* validate the completion */ - if (wc->status != IBV_WC_SUCCESS) - goto err_terminate; - - if (wc->opcode == IBV_WC_RECV) - ++sd->msg_queued_nr; - else if (wc->opcode == IBV_WC_SEND) - ++sd->msg_sqe_available; - - return 0; - -err_terminate: - td->terminate = true; - - return -1; -} - -static enum fio_q_status server_queue(struct thread_data *td, struct io_u *io_u) -{ - do { - if (server_cmpl_process(td)) - return FIO_Q_BUSY; - - if (server_queue_process(td)) - return FIO_Q_BUSY; - - } while (!td->done); - - return FIO_Q_COMPLETED; -} - -FIO_STATIC struct ioengine_ops ioengine_server = { - .name = "librpma_gpspm_server", - .version = FIO_IOOPS_VERSION, - .init = server_init, - .post_init = server_post_init, - .open_file = server_open_file, - .close_file = librpma_fio_server_close_file, - .queue = server_queue, - .invalidate = librpma_fio_file_nop, - .cleanup = server_cleanup, - .flags = FIO_SYNCIO, - .options = librpma_fio_options, - .option_struct_size = sizeof(struct librpma_fio_options_values), -}; - -/* register both engines */ - -static void fio_init fio_librpma_gpspm_register(void) -{ - register_ioengine(&ioengine_client); - register_ioengine(&ioengine_server); -} - -static void fio_exit fio_librpma_gpspm_unregister(void) -{ - unregister_ioengine(&ioengine_client); - unregister_ioengine(&ioengine_server); -} diff --git a/engines/librpma_gpspm_flush.pb-c.c b/engines/librpma_gpspm_flush.pb-c.c deleted file mode 100644 index 3ff2475612..0000000000 --- a/engines/librpma_gpspm_flush.pb-c.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright 2020, Intel Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License, - * version 2 as published by the Free Software Foundation.. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/* Generated by the protocol buffer compiler. DO NOT EDIT! */ -/* Generated from: librpma_gpspm_flush.proto */ - -/* Do not generate deprecated warnings for self */ -#ifndef PROTOBUF_C__NO_DEPRECATED -#define PROTOBUF_C__NO_DEPRECATED -#endif - -#include "librpma_gpspm_flush.pb-c.h" -void gpspm_flush_request__init - (GPSPMFlushRequest *message) -{ - static const GPSPMFlushRequest init_value = GPSPM_FLUSH_REQUEST__INIT; - *message = init_value; -} -size_t gpspm_flush_request__get_packed_size - (const GPSPMFlushRequest *message) -{ - assert(message->base.descriptor == &gpspm_flush_request__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gpspm_flush_request__pack - (const GPSPMFlushRequest *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gpspm_flush_request__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gpspm_flush_request__pack_to_buffer - (const GPSPMFlushRequest *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gpspm_flush_request__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GPSPMFlushRequest * - gpspm_flush_request__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GPSPMFlushRequest *) - protobuf_c_message_unpack (&gpspm_flush_request__descriptor, - allocator, len, data); -} -void gpspm_flush_request__free_unpacked - (GPSPMFlushRequest *message, - ProtobufCAllocator *allocator) -{ - if(!message) - return; - assert(message->base.descriptor == &gpspm_flush_request__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -void gpspm_flush_response__init - (GPSPMFlushResponse *message) -{ - static const GPSPMFlushResponse init_value = GPSPM_FLUSH_RESPONSE__INIT; - *message = init_value; -} -size_t gpspm_flush_response__get_packed_size - (const GPSPMFlushResponse *message) -{ - assert(message->base.descriptor == &gpspm_flush_response__descriptor); - return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); -} -size_t gpspm_flush_response__pack - (const GPSPMFlushResponse *message, - uint8_t *out) -{ - assert(message->base.descriptor == &gpspm_flush_response__descriptor); - return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); -} -size_t gpspm_flush_response__pack_to_buffer - (const GPSPMFlushResponse *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &gpspm_flush_response__descriptor); - return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); -} -GPSPMFlushResponse * - gpspm_flush_response__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (GPSPMFlushResponse *) - protobuf_c_message_unpack (&gpspm_flush_response__descriptor, - allocator, len, data); -} -void gpspm_flush_response__free_unpacked - (GPSPMFlushResponse *message, - ProtobufCAllocator *allocator) -{ - if(!message) - return; - assert(message->base.descriptor == &gpspm_flush_response__descriptor); - protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); -} -static const ProtobufCFieldDescriptor gpspm_flush_request__field_descriptors[3] = -{ - { - "offset", - 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED64, - 0, /* quantifier_offset */ - offsetof(GPSPMFlushRequest, offset), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "length", - 2, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED64, - 0, /* quantifier_offset */ - offsetof(GPSPMFlushRequest, length), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, - { - "op_context", - 3, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED64, - 0, /* quantifier_offset */ - offsetof(GPSPMFlushRequest, op_context), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gpspm_flush_request__field_indices_by_name[] = { - 1, /* field[1] = length */ - 0, /* field[0] = offset */ - 2, /* field[2] = op_context */ -}; -static const ProtobufCIntRange gpspm_flush_request__number_ranges[1 + 1] = -{ - { 1, 0 }, - { 0, 3 } -}; -const ProtobufCMessageDescriptor gpspm_flush_request__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GPSPM_flush_request", - "GPSPMFlushRequest", - "GPSPMFlushRequest", - "", - sizeof(GPSPMFlushRequest), - 3, - gpspm_flush_request__field_descriptors, - gpspm_flush_request__field_indices_by_name, - 1, gpspm_flush_request__number_ranges, - (ProtobufCMessageInit) gpspm_flush_request__init, - NULL,NULL,NULL /* reserved[123] */ -}; -static const ProtobufCFieldDescriptor gpspm_flush_response__field_descriptors[1] = -{ - { - "op_context", - 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_FIXED64, - 0, /* quantifier_offset */ - offsetof(GPSPMFlushResponse, op_context), - NULL, - NULL, - 0, /* flags */ - 0,NULL,NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned gpspm_flush_response__field_indices_by_name[] = { - 0, /* field[0] = op_context */ -}; -static const ProtobufCIntRange gpspm_flush_response__number_ranges[1 + 1] = -{ - { 1, 0 }, - { 0, 1 } -}; -const ProtobufCMessageDescriptor gpspm_flush_response__descriptor = -{ - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "GPSPM_flush_response", - "GPSPMFlushResponse", - "GPSPMFlushResponse", - "", - sizeof(GPSPMFlushResponse), - 1, - gpspm_flush_response__field_descriptors, - gpspm_flush_response__field_indices_by_name, - 1, gpspm_flush_response__number_ranges, - (ProtobufCMessageInit) gpspm_flush_response__init, - NULL,NULL,NULL /* reserved[123] */ -}; diff --git a/engines/librpma_gpspm_flush.pb-c.h b/engines/librpma_gpspm_flush.pb-c.h deleted file mode 100644 index ad475a955f..0000000000 --- a/engines/librpma_gpspm_flush.pb-c.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2020, Intel Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License, - * version 2 as published by the Free Software Foundation.. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/* Generated by the protocol buffer compiler. DO NOT EDIT! */ -/* Generated from: librpma_gpspm_flush.proto */ - -#ifndef PROTOBUF_C_GPSPM_5fflush_2eproto__INCLUDED -#define PROTOBUF_C_GPSPM_5fflush_2eproto__INCLUDED - -#include - -PROTOBUF_C__BEGIN_DECLS - -#if PROTOBUF_C_VERSION_NUMBER < 1000000 -# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. -#elif 1003003 < PROTOBUF_C_MIN_COMPILER_VERSION -# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. -#endif - - -typedef struct _GPSPMFlushRequest GPSPMFlushRequest; -typedef struct _GPSPMFlushResponse GPSPMFlushResponse; - - -/* --- enums --- */ - - -/* --- messages --- */ - -struct _GPSPMFlushRequest -{ - ProtobufCMessage base; - uint64_t offset; - uint64_t length; - uint64_t op_context; -}; -#define GPSPM_FLUSH_REQUEST__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gpspm_flush_request__descriptor) \ - , 0, 0, 0 } - - -struct _GPSPMFlushResponse -{ - ProtobufCMessage base; - uint64_t op_context; -}; -#define GPSPM_FLUSH_RESPONSE__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&gpspm_flush_response__descriptor) \ - , 0 } - - -/* GPSPMFlushRequest methods */ -void gpspm_flush_request__init - (GPSPMFlushRequest *message); -size_t gpspm_flush_request__get_packed_size - (const GPSPMFlushRequest *message); -size_t gpspm_flush_request__pack - (const GPSPMFlushRequest *message, - uint8_t *out); -size_t gpspm_flush_request__pack_to_buffer - (const GPSPMFlushRequest *message, - ProtobufCBuffer *buffer); -GPSPMFlushRequest * - gpspm_flush_request__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gpspm_flush_request__free_unpacked - (GPSPMFlushRequest *message, - ProtobufCAllocator *allocator); -/* GPSPMFlushResponse methods */ -void gpspm_flush_response__init - (GPSPMFlushResponse *message); -size_t gpspm_flush_response__get_packed_size - (const GPSPMFlushResponse *message); -size_t gpspm_flush_response__pack - (const GPSPMFlushResponse *message, - uint8_t *out); -size_t gpspm_flush_response__pack_to_buffer - (const GPSPMFlushResponse *message, - ProtobufCBuffer *buffer); -GPSPMFlushResponse * - gpspm_flush_response__unpack - (ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); -void gpspm_flush_response__free_unpacked - (GPSPMFlushResponse *message, - ProtobufCAllocator *allocator); -/* --- per-message closures --- */ - -typedef void (*GPSPMFlushRequest_Closure) - (const GPSPMFlushRequest *message, - void *closure_data); -typedef void (*GPSPMFlushResponse_Closure) - (const GPSPMFlushResponse *message, - void *closure_data); - -/* --- services --- */ - - -/* --- descriptors --- */ - -extern const ProtobufCMessageDescriptor gpspm_flush_request__descriptor; -extern const ProtobufCMessageDescriptor gpspm_flush_response__descriptor; - -PROTOBUF_C__END_DECLS - - -#endif /* PROTOBUF_C_GPSPM_5fflush_2eproto__INCLUDED */ diff --git a/engines/librpma_gpspm_flush.proto b/engines/librpma_gpspm_flush.proto deleted file mode 100644 index 91765a7fb3..0000000000 --- a/engines/librpma_gpspm_flush.proto +++ /dev/null @@ -1,15 +0,0 @@ -syntax = "proto2"; - -message GPSPM_flush_request { - /* an offset of a region to be flushed within its memory registration */ - required fixed64 offset = 1; - /* a length of a region to be flushed */ - required fixed64 length = 2; - /* a user-defined operation context */ - required fixed64 op_context = 3; -} - -message GPSPM_flush_response { - /* the operation context of a completed request */ - required fixed64 op_context = 1; -} diff --git a/examples/librpma_apm-client.fio b/examples/librpma_apm-client.fio deleted file mode 100644 index 82a5d20cb5..0000000000 --- a/examples/librpma_apm-client.fio +++ /dev/null @@ -1,24 +0,0 @@ -# Example of the librpma_apm_client job - -[global] -ioengine=librpma_apm_client -create_serialize=0 # (required) forces specific initiation sequence -serverip=[serverip] #IP address the server is listening on -port=7204 # port(s) the server will listen on, will be used -thread - -# The client will get a remote memory region description after establishing -# a connection. - -[client] -numjobs=1 # number of parallel connections -group_reporting=1 -sync=1 # 1 is the best for latency measurements, 0 for bandwidth -iodepth=2 # total number of ious -iodepth_batch_submit=1 # number of ious to be submitted at once -rw=write # read/write/randread/randwrite/readwrite/rw -rwmixread=70 # % of a mixed workload that should be reads -blocksize=4KiB -ramp_time=15s # gives some time to stabilize the workload -time_based -runtime=60s # run the workload for the specified period of time diff --git a/examples/librpma_apm-client.png b/examples/librpma_apm-client.png deleted file mode 100644 index 2fe02cdfdc68feb471b0b15259fe321f921ea83d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53792 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 will be used -thread - -# The server side spawns one thread for each expected connection from -# the client-side, opens and registers the range dedicated for this thread -# (a workspace) from the provided memory. -# Each of the server threads accepts a connection on the dedicated port -# (different for each and every working thread) and waits for it to end up, -# and closes itself. - -[server] -# set to 1 (true) ONLY when Direct Write to PMem from the remote host is possible -# (https://pmem.io/rpma/documentation/basic-direct-write-to-pmem.html) -direct_write_to_pmem=0 - -numjobs=1 # number of expected incoming connections -size=100MiB # size of workspace for a single connection -filename=malloc # device dax or an existing fsdax file or "malloc" for allocation from DRAM -# filename=/dev/dax1.0 diff --git a/examples/librpma_apm-server.png b/examples/librpma_apm-server.png deleted file mode 100644 index f78ae02e876cdce23710e21438a52d9bd68dcd01..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42611 zcmcG$bx@UW^gViLq(eZEM!G?|q(izv=`QJ#R6t6)lWpWOob$Zz6ML_{*4hLs%1fdm5gR%)vPc-UOlKX>~8N>mvX#VGamHuD9MgA8J zLN;OYWwF6|r40%a85MPUevVxZo5A#&fZ*%u-++OEfrbWN$j#k;neAdjTtWf@q(6aK zuhKZU97YWB5($hv;j^*5jevjvAp;Uo>!wM8s)YiK_dSqne%w)5IoyYs@=coJQhX+puh2gO=o9$jF4{|;sR0M*4nL#Kqa6e&Oi^pY4jw0*zW4-q2}TFQ&=dYqq8_O^U%$@H&PGk55pvt@PnCdgIa|;9nBXQcSOx!{l5+E39DPMah3#@n zTy!)6x82Ia?fKx~;QYfChR7on0@;KfA)m|78;_FobW*9lx<-mvu*B<=Q%hyEClem9FU?lxgP6=widsB{hFMd9QKwN z);gmRVJtCAGNSg)((}``P~{N#U=VCnlE1%yM1(@AcDh3JPjyxa*6d_VV=nflea-n(g<%!GZOW<$D4-FiCl7-bjduh)76uOiZ}taBQ|& zqvjG45@4?idfu=Eh>%qgf&~>4YK23_#h^ri&nhnd*|8cM8w=}&@#f9V^|DU{u|Q(J zk)a{Elnc2&@}fZG6b(H+HizrsoHN*<9}}3|zkb!$(&FLa!NhrbI9I4FAmVdb_~U4H ze|0Fe@_03GE4I0|X6S(59g4@?kd1dFOi4|R00$SPW4+Y$ zI~m&9**O(HCv5>c{>RWC*Ql-q|;?EiyJ*#$X?CgD(B`GW5Gi3XnJw2`~ zNfs3WN5sAUudpTTwW`fA?Th{WVWT#3a&qhu`V1?$3FTE(Vt)L99~~M>;p=N=Vqy|o zZE`

=|a4q*h3M_Ydr&V5~FkhagOfhQfp`F>&$WM6;n}GGtT~lpqmuC>u*lWfc_) z8C+&vS@loNUpbU$sHvxCW_nvG{1x>Atv+Dh$to30R2cPO&7Yl}sjI6S7#Kh>h=>MN zN@~QzpleCV$qlWnK3db$(qg`)koc+3@&@uD6%E#x%XSIl?da&Jx3_n2aPa2lCMqf_ z*c`?w0|Tq1_!)S3_`SV7umfNa&b2387-BXyHiBS_Iv9IEJxX>XD*$LsRM~M%G?zMmRN&W9A|GPsqH8mVu z+`_^_ERtZ!02trgT+@h}k}V>FFT8 zT8?E)clPkP9{oy6ieY^7_H9pB7l#nnY$g;8{7(W7B#6w%kHOB#uaN?pG@4_Y-*a-p z`;hAMzoVt4rKYAfyq~Es>fF4Ej>cNk(txm7PS6}(q9A5?zZ&)>zxW*;AMgEeQ&C!4 z8XG$S&TWv0hlfY|^sRGCz}CgZ1qwJmj*;wUL)Dd)h83C{fBL>yX7IuP?db}|1A(W@ zn60L!25fr0R&TJ#D3Gi>6xe+r_keSeo10sv*IJsN4}pM>o?UtRD+>Jp znfFe1boavJ`e=7=4;%zLZbGC0HnSl@A0Hp6vJ)3+9U+2QH5yJ8P|20Gu(pv_DHC|D9+2nBO+?{ymff>Di|bM z5Sk?;;4`JcrqCWnxT{ejO)s(cv!rZ*KuaB071_K9Ya&nT= z)^x4gv`R%;8EhOAW8?Sl-@B!{4V#5ay?XUZ>^m~V#l>aeTH84{p}V_#WJJ->VJ?gl>qJT=_Tk&c+r66jf_xgT#enVB__%O%Y{3?F3av@07fKVfcKo~ zCJ>$S>OiS?C>Q;$I{TN;mn-cxyu7GvY}RyCnTVHKYHAaIMYKh}n@b^{x5EVIQvD0T z*`!yG4GuN>eu{5#+_=ID9#(HJr;a z%H1r<&Fq|{T3es>9ZkxEAVqWwTj-EHA`Fp5CI(s0DTcvlthvp8cLcO@mV2@M*62uc z?TSo(7MA&`TGLC*$;bQ6)Ax9mm{ee69XVeXRwpGT`iWj%?z>M-)%-;Rkn->~&TQ+0 z^2L6cc%DMP_kD?_4WsxBW`-^TSP(_7v+IO~7M=wErgte&E4a47a-gWBw1$--iD?02&d7e7LJ8qJOcKne0GQk@-8Qj`BYd^3zD> z{QU+aeiKCLFX#xyP7=6ZJX#Fl;BcdbZ4P{9BlT}s+MoVOuaVt)Un-`IrQuEHztVUt zv(%iG%1=vu@Ile`+sjw&A1*Ts+37$2#6R{YLKMl@P*l|SIhUL5i>bVMVi#*mgYj3y zqi1;Sej&Bi&)k37P2rDWF`9`)7w34M8(R(|+zkCPk4(64XvmnB-h1=6K*5n+MEQ%2 z`@d3iqsJl#H4Mg{AtvTpN8t3x?#+aP{|NQLVNq6A*WUi=8sguVV>}rh{RRep;uRm# zyZo`SvBgGL07pju{xxj#g~Fzi)vPid413E3Qg<&es7?T|NaC=H2d@eW3YwcA0l<%m ziTN|H)#y@^@p7#ua#)3ggz)q87lZVTib^e)C>HyC*3Zm1b$xQO!gP7Glz%ZoQoWDD$+UL5_)v!oF(}soC4~@B!K7sIBvIngNdP%TeGNYYVrh?*PlOsI$u)W@xmW$$iu@! z%l#1_K^Qy)4FB!hH{*bz>+g54YLgNW8YWy;_98qN2C3c?6tF0vlT*sSWt*OsxZb^c zhcTO%nyRa)s0h%7qT)y}HZ`c!x{cYO(hCYK1`|2Nbj^*7908V}nVBK+dBB7a5D;*F zSUP634SdMTazN?jXKQIvx z3~cO}U%#X#Zb2pj==qmyZfIyfm=CD*($b?epQlv|6?yrikql8#+^W*yK;EEq0~i{t z)6&w?3Ge>e{;ul0IbHDE&0t&ma~k=7wR9T0mzNhkeG$m0xUXL`=(P|+I=i~$WM#V} zNRHRm{u;A^WYqi5s3+WJNkmy0OQFvf3Z}OyzT9s0FMz)e+{uCHB=HFe32|{CJxA|Y zb^pYNj8HZM#E9__K_P`%DAK7Iy;4xB{>z@>R& zG9lN(5!%|?Aj3gMMn+bSj}=mfk~wX(&;Jn}!GQ$5f)C>KU9q&Zbcq(&tBD*CMRj#t zLc%71ARveUKi*%JfZe0T{_dTaj!v^tGlOo^4XDT=E9>hj+S)R>SZ{SEkwJOX#-5Hy zc5w?ZljHW#3#I_8CN2&a(`U@`W@D+lTY{dR9zeadb%3uyO=oFk)&K7w78ce}nouiv z>X{i$VO|1u)1Qfn1dyh$mxV92Hv=Q%OP$mFe;Z-VjvKHIZUAwf>x74gBOxI{UP@#< zyacdM@tAc7QU#Lov_bhqN;GO-4LA%EUZ)_2mm=$rT#j;MHXf*dUg8IsLsd03TTu93 zA1&r7q-||(0ygC%s9g8=6;k=#`=TkuhyY>G=z9G0c)bj^y@iDZKoej)d0FfU4v1X^k#rP+dN47<*a0bs#HZi2MzRF!&En{6D1O6XA>IMNnS` zhpl!5^6~Jz;)pL*0*h?BEND1CIjIK7ko?t`FU-#~fS#KN)i%~!tLf51u2(cX`J-8q zMj$?dY5ekk(98dU9tkV=5uKf#Cnt8ep_FuVy!vgvtVZ2IAt7fIw9L%c*Vn`S{o|99 zDS}?Skm_2(7#}Mzi?{0$LP3YNEw>WF!m9wImgzQwlm8a%iriePXL-y$-^|Q8dJVQf zR24!_S*4i@&&+A~Za-@I)CestHE(YoG&DMOb%(#enk(~k_ zV)z%U-+>c|il97SNO76%9o_ctDm*=tadPF_w{h1kL;Z=Mkjzg~RY}*}gq4#m_L37X zAx*H$+aO-@aC2kaW>!?3f--7*I87l(85s%5bl}(N$*O3kwz~QhD3XE?R6c&}Ut9!* z-b?f)vI?6Y%lQaG-E^r=QE4d}1XPGc>LrCGC6s)Wl?p^eDK%EpXaw)`-SZG%iHM6g zxl*||bFw_$na?0*JV6cnUb(kEoPGTAg$eTO*Do0$ID(Lu z0tC<-Fc1L$!2u{ND1d6)n=E>MI3Gr;c=S@zF#0F}$+!S7T#Ad6u~_n3GmP0#1>9pElU)VPr%^Qch69 z_QIur?9(Y>ZEfxC-O|wT6;yyqY!+kh$nRkxTwGkKu&QlS_2^oE94G@spdb_!6qVqv zT>%_lNWq$=hA`+fyvA0XfMR5-@w_f2d*>e)qXKppn_c?PFx2B)e$FIpV%_BA&!aOl z*?H7Fma!rEG+{Gc&3mW2<6IRLCYhP42naYjI?|~U;1qxVjZ-2^`AoE5 z08TXU-*RJutyPh+O-b9Lyn(@Bjg?k>yhD~mfm87&xCglBLQG3M*$?+k|4}rU|6POh z7_=0BkYWY|p+2ao)fko7Cq&i}vc5s7EH5Z{1?iPnQ&sKN0Tq=E8dAnqB6AH2V()zA zW>=#ts&PuY-)00cQEoAVgy+v-TAfBtHmGk_?v#+(2$GFHcbBQ>hisjLJ4b6C*-}LdtZ$R85lId zV;FfE_JDTGdPR;P7<=WNopr>-QDI?($jCfaR=59T zT=eyyLh*8nG=!R6Y+eUIySq>J#|NmXzSq?L_euL7>zj$2o3o&xH5~fCB>cZfX>XtE z(&}6-O-!Og0nu?`OlTT2(NG%>lnKHh%5 zHFHQ>J+)PDn{j(MmBdOKWQI{weT~BpWy5#?csVmOMoP*GfB&r|Ni|mGt*pLe7(xdRzyToGJ?u>!F4X zcA8J+)Gl)&#B^cJZ2dR@({_NioEvZIhmR5o-CY*<_C{A2sX?s_{8r^ms&Xlrty^x)o9)5qEsYH(%dV zOUpG#o2es}g7+I-b!)34r@dH4KVdju%8wV+@+c3-ts>+xF|pbAH$S7JGbP320PQup z`<|Nma$%wH`H9||9SY}U<_Iw;ZxV%;Y0TPiN=ndd*)= zEG>C$=HBDu|88n(0@TRatOqOHiriX$%%v@RgJ(-xHX0{D9i{?aIT`U8qJiU)vlMLWj>P zLd#J6OCl>aeu_jOabVRhXaX>{n1H1F2U&U!<+F{rqf6k1AJr^wAx61ZmF<1WLM@=op*;FpuUA4F@Fs? zIql0-rmZrwa;-G+Z+HcwPxm;;*MeUEbUEe z_(InnvH7Qvo=M)SqC9i$5x?E2M;RLW3{1%3VVs&;7d{GIfCxYXexIZJ1ATj3BxgL` z+z+Z*ERbl&uK(xh>+? z*Nq7nmUtExUxkI`Y#5XH5C(@zp&|JAyb!66p%c?wC7PomA`%Py?+^j~Yhb{bG`Kn> z?C4m;i}O{|X#X2WIuB18N?6CYrY1`Z3wT#D1>U7nqxt>OED=`Lxn_^`*RRF;OovlG zTGg&Jt^YSQiUqMej!s(xqZXEH#-{4=aB6z`c(E~I zhLfFrd~_7Ei9=kxYwH{9o1eH@aWOFze3XcSH2&J`PWj){^oH8~%4)4ENM-)@?<*ur zk-0$mmXw@L7X9Ys#R6w%0fCCLneqr0s}ro;)6*ZH$2bw)fZ^e?tJA(c;}fFL5`-z= zrG~iuEmJAoXhBD+n(XW^2bvsDlFm;vQ;IaNF)@*@OE!DLDO~*ODV0Ph zK?+KFyOLv$vS{UAi)^LUv6jtmeI00#pi)HOiL)z$AI>7(X>Xhc{pPKY(b zXPXkPM;obvDR&RN5!q_can5e0%*eQzoxRi5 zu_g>1lf0t~ zS|YcSj6iZxG_bl9@A)CXT_1Thamc8s7!IelZ@8Fwvvh~4s3>E3+yMTdzO2=?1%ymOs`Rud zW>69NJm2d9IttY9CMG%GzyAdcP)SKil29vlhHn0CV}DBWgpExc04RU{OrpR~{uLSO z-iqOBM|nf)czsmAvl9(~SRz4fVPSo6aP{xm`zkqJ-sqzvQ$GYB2Sg=q^O2sscIMCd zT$Zsiii!p%CKRVs*(5%muRhn|pTbhPkDM8Jyf+OCiqWJM$h+Ur0iA7+KHBXf()|P9C4vi826B-{*d&<|==C+4FIye;mlEoAd=)+i7|c;zHv4Yo$$Y_t=T&&0Q0~>NJ!GYgaQ&-r(y4yIkc+~ER{<8$Vgj%D2F>+ zE3cQ7rzao=8E%)W!92L1f2X9}U0sbi2}c!?LhK)8w4Ub-HR*5I|L5$wlVx!2{CIE; zLoO{Nj;tG<56=!*6;K!6F%X0^2% zdU_6f6E000Sw$B^`51cv|0xLG3=GC30(1la?rzFc0RmMoVOw=X+=H@Rns9foIZ^%i z7sPrI>C3NXs)&~&{}B;FU}dUIcg4ixUcXlTD9ze(Ba(5u*D#!{7>`az7t+v}R09TU zJwzyUm7Gb5K*|_~1%xo!1iYLa)pZzcP+)ktf1^j85P3*obhIWlA2?KeBsd~zuPo=) z{c=|yeH4>Wk8V!U*}O5bIMhCT(~=NVnjd(@Z5PRBmuUu|nlw`#k4 zZLW@Vbj5Z34F``X{BqxlMbV)#csie**q?ICVJt+|ye6xX&D?FzdDUB+1ChmD+^;sq zW6=Ex-G1Gjv`##S`xF0m`l>8rA5y+9g6Is}^6C|tzxHM6(IWU5#iaxiUnJ)a{f^#e zCnZq{QJTQ(pJ7jLL+L_)Sfc5eR{fO7(D`b=Yu{}Y@rk%@@rw$r8yj4PApDC^w0HjQ z4OT~W;H&);VvHCP>=e8b#v-pT?L4fQtdKWW?_H*5wO$qbQ~y>txI73TA{EK^Vu7*= z1oAC0@WB9T7WfywPYBtsbprd1dKm+z_Es%HFs$dgr{mHVkaCH5Qg*k-2h|4t(4ScRsWHe+ z$hJkF5%d^2n8mG{C)9A{4{X$NEV9YB(Y1N5e%u?|OCj{`;qUW=hMY5OV**NKgr@o# z^>#VlS8>D#0{pyEukl~DhDHLT@RTgz4R4hO<8$@m93IKqO` z!ZQ)%DEVK$wH*NMg2)cX{}_B1cYEGGr#&*BmhZto=)HH_h7HM0lq0fX(Uy>ap{=gr?6_Tk|NyXU}F z-VP3v_itxVod~>c@%j<+Q55y*R43H<2fu#3-83mvEb~&i8e~Z$qok|ZZ!i55?`ZaG znAF3fN=q<{RKB1A#kpd#1}7uLINoGQre00y(`aeD`;XZsJn-P>MOUfYi=7taLR&3^ zi?_!^k1E$iG6gPfH^UC8rwSi%C|}NJ z^9)0M5S8%bZq297>T4DoyZ_DgYv@+k5hQsm1G)vT}4|3ZSyqdm_w0 zvc$(P(QDP!(7=OyS*TzAPp+^uGO7Z?MrF#D)d#?X#?fm)Lqlsa#5XlP0IUZL9e}cS z`|AxHJENh%5RsIWl#)X9C$wXA0jL1Lp#nrRK-j~;quc;V4rl?5oBR8eA)y9+Sdp>* z$ao(fI$8m0U)h4EqqDnW2&%p?k}fT@HuuevB;&wQRc)KZsm~>LIsSow-ZqS0pZnys zdN>dG9BIC|IJ*aKW0P-Dn8kYN4GjVLzx57q(9phJfFF9p zhx_?+`s_ppQ0P3AG!VGBRuaFi*sUxH)VpJ!oqdo&f=BUXZuNf>xJ<#;z@VlhZ!qq~ zIuap>>&|BDi;$<1U$D@U6-EgY;k&rOfPg@RW(P@+T0|r%oyXO{Wp1jE+&<%lMB*ES z&RNGt#C2$VIaw}0nrf){VKf*!c!6_K@VYQIU$s$t3*Xd{=&eTRAwzTJ#oKw?T-09@ zxGvT=dgflErKRpcp+PW^>rCjgELhP@P-FP}XM!c|Ec^!?skZaAB|xO2X#(=kWRb@9 zP|8P7Sy@>WG_)_~Hyh8LVg^P=6s~+gW)pfi5%uyCfWX4Seg>=o&~#cKuaXiH@RSap z9`Dgf1W|yoMewW`3RL?b@*$z3QhNOPdb#(aDZY7=UtBDUyVU4v3q}xQhS+Tl{04GO zu~yZOn|jaNGvM{H3v2*hEl}_7?(e&vHSRUX#_C^LYyQE?&S{^23rTMw-Wm$nF?YMj z-#ow;EG}&FdRuGbhpvK-$J91ibYiea#)|pfZ*{!DNAJd9Z@F%LA6e)D(wPkl+g4+B z^1$O!RCWM8Yj)jhSFb#z1&*wTVPk8AyH`5Tr?yDbz# z9%zzW;&|pjg*@V`gKrvT=_CqX+Y=T0#+}A)L*GsnW7OB5GFPfe1oDa6JGD3O;R8f&pN_5{uxmJzHjP4NW1;9^zO*(RzTHmxocwuOlgqhn z0u}9T5dAK6?Ew407B43gan588lg8)IB|3d?lMspCdQ(sPVnqb~W9TQ$=Z$0-pcy1} zCG)?F7mWAC;}?i0WI-cYjOb>X;~CF+-D*`CIY{U<2z} z=)<(HH>(K01m2ns!4jZ`6Zy4$_{D>*+x)%clfjLh+c`YH02x2w(ZaX*T;kd<0V9fv z%HIc*+6PeB*bSb&gF^k(ion7e^q|=}d=EetmPLVvUfGb=tV5%cg)-A{9=juL|G3n^n=&!B>@Hg_}8iSQZQ+^8z5iSr`8O)6i0I44Vf@_KEi3UvM z@?LCEI+ezK1uA(#hZf_x&EAi^+}!o~`9b$hS){-h>+*18Z#X|Xssuzea2f>#1s%7V zTBB5eFB^FGfbcMgJpv?OTU%SOSin(bWMq_S_w;ZJLO9SSj4L#OX-sSt?3g}JKv(<* z^;l|ZDp)}vwlb&4Z`*NyjAsC4Ew+-uRIwItC;;F2ckkmJCAU-PmPcGRwv}NagC%~= z#@fTIc!qD_Adcs@?@wb8qKJ!+3>5^L^sjVG_+?S#7qp*mudKs>!!$9WKlUyt$eawy z#v0bv76aRFL=hY|79YW1iGK%^+6>zR3jzyNgtoHS&AulRxPARQTUGALJhI!i+7?X- zj<~@T!%P#tU|_*<{;9+|wpQ?w_ff0DqmG_12?U_XI=w|sbv8~lPMcEL-GDN%yjzKmfn)Art)pi-3?28(Yl< zl_KOL_=k~}wxFymEjISOQFo7r4kIHY6e(AND-jL^aD*D_>hg*2gI}~GVPS)zWF9~= zMudf>uoyrq?QCszd!>U6nU`l~ZOs5Ut&fe3jewL)Y}fxuEbtX*c5`!cfJ{3i5Z9w* zLYpr0tKm49g~`peyQ}^n>BW1=VvGojASx~0h^<&!fFLbBG98%x4&<@&YFLQ5#U7ae z5gon3*vmVLioQIKD>wE*VF6&R)8qx}|9s1%?(BvJqxv=SB@3dW!2cvh^@IOb%jrp_ zvaHl^6Td9o1Tx>Y(?4ky2^ERYR9Ww{Dof86zB`r>oo$vglQek)D4S!&I_=&?M_xDS zGKN|iTl;9k+21qUTSZMS-^;#PV_dWMc3-d6eQ{=jTgE5W7YaFl(Ee0uTyfoH@X-0x z${zDn(jubX6>}KsP%|>+GYlOC)%ut1C##V%J)P%&QlnD-bkVBGovU^&6^}paxk$(+ z>Mr`G6Z-mn9O44o^&ya?!Q(agP>;=xje4Q6T_-?XVwQ3QIq?!f+~Q-ffUzP;QY0S3 z<5gv4qXEXul8;Xa>y}=Ryi2J|nvyvY;U5R(}5ab(klf zt0lG*!BBQJ2Y0_}(grr#6U$u_3W=UX~JeV>V`^oExCuXRrY3FQ> zEOht%*S(|(Ja=Y??DnLpZ%iA9MpZI#UNgLTQnQ1XUKhK5R+4L=*M`E7YlBZP@JONikq&;{&SA3e-ZEW@H`ey|A- zjTopL0E1Y*wF*9UcqSu8n^P06oenXe=M0~tX^(V!+;RrP(8yivW9oU#csS`r0CU|q z^|0@m!6y4^1bK0+SxHbnqNv2@<9U* zCK8Q7KJJ(6Wu;mGwgD;W4a$$kMvrOuh5d=?j$|H1C8#RXZ)MC659|Qhn9aY#YFRS` z`+R4w0D*%8;+s!nZV3&hxmOBuv+?rv3ST^Yo(Lfzv9z~C5fVZmGuHKXQ1Of~@Gy6e z6RzL+Ri4_aVTAY|ldnL^&Ds68kCo61r5`z$9vaHD*SmW{NKQ+)ySwwpYvHOox;pU( zff}tE4lRy@$-6L-c>#-S*R0lly8dX~n5md)7++BFmRddBnCAuf;qjt7$$P}8k86rP zZAbc4dDf#i+vD#kYwIMcq;?pya2UVuB|{u@u<(R+ zo&DapH*#lZ2Qe!;Y(WQMkF?PP4JG0Tmt;DLs8?F9Q(~5fmv8 z&n6Jy}Nk_>N~*6XOZFL$K=`37pe$F)!n1_t6Q z8n`mUny#Etf$4I%cL%E~{pttGw;l7FCy$xt`^T4&SK46|)!@K_r1`*q`cz&E59$5) zHBF0`7aH=8x})UN${rFJ5%QkE+zJK)i(mvjM@5w~`_O`|Wv?Y@%bqvBQ&NIW86Jo8 z?ADNYFK8tw0Az5IGgEiKG`1>nEpw3)jA-X<%sug%S4jci;9f*x7NmP4R)agH8C+V9zHHk z-{O^yz-75D2{-Rw+t&8oaeaNr>};E1GxK&!cv-=#jvt`52?`NW#+sP+i<`XP%rh}5 zx4`y%7BIK`{sTTXUc`Y7@}V{D?un_0!K#0evE;C3s#5p3yoGvQ7%^k1K%o?BQ$bDb z@?v+Kjg1ZHG{D%7jfr`Bc}c__c^xaU4P^Ki%6ep^95D63z0+k_P*kJ`Optxi3dFHq zHzx*WX4}An0=$NIcXyz%1b~eQ%{uVt4Hn~IUUCi&4o*%^Ha3ibwgD;!`;H%|I>a{2 z(UA~6FSy)Xl4COswSXdxjAE3nK`Zy!9A8zn)eDQrsBaIRZdWK`Vr|oS4FD%BaGzWw zh>FrM2J}klSA5VRV*2b0a6B3byqTGl{Er#U{IWp%^_8XO>wR@OIfHR303Z*n5zzxT zj1^V=Nqk<4wzO}1KlZjhQuhhbcG3Pt!vK^ZoJ`}9D_LsI?)v(;&1p56fPerW-~8NM zqFV;0E3iO@!A^%UfZhbqkOz9fwzjrV;3-&Hqq+=1PYvca)hBCeI=aHzT9=L9C}U|+ z(GGy0RaI4iVIQ&rI<@YAF({4S-SB>Q9Vi4U!CYj&6BCtbVsWzu0f{s;G&M3p%2esN zZpRH;6TsvHk1CMTJ5v{)=QsH*ytwi7Ifygw~!&0uWy zzkWjeZq?{l1I+b3=jb+E9`Os~Z22Fz4jAdn{~Yiy<3+rflL0d+(jb z_di>j!E@)M(M_nq2M5S0Yboi_37%+~BJ--mOZ1f#CG}o*QC{?pF&4R2Us-$^HQnFV9?{|pXKG+jvdi4F*ddb zc1^S@eG^7@;sQ zSgfXs89&tm?jX0R=`*m^6Hm6Vr-Qr&uC&9(6(N$>NSj4vEq`6xuh}~rSMIAr=0ae| z5RUQ|%JNHCl;1nlIc^tVXkc)iFUY#`xf*IneGQuDsIytG{autug2MAl@mG3Ty3hC} zRba;-Vvk4dgPM&@W6r=5>aw~v%l5VQ(7x+rdv3yIx8?nc>6nn{898ehaX&b9{*`Uq}& zdO?nVdViWX1-(T)JzAbs(lxSGuicr~KG!{mjY)m{MOd?;^PSg{W~1W!v|M0a(esg>_tf1svZ9q_XX)DQS~7Dpiugt z@z_yo+W}Bx!>GdhoBBI&6Os!c4Wi^I=TlBnN_R<{{xgM~a6hs_eohe0YPUgOO>WiC z6@iU-@oy}Dfo9D}piz*Yo}ZlW@A#)de( ze?7UKaLe4+KJ|X$0DXy>j$He*nkV@htP)xCJFk*uZ5?-=wS6qRUxzle;#BvtK`WoK zXfocM+K5?sRQ;=jv}x|fBxwDjOM?EO?v9&gD#Qi4GwVVA2i|(n?b!tO`hShvrlR9fj2m7sj1^q0CIR?kmmN9*&ILrG&N0pVX5iau$EK?k235 zWg1sn3{ZXK_^58)o$ZQt;O}z`%dy~UxRC4g{m9Wf)V#NhpD7x+FGTH`N7Ow24GlTZtj=a$^e-z%I}XrV+MpZ87Zx=NCshw z`-IdeBIFmF>~L@@z6rj;ZyWxBE}2Ekh;iaGwu{U9{r7Z-0}t%~qW_5nhs6)JTOg#! z^T4&B5f-z~a1G%>(D+EGhGn$#wKVg!oEWV6bQ;%Jdqmkq2UQ2KLa{y;exxE$81P8K zOT=$*xRF5%#E!=?%`k0G$vuH(NayUCThBEnU1;Q?81`=V}B9T3`nh znx_=<8T}a)X~{b|3E3a_iEd^nlZ15gcs|LeZe8U#8Tc9Rk!%3Z8Oud0nMPP*Q!Ga> zO<%&aDZS+ejjIUQuCn4v1^~Rt@85-S5PEEG;;gMXBpo;%)+1z67UfWvB`77f>ue*J zFxLweek_9V4a-H<63H4<%~oAfZ6*^$;vTr-oF~c_%Ym%e9DX|b8`6LTiNuQ8Yw^CX z2FfkyEcAN3oCeyX;MWV9t@Ot?FDvgYul_myo}!|#va7}m_2387af*DFPsXLVo4T8g zk&U_O4mdl}nb9r{E(oG%5?f+auc;uAVH*K{KoIbCi+^+3Za<`?Bfpc5crAk*@WI0J zYb&mLn?Y^eEUvQyYJPY!8YKI59?Iw&5nL)9N+{p(Vl;5}9f7wC(Au9GoOS^Pi$)?S zn{`?$BK!zLm5zandj-lTAY*{GYb3sSg^RhiyZG|zav$s`XQJK0qICKLO~FwsnEe_j zV`oETBS2aVdSShPN0Hrp_=e`qyK=0*Q~sFL`P#)8zp?S-@lA`Y<~^C?L;}>Y(x+y2 zXW{Y?0<#18huxpT4!I!u8Kz|PO!wT6r$w0>Yfh(Ex+J!&KVG&Xyz_>W?pEv1zK9Cd zx_8JVIRf9&3)GTC*hK{n1bSoAc{X|QbMS!^G;s)}DiBCS4>+d@AP`*Re_6XKV6JX8 zf8>S*0x#&oc5rl@Z}GYZtpNc^L8ojl2<9%vSz!KJzlls0=G$)xG! zq$DdI;KT0T4C(hNc#cy~;4FW8wzLJ817Ffok!Wrc-^Bnqso%8c*s@%0{G0eA5yVHE z>so<+cX*O7EhD0OK0fl>bc?jhzlYur({G_+%Gx}$=!}&+3;=C(U zde@sdLJg0%$=00skg2;8uh^^n%F@acomCQrr~0!qB){%AX58|T+(u_cwF~pnYVm60 zis$^-x6>_pT$~)dzqxCy%K3TO2d-q6Vw3N@=+cBd<$a*rq!y!qN(|Df2k{YY5v>Ox zAI)b*@B6MdJ2$D`DD2EB-jje|bivHbtf#k(O)ZbehdaRtTDNBA=8k46MC;A)MMXrw zl)m^0OG@N$uYR=ML46XPCmMIzq1!`Z{Si4$mim;sj_`9jemikl7ejM-jcsC6{clNU zW+!Dr0tV%4B$JTY*GJowuMDT!w1z9w9%uKE=gp{&(B zrB|Hw#=X(L*}gkXJIr1!8>LNN4=%!Az9B%UvGahiU)tmCnV0zOd%Ffj3)aTWl#}T% zfuHhO&j%OhA^Y@A6wS>P&A}o_0c$*?=Z@Z}(JP?6s>-B4UcloDben@;JE1+Zn$84z zuiK}lT)^>aW*OeE`F6=z3t!8ZcYF|#@W;bOzd1fXXs1gY4-Z|pm?ndUj-2;{Nn3?h z58(yT+&mf(U!4Dy>9RLT?1jf-#$=4|Xjf`u|D+~Na<wH#L9aCO(INoRm`vV3NCd0?OpI?((1ODek9^_DnzW)&7njsftW_Rw?8nN_$ZJzA$ zoo&2S*E+{(jS;{yV4(y9Wx9FW9r*@B5%Q*x=i*{vJbo`8@MaEc4#4Hm+;rnW?N|oR z**4D(-{;Rxqw3S@-^l>ISvOkA!+!je6unFw7WDmqQdusEbCrJmo%(Dwff$b_FiQFv2c{JbkCr^|6|ZEe6n z21J~`zP?*fSN*5qa`W+ls`A|FofHKiDS;Cew4dSgI^}0&8HIjiq^F~UhJgY6#xL2e zNHWp?i?F{A>*|ZXM$rw@B8@1Bpdww8N(d+t(hbs5(jwi60#eeQN()GbbVwsemwQ9^t?&!*a| zSL40CY)nj2+S=f0vr=5VxygB@>lrIC0m~U^Q-~#^K$8|!@s^L+Mfl8iHO+{9o^5Y! z5uC|L^o{j3b~N7kJ4!J&u{{3A&1ToAr%OgQAr|-haX#zi;ZXf;YYxEB%RZNVcr-Fd zgW+3;r_F5^mH08yGsx3S;afmyKuJ_djcCa+X)2*c=D(y$eg+?g=k~sQ@%-hLgT-Gn z@3TK*&wm`;p@-LZm!l~)|Cpr%M;g~qrEvb?ym&$okIKTyxX>OG3+wt}KU*%1l(wpS z)q@K|=XwA_qHC*Ul= zP0@5^-2k-iaDAf9xL&tj?u&dho9+dW`iXi&s86^-tF%$QSzJ6NR4uBYunk=PD+%LO z4++e2kjJ)*xJ8bG*$Seloy4)!lx4>(_W8831K+Oa%069;pMI3fw8q%$lcdS%a3jvk z#m}Xny8QcBUvsmdfA00$Dv`=)UJYvR>oLywL`~Wk*AgOdghW|$w%(pUmty%2&ok^j z`88hc>Bw!`Ysj#i`sSMr3FfjpmK^cjyRv@CQ(K+~8=R~Gx#q~x*vrk@L)w?bqJ$Qy zudk~Y(PU?<3x5^)87-P}gyBl|0-dYXoBk6iI!(jtFId@JE47lO85e1id zUDmtl0TJ8Qn08fvF`8myUxv9?ZGgkfoaDkR;MeEBl$g)(|ITq@p*1mfsZ4d%Fwo$5 z=(sz(ha}uZA4*9nNHr{!D$K}yh@9>IOKA_1K(<28&)mxBz89+ZJz}?#9bDIbMu2u4 zwzazp1`LLEd%h0*|6Q+Ice=>3PZwEb_mFh2B|qPl<;6+|M`_w23*7SNOc z1t$;#0JIYUE{FZUCQVINyR$^kl;ARB+s1J>LuGhxbh;8bm z&NtMLigq6@Ns5NohSgR@x)?iW9(qn$oHsuUf3B(xcM@)LySqPPz}(avTk3jXM}Wpg z#aSIi*KTc1v@{LB+}oS;gt#&{WSC^2!$v-Ldmv4WM{7*@p@N!bzAAyrfA{h1@2V8s zhxAal^iYr}&BL2C{l%uZv}prqdv^1t1(-T$sQTrN7J^S|&sNVSBrDi{YK4+S?!~w5 zxD`~%ODZp6_tcO~ZS8H9_Lu(1S~5P1x_6I$=5bG0qhVn!%KEI5QEqydiNh6ZXL zp7JkWMAX$|PsM=P4$es*KUO8y8$k3!-ooK}gM#O;513x%=CmKIPhcWo4i(Su$f~+C z+j1R*&Oo`@950g+7DkvNBO(I*{TrWIT3b85eGC3iRZiPqp*0AHJBXqT4bvkch!12- z+3057VooM!+Wh>{ULRS{MA*^lKfKp*?;xw*qpp$vDCewCGfh0VP$0hKy0;F7QKZS$ zRi|?`d0cO!bY-UlBU@G7mkew zBtEhxZ#KIlZ_Us1f3&7pyG~utJy&gO4%v(^lk!^H-6ahR93%hWGv4#YamxnF<+k1S z%8NtOjn8v;uAAdL;Jly2oK)!e)%^+KQuRk_texjzJT?H*0NKRH+x3^{*4YLkCv6S1 zsbKyB^3Z`y83W3CV=%TdHoi$k6=DfmfB0uGBoS~s0us5OG%fL3bU>|@w1h;1t+jU4OLZIX6A192jI7Lr??lqW%BZvA-5g=M~qZ;Lf`H>SQ%aQVCj4i zJu9oL<`QhPI=AEg&Q2WsyK*QUhCAT;RS(B9=&2nY9j!JDLu3bsv}YGZ1r_DB6$;jS88|; zj|)%SLY&dQQIlKKAKuwVlOLWRXlQ9Bs>B&(nzhEeqYA4z>+8$t+gNTp{n~a?#6lL$ z7O%^Y>A2hM8_h^D<@Z)h4im%GiSAtfyCB=+py%Nqb|-i2t)Qb@U1hbgy`Mh4BDrSI zkK@t4?;84t>u7!Y<~)B>Z|~(=K|Qz@nYRRxLJ{+v60aX0g9ioLK0ZB9>A`+x7W)lY zCn139pMjAarKaBcr=0ZkpH))w@&pL9pIrt&MMtZ);Z&}!njydY`ex+)NFCl&Ub2H& z5D}J#N-JQ04#+(4URF%zKggT3H>2M-RkUaWx z?8{kQ@ty}*DKR`Vb%ZRYpL;8c$PqikA0Bm7W+=ki-%x*R1gu6ud0W7uoq%y$Hv}5>=Iulm7(QwzW#}2@rjj!le6Tr zk9N|h1hIBQ*%;<~_fU|yxVS%wBtq68>D6?WmBm8}@q|D^ZLt0>AlSR<>gsRMKJs{k zv={W4FqtH2QRZ?!^Z41+2iL8#k<2y{94dJS!UY;)7;Ss*hW-o8VtG?H6Z?yThy{!xvi$tSL&P*6OlQ8A5eBU&81ytZH^ZT_eLD>7 z@cim8&=6qXu(0GqCI<&h(48klY$hCWVAs>iZ})DPEf@ho&xh?L})rH(%_xyN4Rddupjeu?5z`#I)peqjqQBhG*Gc)M0&Igb( z71qK>Ab&SDWYhW}Runl4yE=XqDTl6ln+*P1^YB6IfmyhjMwEtQ_@=~lNwvBHnuevN z>c0&&oV(H&9C2UyU#O|Z#55)7CQ-$Z#T>F0bX5C`&Tkwah(ACI9XE6^sr<@fMo#+O ziWIisP?57uET)WytgZwE}kBp`4ZViX`%7QonljL+3AAzR>*eoz(Kszj*ur_Tq$;eGAH@hvX&dF+q6zl4RZ}tBmhDymeQn1@P z%phF0=-3C|9}5_Vz*58e4gE>r>_Ln2&iB5qE_1MuJ3@T{{YYc&RIIf8{G{mUtD+k$ z!Qed}jtWJ*Vq$ooKD_{{C-gF*2ZR69vp<3o24x~ zxNj`u0Rw%9l)iJFLG&oagm}8RVYCTHEUpUnP|>Qv_BI#K0}CgHn&Kv1@uy9`F-=S? z%#$%6g?7^R+jD_di-?SS;w62`wh9%QsF+s$&S41B>JUB zr2`i+4s^$|BKGgSV^P;$N+1nVGr`lhJuipO|8@S0KDfyo`}w`iQ^FWWY!QNaOc3{j zStPtNf{|Vxn-~TRJx51Q!}`JiYmHah%s~+VMXSqTkE0p%`N76T?&V8pbVHb^97@Z0 zJhwZi;fIps^3H6oEZ8=93B&T%-QL6D^7AjJ5f>61iYLP_(lDARhsrLM8f0$etlRKt>^vp-v>fji!Vrb35a4r+P>1v#&HH zG(U~oP#b6|_T0iy6fWunXn8Zw+@BD~uC?WdFa=04%WAzYMbq@mEiT$|*|E1Zvb8mm zwJr<0XmOb6Qxe9A^zmtdURz*5z-T6=XdN5uLEvjI!aqU7zM03_$qDqQAMpdk>l_UR zTR|DI!wgB-!`(ZtoUo`!La5K_>*%Lee3g_miOYYCyX_C0Wj*b6&oq;3A^II~NJ{sH z?ho^%{3>Vcs1?5pPP-SZ(d^uu>&2OK1@@JrY=PE~ozu(cBb>P#7Mc>O6{)pf_fkjMBmRQxN!ZMuTlKPQ0PaWPQeqiP8BTkX zZ&KOB*rGULufLczK3@!*7w>xhp#3cvE*9#OP7X5z%LR-I-n_Z>F`JK(g(Zp81aD38 zF}S80lob{h>Uy3->z{N2DzRGFYV{xj=Bt;fu!n6~s6PPl8O&0Rl2pL*VFlhZ^?C+@ zTjl&8sCrhRt|nvEs(iN)kUsBqhR%Nrn;waUm=GV2*Yl%}8$cfTdQREWz@fs;twQ;| zSFN{IY!lP7Zu)cL>Kz%$U&IG=TjAT^K%M`Yswotrpc|ZcV63@ZJ`P<{v0!p;aF`dR#@+ z0BWp$G5}mVGCJ&K?9r$bQ>P(w0Cr_$mWKL5+yQwmkTkOjra#!Smb6Qxj?oH7KibtWG zPVtvqwH(@!a)YXEs-MKMkofWVrjjP9RVk7eq*>;2S)p|&NZY;g_rGK0pZr0ws|yJ{pc3UQ5k9D^-G`GfiGqI+y4{Z9Z!1Nh7;7tpgC zGh}M$=suN|kAYu{RNAkpX4wNG16Z!-$x0Ty`M`l|4TfH+nVw#%pC4vMPI@10+x(EgKJ?VR5x%faGU6f{twRG9=&5F5z9vGaqOo!(_9!6D1$ zHjx4P+<>i|)OC+|5#}FU#})kbq{F1Mq$Dp$&MD7^ehyWdQr)(K{RmueV5!2n18FFf zyudsL837kJH|3o>TXC2gu6z)PpvK5GP=arO-27+}xa-freAM&sE>6CUoh>P^=Zv~G;B4nMYcZ=k-HS68dN zulK@0D$V#+N`h;`)&H;Rvo(F}rt$B%DK?*m>5rzxv2gT){%D90 zHBN*G#`jB_m%@Z-$9U56DeQ0>c-GYCh2|w>Q0PqcPc_{`5j;H8dT!gCZ0Z^v=XU$1 z%cGgusjXVa{taesoq(v)zKOfvJ+kS)ezLT3EnHvBP1t_1t;Cgucu|Mw{bhUqOyHUS zL;oSFZwxd6`QI(K183>R=v2=udfFkL>V(VN{_t{4j$z*U8|AW z4SyM)O!ky2i(}(oNy#W1a%#NMTz^V7LKcDbhqWjWmlw25NN7rmCnRV3`ZEwXOwG+J zN=sqcc&Mqtqc3Of9+cf`-?j8vfIEnThxgR=fVtcm0L#CB^?)%4EfYXCO3Tap-;{zR z19ERaUtc2spNE^%j`2+nxIwOfy+gKV@!(gH82qNnf)4{DBO?O?)y}(%;SZ%CI)g1B zxN`l_3Zi9aCvcq@A0Ad!R^Ho~!4Cq50=7zs}#aG7H6uL>eONP8QDCsN4WK*l^ACUi1b4^>4 zS(b)SVuN^cJM716u!d^QpE!PN^4ezhagiRjqd-HiwjuY#2yHYYZh z0T+0PfpF?WxC5e{1%rk75zd6x*MSwvr6)}{$QS=k714>BMR0?L_tNrrbb9O z>4_O5Yo4uPTa)ji@7|!VRh}NsVW?f9?ESN+5fliT!KYulFVkT>xOVZOt zwY1ziBN?mm0Ki~0J*OQ((+d^MrSzn6PfA36+mURM6( z8< zZw4<6m5_%UY%b`aDJb;8!*m9Z?mHJt(vp&6a32*FylY1k%qh7!InIEaw>^(fNYK|i z@d7VoLt|rA6_p~7YJh~A9c*;{qO!BI%gXG*>i}{nc+0xarFZhu{-WpsK)|G$2R;@M zwU!UNDO}>c04KhAV!&cLPcf2K_BU)3z5M1`;p;E22}6le?`OWwvTl2otPuD92Ky|= zdtvH`c7b%Zk_So74w-d7bRy;KwhY!{o~8;8wehpRvaypeYwuf5o5-?gd$}6F+9N3B zw~p#%!#Ibkh~?li9~d~#!QYpTdO;A5;`MX(=ituZQ{$A{&-uD1 zUI)rln+@L{AW0xPbaf?we5X#&7?^U zjTaPp+opSC^Z;{0>7|n5OQphR7I)?U@#hq07f;`>pWe7o)zZClv^qe>^Mde&v;Oh> zAJp^Je(sN8Q$ocn1aA7U2ZMs7At+yY7wUB-m2~|2We?u|VGZ=Ja1?4tjShRq5Qf{7*m0^|?C@@4#S!AG3OZ@*?8qD^WR}xv+|!_BpcIUg zE4ZQjQyD7OAksQ=+s~xr?d~Vf=sM|KMpiZ;njdo?H`O#j9@u`pi!&D2El4&iSUpDr zTOOSTtK)1=o>`5?lI~7vqOf$==dKuSVCl^CA?HK$6`D&r9&=g4f2t2R2#YO_nCzPY22nE1)4{;g)JH))78NoPp~CHe!Y-uXmz&1UVH9) z;&rhlPxYHh(ewN`KRbK*F-=4ipz!|0q?{)2zI~u>-x_4|6#7%=?g|7lIDzklNx&0< z7o)gX5%j?#BJb_HWgySf*Z%_eW?|u5coRfKMA|axNpL2}jv@IVBOzhG1zNxt|K>aj zp!zKMtuOq+{m zvA*^;99HGI^FhI(p#&4f&ufh>{6x`~{R=~mvDQ}O>@;BvoH)19*2PwN@%PZd(uQXW^F!7j zM-lC~uUtM&O%$iY{qnzlFE7sp-{3vFjf5LPQq!(ya4{bq@bE-S(;7tdKA2|P!ytiM zhK+y`EJh*dVi$t(=D~DoILd5sfpq1sUhU*pf`?sHDO~gb=h_L($ zFE36Dva@)jPp^w!b?Sew*pUbG2rEH*+q5A|AM6<6_6h3Zz&kH8au1S1XfM2e2#Q-^ z$+u-a_|@AhIlHCou%)`ofdgqL@u zxp@wJq9ZvtGvGrCU8fJ?&|Ju=@Lp zQ#3ncM0m1*t19T~E%JW0(HWheu)CFyot>RD`w`#2k7HmEv$d=Av~BFQsWUfk#f5F6 z&+srW2S*~!!{fs68x&3MZcj6Me*DF)c5yQdQi^ z=@NbO=5Da6bQ%jc*S|*c#y^SK6aOtt;~AVvuz5kQe`i%Vw2pjKZVP}Q0azR=s%d~1 zLC*9oHy0R4x)2hBxPsQLm>k? zb0{~V?in5*hv-4B8_vzj+SAr1uC6{hJ$(sB+`_^FjMw=A1!cvIja78lsEb`KD0sy_1?-%h$g(kMPXDQS!fn6MO-Elb; z)+UY=cbANR1m%m5Kx3XkRguVL`?ZF_T*1nU?Cz2|FHiZ8D&K2f85yV%KcEYuuF1q1 zr&)MOE2FqN>Hk=l+MBvPgbvDY;?p1||qWEMmTFuBU}$ z|2hJ@Sv61n9(+A`Py!RsuEc=<_oWj8(F7a&Hkd&}sR_>PU@-~pG8k;L=B@2sQ}jnm zZyFt=4&6)W;?~lt833l#tUc8haZ@=;JO}|nC<=0UkuW^my0sm*I?we|RTYejxn6(# zS!P}W+%k1y21&^}e#gc5xQ?A&rP9)$pQ%z%5e9}7RjF!wrmJhC%~OA*_{>{Q%-3_0 zuUWgg_5X2g=^sCKQ*w&Q3VVIcW%5`bx6szMA4d$=wht{7h|^sYWFCoTW8hb^~$@J&u6wQJkL1*9K>DjFKj5Y47NPJ>@&IOtLwFW#^~ z1#@g{1X2rtFWRm{`_F5$e`pBZ3$XXP?&{Ahep`@TKpsBl100uHD}sT*(W+VBJ4jR0 z&GFIfy%T0~a#;Umg{hN$F(-X>b&&#!pL_SqtqRB@62Z{vn9vh@e7N<~C;A39G~|=$ zGgtmBfv_&(8@&6!_HAC+D3w*a9rs!KJT1RGFW#+?%9m*2T}xQwA7;p7(mLCm?QE6P zew=J5^dr&fc(p%wTygwd2UEml1^^iVN}e5(uM-N=r(hyK#E7Z6GGr3dZMPQVQ1pKvXKkfiehiC=eZ5 z?1J`F^qS?&GfQN&WGSw~@!gA-w(;>r@Ukq-3A@SCkB*3oyK}@jNk+y!CPJx=M^{Bo?jyC?T>Jce_c6(d;}&pK-AFy_#P%mjeg$W+ne8E2At%I z_49Vd8#r(}%YXk85D*A|v3nYa$LsRniWU_YcXo6<;^l3V0=`$#J<(VQk1()`(lZ8B zz#TjU$?%SF5fk5bbR2-#t)MSZh(&U|5_Vj7#v0vlNyO^}cbhNjf>t z?cBvTa}nKwlcWE=CAB~dwCP!W^02~gMq+qPhB!LDx(8haqYfz}g$1cVw(W3d6up4q zNN2L84Au13#kN;D8v6#6Xe$hSNgFFGIayhLwbsu(aIZ~a?t$SOD8~U?gX-YRzzP6l z5NYyun_*tSIJi}|hdqE1XkeKS$t0{GP?n*eH+R7d5eXVwS9LZcqoT61R)tj(%pnmL z_KJ;F*Y)0fVKJ%0hJ1n-@$?ja@e{BJ1S<=`WTxxf^CG;ibcDbffTe^gN!#9Geo^$p z-``&(F)$RTraIsU(gx!A_+HD(rfF#hZ{xsvad1WQ!MIAks>*MxX^|xL(b2IVK7gI{ zgG!;mkX|ksnWEh#T~g9oHDwa5ik|jCWm;oTb5dQkZ&u6@cn)F^vqzQt=iNvLMps#Dh68-J(x6z>=rY@3~3{ip|UYr zEgs`Hw$~hSjISAmRxZ=o(t5`|bY!OTM=GXNYb{MmbNzE!Zj}kki51{id~sDj=n%2+ zU`CiZv_2XIBf|GXJ$R0tPn*}F^`<^Ms%uY>o&_Do(CBEGDk6P9?22A6jobQa>+|Q& zd7HHSR{*}l`m3yJCue7VV?E02{-R$20a^=`1n*ho7LZo6-rI~ZFO639ukWLJ`TDlP z=$EQ-NIL>$N`HP6ze=3{<$RWk=I2|5KaQ_%8yM5Nu8;qdb==+wkLzZcyh-GbCfEBY zkBxTnPcqWb9;RC*QH;@QRFY`0_OfE+I&>JmI&O5YgK#KMSnsc#g^yrW(I4Hv_<8Ad zKaVqQZQQquQa%?Mrz~uCt+S2Kxf4(s3*h$R2$S~AOw4S?Yr;k)~L7uiEg&Vn^>99Pk^|y;aua_bH-Km2s$#;F_#x9>z6F- z>c3Sa>a|XNdX^2jXk?+C=$Z@=&Pde1RSQIqBJQK*qVm$7HEf75D1|||QTgKs)Tp>{ zhIo<(DQtcC3)C{eltKOic?RTFwRS7vK<5n&{SAG7Up}sMDy_<`lga832Z#7?-|lB* z1jn#uxVX|`V=H9IC{eEd4*e3Q7+rj@_=?e=e9PAB`<~kQYqp14io|LYhGmj3g&E84 z@1F(k;&a}eQm+5;Tkjq(i|x~z;3=_t3aY^x+|P_ZqScE&mue35CL0MaNJ>q5%)W*o zN3F-GUUP56ud7_=2usvW@TA+9eZHIJU#k;c^XJ@&S18IeXIt_4ljn^7Cz)r#p5B+6 zAs$q@95vS90vB#ub zef|E0sdahT zo5BwT=;BN)TOvRbCJrDfZ0-;(E>Az8Qo3xQ(9*A(b??gRa6F$qyCv;AeP4(eojA|1 zc+v0ydRi0;(`M$Rwvd&e-QrGoS7N=kyoCGt2d~<&hlKSfb^eyGM@B zH4{NN0v8vD2M6tT<|X&G&)at4F5!;B;Go)eNfw|oe^Cw|9tTIq6ey46+kEyyxXp1_ zS6^-X>FD{DPZx&O+RCx9k!id5#?F&wr}@YJiK?;6qTTw6-{PGne)8h@9DZUcsz;*< zE#2RwStpjqHz`Rk74>X5PV!EV3B0fkNG?sT`p6e1OfpN@bdVXD z5sH-#ZkUJ{lsxaTk@Y=?zeheUK|~b~4qSpmx-pSF?dw}IDBpzPiG_ZK3JetBz+{EN zKHGBZkW+v`Y?aL%##%p1JN_J|r0@$-(W~^}Fee7%RsCMm9bZvVr-O~MKh-1evahYQ zzFqTqLgUmffNX6vSM#`NW?^Tu7qDyk)2FSfBv&4vj94K^j}Jf$@{+i zN`&>%62E)~dzrabQ)2Wi z%rImye0BR8b5r*|(Nh_egQ9f<6$4VX1u4cn+VACk?;afNChYLS;gIpI2uF%w;p4)q zmHel>?xRl?uX#PLclw`ez4qi9@~QiCV*a6#^b~-L2>VMb<*RMN17yrPmwm%dl#n~qnht*?XBtd!}212eGUBzo#}WXv!@7G z8TYzd}bUpT#h%jaa`Eb@;qOE9Yt8lCzx6-1YcdBM*PZRH#Oa_7$t z(TwP6UTP`aDSsm4I*vW=|GQiM(0}8oTV_*p3bP&?HrG01y2$c1J`GzADxXaN%Hv!( z^SQy*rH=l>tX~Dk-KC4vkc};ufks)u>yYGdzvi%^)ql7mxkuK%ei)xj;hJ02MCv% z;nU^_sq)5 z_?$FQm>Om+7qZlQpE+STFvtS_hVuH`8yEW(6^w|Y`OfgjVv-uSjrJek=d{fe%yeUF ztt?EHNtJ3#kHU+yIbwdjd+N3j8-?eKC#{#MmYJoN*%jD+%CbW|cUt_nrJP}+G^5n~ z>2P{vX1ZD?kdXM@t3Qn97U^7}kTjg_bs0h;9fxnb+#@t@r`R#u0VzQ|QM{I{NbmVos75bC2h81U)(qLoJd=@f?RwMF=j0O~!u`Vj#hJ1P z?063x&oA=3~3RtJKXJ?(Ve-2^34Zc+kZ#H8!Tbckj^~g?k@zOt6=s@dHJbYw0(Rog_X` z`T*6Iyu4;1P-(s4ZS@XS;+24RZ$mVl^zWN`5J%D(}A0)J7| z_rh5N0FGx#$L&B%KGN$V8#>7_jR0sZFcx;*NpYUv{@>^$FBxRcmyaOblX9qkcCBt0 zf7M_@+>OgcoHFZDl)%vIXX^#=&6};`*Fv9t0aGT09A)Tc0ptjCSO2iJYkYed`egjmURKD^cGMit%Wk5g1ZuKnF0e!!W$V z@E>TSKlcDBgibnE59SuorX{~`MtAAQ^2WV>Mso34TY?bnwlw5J2;Ta7K9rLYv`K8_ zH~u#lKqj7DADqMIT7Ld6@N6c$VtxR?eH%9{EDT{Px1<2i%6|DaZ`?;$=L;b79Jeei zEm64U7nqO}=Xjp^>JPME#Q_nAKNzI{>!(FRMY!{be*;V<89@t!Vr?}pfprJt6+3%+ z?*7jHpYQgtXy!vQjKYJ*Ljk zN@x7-O%>Frgd7h>@g(VGA4~GbDMmNxvF{n}Ycp$s*K;*rS({+UU*1M!tMi;x$fy4D zJ8)Lh+kE%wjy}5!uh^XcS=!@xAqKYN6^|Eg2jVv+KFkybAsFZ}@~m8%>!e_UB>P|KcGj_+b=K5k8t!zNI*@WQao2cLE!>3x^VWk2g7NYg zXlRLi_KX4oS}^O9?Mh<QnM zUJLpQSDo$bK#$u~;Kbl-t7th{BFj2Uz0ip}9Kdkct&pyKu+4y1<<5VX3L6j55MVI^ z>(ve>T>|j~`uAX{=>ldnc|$O^z84&apn=9sPv1T^7AH)7rLE-Tw9Rf3BbcvtU^|}z zroia=@KZxrgQbmMd@CtJuui`VbTc3kw;2 zZ$PD>{^i4m4}h=2Q2JruMFqogSx@^?Dtl|;pp zYCbqAJ`qm~$&Ahd`m5YfvJ2MneezZ zTI`I%#Z5r~DWo*YvOc8WRnXGEW9|(3tPdF(Uhfm;PC7nh<^h)X9>z;yA!r|4T394L zGQhY}J$?N6(;NMIPqN@CC=wwGz4o~R4lwziJXs$rSppN{59F-gxN2-tIvat1#7%yq zr2eQq7V8X#&i`N1#!>Ml9+!!owJzd7;-b#{y+}qWA2muL6Wy$#U zN=EG!8G^Hlvqc19eRrk@dzILD<<~3+4Fr4%f=x)+=UhmpWE_V&; zj|B$hHC^=N0Kt7YJ9t&hzeT2!Otn92_UT#d>HOMBa~~V&j`~G*S?#p@@fYh&)(_54 zP#929ug&dnCbj~@+Af#UMTJY> zVCZFv)1#b=UP+c9=HJG}2s_F!w{UY4K!C$A_Yhh*rKM*aeUi_fp&~HI9#j}T#M#49d*Z0y)1D>;EY{&v8_RQ!G_qyhVsSZqfOp>BV$Y`mg6rtU0w>>}#$ z^L1K_`UCh6&xwm*?tY~>&C~p5M=4h+3A0b7se7XP{@O#PX6CP4%`L5DzC%q09E6(0 z4nv2$ZdLU@b(_a0Tf-fiMm~n8OvbR{9`7;kx!-^I(CGDR7@=DPc0}dnJcu4g9Gz?; z*7fTVQBgpq{b>%z4Ve@l3P|o6e*LKMjx2l203OO@sAn(8FTz|^{3O|8_ID z)T_$Udj3#=_yT|-z+ljZffNLeY8W*Skl1sw$KKSs1gWRp#ca(sCq?+nkjo;4ddf@F z(@YdhY8ZLU-bR554p3l4>dFX^kN!TZl`6|@x~C65k9flGL4sbu-m6ld+;<-!?e3TOFu z0&G#_Z=%LQ!P)p(<=4khV%uZye|EjThC`;Uquek5&StyiGmJ>k^SPIEFVAOm@z%m4 zq~W7%T_2ndZV!C-Dda8Y3CuS@O%C?dCeVxl1RL_7o;MXkMJ)$Cg9&k3@n`1k1=U&W zP~uoxSk@e`F7D5-DH9F78i;>hGP;#?^z{fHde5f#Y3_e34-AKa8FA~}DOP-S;F-Sb zmt;ZTO|+*^kWVgoEVr=A;#E&z1n` z1EmN=;CGN(v|!xo=qz^Zg>(+S{;BIi*{yv(P>lnk8m=uY5sVaQk!&UWO(?LMeMnA3 zZr+yP;&IV3AM-otcg#aJHO%kEf@U$lSlzJPvXontjnIseNd-6stpcKOmjzPoXa$$; z0V63G7z;a_JI^K0Mf5I&cE=nh?W=O>@-Yz-BBO%!DQ@18qn6X-mQ#IKY_z826<7Ip z{?zRi*0CPmLht53m6sntYZYh}@a4;Q2Ti1s`;|@U<}=;r&d+r?3T~y0KKtM^60O~= z#ERp;(;MyyM4G{egFu}{RP^#X)$3n)05IziAWD;z>^QF6XZKcB3g46B0+4~*Rh($q zsI^vx-X|ZKqzcrtUt!6kAJMxRzcjuGJTqDC`PT+3C4$k;?tbkANZinxgc)^Ld=|}H zxPjDIhmaMqKw>oBCADZ@VrN@ow`R8qOm^+sajtOQs*BzI3+y8P0sBl_r{-1efi81e zHKtr(Kwp#`QEl|PIxc8$Fu_}fo2Y++u~#we;kv)70*Jv{Q1Vq42|JhiR;IPE#>fOT z{r^iI2jD_LvT*gExKZ#!S8O9Zzm0^e?>$7XMS1bRzVH7?GJURS8*J+8#%H;+?Q^K1j*t8e1M!d~$X3v+3E@iJ`l)w_2)@_t@dpN9y_ z2m_)GU!V`bq$i)J5TPajC53U1sQJmcyq2~$yfJ=!IRAZ=`~T#}kazk#ZM?d_Pf&5K zb&NnY1AqM3gMvDPAo(;9qUfNI0si#I#=Tc;R>qb}>kB`-Mth5&6$j#y-B7oK=zQzH zY#BqeID&+7`DnOdDc(vTqiBe-iIav3Gr;E?I$K;!8S4K(1<9Ah8Bmbqkmf)Q4Ba3|WlQDD*j2cUEVItskKv&8 z-SH(JqC5D$&>|K%R>d+qggcL$yeK4-D?$91FgE+Cf`X_`gSD2)?_W?qVckeWjAosNIQ9hRk&3_>>aFfTZ%S(*L>I1 zxwJyXx+o|;z0PnUIO@i)8?ZLM?|hXx_JK;bgx)*yM~k?eRyuTP04>{N+k;9|sOR=0 zaSde+RS8u<$-%r#r1b+7{oFR(d3YZ>D)&#KYYJ;J;*AP4H&z)7%^Xe~6ulL57IJ!V zlFvymVm?RW`Ar4GVEV6|%Xc<{(!C7jh=1$5azb?>hMR^~ss#Km_?oBWyg~;TBVA@q4?rw+RT>9 zp0mGso7E+Bn|e#-@35q1Q8T2q80-ara0jg}LyoxSnMxR%0(Q3l$=p0(!ab0)^cMhzxayHr*)s`U#?*f*YJ#i= z8j%;fy+SZ70R<5fs)vc)Ft=4jyXf_cEO%iTRo&Fw40QkywCH5w({pnJH(@MbR^OYo z;e06K0sORrI0-hLAR(=+bOJ~O$VCbY3c!7b7qz?lADpc~V|VIy>H?}EG|)YP)CawC zP|3AENw#83EHeV>0o45<_k`>KoM9%P8{ee#@TOY9z)!6S_&WjQ1iS09?!O;}emgQN#>#*nMDf&{dvr|&0 zp?yt3PQFD1XayM00L>o!@*$;yu*DhI9ZVr~ZnO%R0#MH9<~|su+`(((0j3cQ@?Kk8 z+s28Gj)tWWz5j@wei=x&;7o1dJbEQNwjBTXF!c&z_`7*&`gk51?nP*k`S{B~#m2ky zSUAh`;p2 z@iq}iCcugm^f5D!3|K<$Jb4F?2^b{E)`WFEWTwHk0+TwAr;0(?3)(vo5foK%MMaLs zk4O9ai`SO?si&i5R1+d!L_x_tMNt=%(rL|XZNb}bmAR3HZU9H|@3_6W(m6_ex9Od` zml`V4QI>4)h1K;6|EhNvwf~cVnhzcdp$6g2Z#SX7cDMMU^z!S=yaZ8H1rgC1`(txF zKU`6&|GnAvG*QWkh>FdI7&+nu%!ir5{{8?cVQkEM;aEY}^5kS4z{8=;Wz(tzZ{C%K1s^rd|8KT7tN#F#;s@Vef6?NK z3UJ7RQO|n^2hri-tLnDk6s^o?zrQ*JJWbHx&2ikd0!Ep9jxzXw=;%zrHU#!D&>oBp z4J9Nb_OdC_ZZnFa+PnvTI>z-|(qbMm9$=Jf?dT!JBDWtqkAeU|3FRgCqB-B)Y=#{F zOX>UJe5&eiDz~73r(oc;sZ9(&OgYq7ph1X^1}*pYm75Db)vTavp<@KlUezmJfYBBZGkQQn56mo(J;A1IdRJ+M z4|L@2&Q54_8~l2TlImGcO$PCWj10OmcY62ON>D&x>tDpFQ{@c&n4dUp#N}cA zC8TUEt*u|tNRD+X(W*af`~P31U3oZ^?c075vQ#Frx0ndoTP90FT97QE5(Y0t_Se2I ziM*91J6Xn(WEmQaeHTIuWo%`8Wy_u=X2S29-|_wN{rMfocmMMobIdc(ec#XA&wX9b zb)DyVC5yfheIW)xZ3tLM7fBDq@AaScscWUsGBP#Gduw}Oa#d?-X$+_FI)Cieh*R|G zJ?2VraMyMd*T+{f8>}0;Od)=znl({F8M?r)#DYs}70uYJ4p9srn6a_EBQi0Q|cBNz-Z zGG*u-1j}S@y51i8_92XyZH@irvDOCbKN0(W-W`u&f=->|wdVq#4fe$jObO!&10@OU zaW6kbB1rko7Anj}3xKq6Ku1GF(%XdpmLS?%PNsqG+K&+Q^7U!oaiJ#%fkq zs_#2oIaPY^Lrnpf+r356FzhN4wJet9ka42(uYA-oAr&E)kMxJp)b<6dhX(XoW2ip? zZORm-mG%0ax|KUEo@2G7b#);qAl`mT$xrUW1s9N~I4Ga$qjOh+OSu5CWr|eI?2Rxy z6Y?E&LKuob)#jZJknb?)M*>sdsq#yJnV^&@534d|wpkvjO@C@udE-o<7N3g4PbDDD zEn-U^ynD?_<|Y#d)+D@^%a^~J0gZM8I2SH~tN6!XeV_*T@myGaR5Lm7rRDjeZtttdqN?=1>6c8{6 z{U6}80Y-{+6#_OsK0fdOK^1o#U)hawqM}Jk{tC~UGTJ!Pl>7mmOztm&+y^{#8&WZR z>|>;7*May3f`-At!5}>cnNR%)00e^-HIV`s(?qLdWI;hecJ@>#7#Fkp!W2W`Ea>Yf z?fE_RVRV^{qZtU02%z{kKnV{BvxK|`3~KGr%>z8Gq7ZQ#Tc^%9n#;VC(@FkUak>L* zP%=L|B->uMGgB#xBmQRS`BOOE)y-p-X{qYIp!Y@ax0R!oW&|#KoZs?PAnOro%8ttB z#3v^;CNy>wyBo)X+{&!DrcSGxRqY1YBo$EP0^%2_fxFH|!U|9q5{rM?@d&n$_V#uv zg%SXOXP5`*&I<_%iHZG$Sc?5+YE>8%SCa%>l$4az*|VX13}yxfZtw<5H0rh>Z~+_# z;`lnsyO)%e$I0YP@Nqzd0?Zl+8}#2(-~D%gXBKBx3s$N1>JdE7{0Lmpy zDto_utAY1+NVwP%eZcTN<6HZx2Ff8o+@JlN%yI141V?g!k4V#TL59>j!W z84$&^F}f$vGiW^mfpQ(#fxmvezXh8jxI3kWg+ToW1o!0>t*do{AprF7|2^snd$1`$ zia;)es+@`{u^+xrWl|3T_h=fZ_Werxd|FYpTU>y=s@qMdAh_r~#rFxI zbE%Q@1=0>%I6Is%NkuBP1gJ^U_1hKz<>(j2u!+u?)A4N8-twMLKS`0N@K*3B4F9rs z=N=>Zq$B3XDXISi0Q3|H{t#e4{;C!JR!9p$8ZoDB0pS0Ih6D>BcvU}D3qjec*W3{X zS{FM@=LXy^sD3eYm1?(TQ9gVRk|_rOz(c=hTlUhxuuGseW(Lc_wKROg|veX3M8A7EE; z?$$|ntZv`#1V|##ux~IW%ez|X>H_m65#9lcYID&DSKc0)yzH^7h3)0Ydfg4vj9U#L4uZ?d(b&976jD)oFv0SuS=l^pdusVm;EXr+(O$3l!9*>^^>nQu+lCR zv?mZm>kh%AR1VNS-)G7|%$qy;IxW6hxVBccN&O&nVG=FBTHJI$W64d2$h<`d(FNI{ zx;_$Y2+HyM{WS!9sg{9AOu1&ny?dui!Yd%^3NU*ppcbeTRSZwn@<=i0MGa!8s_B&3^Kv1MO^iuT`i`d?*6T zFqf=xNEbnPE;Dkg5Lgruo>rY{<(z-?n9%c&=NV$?^4Es0w7Z=&x`z)7yyA!TN$a*C zow{{c~#KJmq!t#309f+6ZZVm|XHH*^K8EYEvX zxJSJ?4z|VAQ#;2fSwC6dr`TWwJ#Dd{;%Zpj_0X{I4x>}nZ8e59hR%gA zS2&%NDw3_6UTsEgo?NnPDid{*P&Rb?+j6WeuSh?Qp~p62B-Li`uih{vRa|s!^b&Td zVPKD9IUfakrbjLD8Omj5CK>LliR<#A;=qZ8Iq?UbZ2KPDVP=6DoAn5iBuuZ1$Q;n7 z6ZuKVDQ%P=I$KFHl{Kyi=j65LNJ1Ghg1M2z*2CJ_&Qo=!Cy+*&5QGI0E+#b!xL$NsRgWsq^_+TA&{roL9~H-kA86io zM-YZZjT_etW`3p>=%nNIM>Uu<#MJYh3UD(D4r?K;s`b6WHcjR->?EO|bWf~3b207J zB*MV=dPxLX6{6kCBZr#>LY@$f>QWub$a89M)F94vzB|d^12%VN^y4Fs2TT?MKmKV6 zU-N1@nqzcM|C8Lz3EQvfPSQ5fW%)+FVLkj2vKxA*U@bof!K=ngtDn6?Uf19~H(koB zre^Z{^G%$KD(XBxXv%Do)aC>eUgQm4WjOIPOB3zLrN4Xn{VBhM-G?x;<-_P@G#_4g z?M_yf<~3q!o%a@wbH88H8$nw5(`h@$->2t$Ftb*ppTwLbas#N#SJ~#w{g40Y+c5?$ zm=jm-dNg+rbjLWr5Z|8E(~1&ye<+526xp8IT-{v3R=0%de1$p_tywu^BJwoW(c)cH zuySX0wEN^h=)7-k6tDcPqBz+yS#TT0Qp7f$tDsw6TDR%vlZ_&7?dMK^kPBp?a-_8G zVYh1DYYXLb)O{ZInyEc)8R#c6ankkO&Jwjkb2+}hf^1wOInL%67~Ddy`l&M`zOTN| zC<|{}ly6()a$N46lqPXPj@}kXbo`HB5e^&};x44nuv~L>Hl6b2{ zAVema;vLO+hwr+Xw84Q!@vOW&jZEE*uV|UxrBc!l0%7U-wp)(TL;nUNGX9G#u}P{4 zpMRflXVG@*r}=!w!gWmba5eLe>Zlb?Nx?Rvx;n=w=f1q50+VEDwXBkRZoa>+T`R$* z!d)aJPBy{Q-BZgs{Y#CGyC(79=w|W=`Hh{V{wLcXm~@Zy{#S32USm7)i_rC_=;ttf9?Mf2$!3K~3I{2)5*-yo~PVbfRQgJUt?uS(#L7pZv99AG@&l-C@y4 zg~Z6Ovc{o^%ngSyV{>v&SUxy_T-Scct0pk#?4nAchxOQ7@ftO~xsXczP1SayM~W+1 zxxJifGat!>V-FoZ02U_0Iy3XOQiF(KOXpB1(ui`IjjU4th%I~H!0k0behLqaPut`Z zON$YGeFg`I?dJ!A+GAquu_pbQnQReQro+tJ>j*-ruq7YldL<-cDI|xWRMnl&i-?5n z!?^F%rW_1G(VmNtV}d^H>_5~Z4euFzh`_QUJP#jmPmu!4Q{?q|xt_P(ADJNMkYhgHpgw0@?@n3aui@fR1?$)-@cFa4i_6qM$3`mU4#l&W zVUXhYKOTK6wN?`nk*%)IhwC3kZx?_wY4MosIuW!ncJ;n}pM1|>Hs%c}OnYp!o?pLur64$!u4hy3md7!6h{4NU^tcty@88!6!rNVDZ?dwFl*mXY zU82oJf}7jj$EPkV%x7LN7jL{IBg@ga`i>k^DA85riY+pmJ#lp;=!NoR-Ulv4-LXjXN5lD@xI~M z&0hzO!);7%V$=pp~hDO@wAd2*-lm;klgRu*i-e=1+JRaf}kJ%>O;7 kS!b1Y{6Amo|2dT1LwhKTo}|Ii8d|R!H??mRshS7>2RjG#zW@LL diff --git a/examples/librpma_gpspm-client.fio b/examples/librpma_gpspm-client.fio deleted file mode 100644 index 843382df66..0000000000 --- a/examples/librpma_gpspm-client.fio +++ /dev/null @@ -1,23 +0,0 @@ -# Example of the librpma_gpspm_client job - -[global] -ioengine=librpma_gpspm_client -create_serialize=0 # (required) forces specific initiation sequence -serverip=[serverip] #IP address the server is listening on -port=7204 # port(s) the server will listen on, will be used -thread - -# The client will get a remote memory region description after establishing -# a connection. - -[client] -numjobs=1 # number of parallel connections -group_reporting=1 -sync=1 # 1 is the best for latency measurements, 0 for bandwidth -iodepth=2 # total number of ious -iodepth_batch_submit=1 # number of ious to be submitted at once -rw=write # write/randwrite -blocksize=4KiB -ramp_time=15s # gives some time to stabilize the workload -time_based -runtime=60s # run the workload for the specified period of time diff --git a/examples/librpma_gpspm-client.png b/examples/librpma_gpspm-client.png deleted file mode 100644 index 0c975a275a4b9d8c06f68867026015279d6bcda8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56398 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

wXUMgtjJn99gl7qy9_e(edQkXioNXx%qvm~L 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

3oQY*V{ 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

0U)LZ*m5whi!U(nz!`{<8S61c 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 XT6~}AJ9%gp@*7bhsTVl{uRs0|z5_wz diff --git a/examples/librpma_gpspm-server.fio b/examples/librpma_gpspm-server.fio deleted file mode 100644 index 4555314f8a..0000000000 --- a/examples/librpma_gpspm-server.fio +++ /dev/null @@ -1,33 +0,0 @@ -# Example of the librpma_gpspm_server job - -[global] -ioengine=librpma_gpspm_server -create_serialize=0 # (required) forces specific initiation sequence -kb_base=1000 # turn on the straight units handling (non-compatibility mode) -serverip=[serverip] #IP address to listen on -port=7204 # port(s) the server jobs will listen on, ports will be used -thread - -# The server side spawns one thread for each expected connection from -# the client-side, opens and registers the range dedicated for this thread -# (a workspace) from the provided memory. -# Each of the server threads accepts a connection on the dedicated port -# (different for each and every working thread), accepts and executes flush -# requests, and sends back a flush response for each of the requests. -# When the client is done it sends the termination notice to the server's thread. - -[server] -# set to 1 (true) ONLY when Direct Write to PMem from the remote host is possible -# (https://pmem.io/rpma/documentation/basic-direct-write-to-pmem.html) -direct_write_to_pmem=0 -# set to 0 (false) to wait for completion instead of busy-wait polling completion. -busy_wait_polling=1 -numjobs=1 # number of expected incoming connections -iodepth=2 # number of parallel GPSPM requests -size=100MiB # size of workspace for a single connection -filename=malloc # device dax or an existing fsdax file or "malloc" for allocation from DRAM -# filename=/dev/dax1.0 - -# The client will terminate the server when the client will end up its job. -time_based -runtime=365d diff --git a/examples/librpma_gpspm-server.png b/examples/librpma_gpspm-server.png deleted file mode 100644 index 56124533da44ca4b960dda8418a4015dfa04c93b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53793 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 Date: Thu, 29 Aug 2024 13:58:38 +0200 Subject: [PATCH 6/8] rpma: remove librpma support Remove librpma support as rpma project is already archived: https://github.com/pmem/rpma Signed-off-by: Tomasz Gromadzki --- ci/actions-install.sh | 3 --- tools/fiograph/fiograph.conf | 9 --------- 2 files changed, 12 deletions(-) diff --git a/ci/actions-install.sh b/ci/actions-install.sh index 1895e519a5..6303d53585 100755 --- a/ci/actions-install.sh +++ b/ci/actions-install.sh @@ -146,9 +146,6 @@ install_fedora() { ;; esac dnf install -y "${pkgs[@]}" - - # install librpma from sources - ci/actions-install-librpma.sh } install_rhel_clone() { diff --git a/tools/fiograph/fiograph.conf b/tools/fiograph/fiograph.conf index 123c39ae71..6fb1bc14f9 100644 --- a/tools/fiograph/fiograph.conf +++ b/tools/fiograph/fiograph.conf @@ -71,15 +71,6 @@ specific_options=namenode hostname port hdfsdirectory chunk_size single_ins [ioengine_libiscsi] specific_options=initiator -[ioengine_librpma_apm_server] -specific_options=librpma_apm_client - -[ioengine_busy_wait_polling] -specific_options=serverip port direct_write_to_pmem - -[ioengine_librpma_gpspm_server] -specific_options=librpma_gpspm_client - [ioengine_mmap] specific_options=thp From ec45bc8b5ac779c3387c0c4f1815092b8c85d834 Mon Sep 17 00:00:00 2001 From: Tomasz Gromadzki Date: Thu, 29 Aug 2024 16:14:20 +0200 Subject: [PATCH 7/8] Fix parameter type Signed-off-by: Tomasz Gromadzki --- fio.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fio.1 b/fio.1 index 7846e95732..1953aea118 100644 --- a/fio.1 +++ b/fio.1 @@ -2431,7 +2431,7 @@ The TCP or UDP port to bind to or connect to. If this is used with this will be the starting port number since fio will use a range of ports. .TP -.BI (rdma)port +.BI (rdma)port \fR=\fPint The port to use for RDMA-CM communication. This should be the same value on the client and the server side. .TP From 52fe8d5f06c02d5a744a083517d7171ebee3b111 Mon Sep 17 00:00:00 2001 From: Tomasz Gromadzki Date: Thu, 29 Aug 2024 16:29:50 +0200 Subject: [PATCH 8/8] Remove obsolete library ref. Signed-off-by: Tomasz Gromadzki --- ci/actions-install.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/ci/actions-install.sh b/ci/actions-install.sh index 6303d53585..7a87fbe334 100755 --- a/ci/actions-install.sh +++ b/ci/actions-install.sh @@ -54,7 +54,6 @@ DPKGCFG libiscsi-dev libnbd-dev libpmem-dev - libpmemblk-dev librbd-dev libtcmalloc-minimal4 libibverbs-dev