MSG_ZEROCOPY is not always effective as mentioned in https://www.kernel.org/doc/html/v4.15/networking/msg_zerocopy.html. Currently in spdk, once we enable sendmsg zerocopy, then all data transferred through _sock_flush are sent with zerocopy, and vice versa. Here dynamic zerocopy is introduced to allow data sent with MSG_ZEROCOPY or not according to its size, which can be enabled by setting "enable_dynamic_zerocopy" as true. Test with 16 P4610 NVMe SSD, 2 initiators, target's and initiators' configurations are the same as spdk report: https://ci.spdk.io/download/performance-reports/SPDK_tcp_perf_report_2104.pdf For posix socket, rw_percent=0(randwrite), it has 1.9%~8.3% performance boost tested with target 1~40 cpu cores and qdepth=128,256,512. And it has no obvious influence when read percentage is greater than 50%. For uring socket, rw_percent=0(randwrite), it has 1.8%~7.9% performance boost tested with target 1~40 cpu cores and qdepth=128,256,512. And it still has 1%~7% improvement when read percentage is greater than 50%. The following is part of the detailed data. posix: qdepth=128 rw_percent 0 | 30 cpu origin thisPatch opt | origin thisPatch opt 1 286.5 298.5 4.19% 307 304.15 -0.93% 4 1042.5 1107 6.19% 1135.5 1136 0.04% 8 1952.5 2058 5.40% 2170.5 2170.5 0.00% 12 2658.5 2879 8.29% 3042 3046 0.13% 16 3247.5 3460.5 6.56% 3793.5 3775 -0.49% 24 4232.5 4459.5 5.36% 4614.5 4756.5 3.08% 32 4810 5095 5.93% 4488 4845 7.95% 40 5306.5 5435 2.42% 4427.5 4902 10.72% qdepth=512 rw_percent 0 | 30 cpu origin thisPatch opt | origin thisPatch opt 1 275 287 4.36% 294.4 295.45 0.36% 4 979 1041 6.33% 1073 1083.5 0.98% 8 1822.5 1914.5 5.05% 2030.5 2018.5 -0.59% 12 2441 2598.5 6.45% 2808.5 2779.5 -1.03% 16 2920.5 3109.5 6.47% 3455 3411.5 -1.26% 24 3709 3972.5 7.10% 4483.5 4502.5 0.42% 32 4225.5 4532.5 7.27% 4463.5 4733 6.04% 40 4790.5 4884.5 1.96% 4427 4904.5 10.79% uring: qdepth=128 rw_percent 0 | 30 cpu origin thisPatch opt | origin thisPatch opt 1 270.5 287.5 6.28% 295.75 304.75 3.04% 4 1018.5 1089.5 6.97% 1119.5 1156.5 3.31% 8 1907 2055 7.76% 2127 2211.5 3.97% 12 2614 2801 7.15% 2982.5 3061.5 2.65% 16 3169.5 3420 7.90% 3654.5 3781.5 3.48% 24 4109.5 4414 7.41% 4691.5 4750.5 1.26% 32 4752.5 4908 3.27% 4494 4825.5 7.38% 40 5233.5 5327 1.79% 4374.5 4891 11.81% qdepth=512 rw_percent 0 | 30 cpu origin thisPatch opt | origin thisPatch opt 1 259.95 276 6.17% 286.65 294.8 2.84% 4 955 1021 6.91% 1070.5 1100 2.76% 8 1772 1903.5 7.42% 1992.5 2077.5 4.27% 12 2380.5 2543.5 6.85% 2752.5 2860 3.91% 16 2920.5 3099 6.11% 3391.5 3540 4.38% 24 3697 3912 5.82% 4401 4637 5.36% 32 4256.5 4454.5 4.65% 4516 4777 5.78% 40 4707 4968.5 5.56% 4400.5 4933 12.10% Signed-off-by: Richael Zhuang <richael.zhuang@arm.com> Change-Id: I730dcf89ed2bf3efe91586421a89045fc11c81f0 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/12210 Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com> Community-CI: Mellanox Build Bot Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com>
211 lines
7.4 KiB
C
211 lines
7.4 KiB
C
/*-
|
|
* BSD LICENSE
|
|
*
|
|
* Copyright (c) 2020, 2021 Mellanox Technologies LTD. All rights reserved.
|
|
* Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* * Neither the name of Intel Corporation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "spdk/sock.h"
|
|
|
|
#include "spdk/rpc.h"
|
|
#include "spdk/util.h"
|
|
#include "spdk/string.h"
|
|
|
|
#include "spdk/log.h"
|
|
|
|
|
|
static const struct spdk_json_object_decoder rpc_sock_impl_get_opts_decoders[] = {
|
|
{ "impl_name", 0, spdk_json_decode_string, false },
|
|
};
|
|
|
|
static void
|
|
rpc_sock_impl_get_options(struct spdk_jsonrpc_request *request,
|
|
const struct spdk_json_val *params)
|
|
{
|
|
char *impl_name = NULL;
|
|
struct spdk_sock_impl_opts sock_opts = {};
|
|
struct spdk_json_write_ctx *w;
|
|
size_t len;
|
|
int rc;
|
|
|
|
if (spdk_json_decode_object(params, rpc_sock_impl_get_opts_decoders,
|
|
SPDK_COUNTOF(rpc_sock_impl_get_opts_decoders), &impl_name)) {
|
|
SPDK_ERRLOG("spdk_json_decode_object() failed\n");
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
|
"Invalid parameters");
|
|
return;
|
|
}
|
|
|
|
len = sizeof(sock_opts);
|
|
rc = spdk_sock_impl_get_opts(impl_name, &sock_opts, &len);
|
|
if (rc) {
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
|
"Invalid parameters");
|
|
return;
|
|
}
|
|
|
|
w = spdk_jsonrpc_begin_result(request);
|
|
spdk_json_write_object_begin(w);
|
|
spdk_json_write_named_uint32(w, "recv_buf_size", sock_opts.recv_buf_size);
|
|
spdk_json_write_named_uint32(w, "send_buf_size", sock_opts.send_buf_size);
|
|
spdk_json_write_named_bool(w, "enable_recv_pipe", sock_opts.enable_recv_pipe);
|
|
spdk_json_write_named_bool(w, "enable_quickack", sock_opts.enable_quickack);
|
|
spdk_json_write_named_uint32(w, "enable_placement_id", sock_opts.enable_placement_id);
|
|
spdk_json_write_named_bool(w, "enable_zerocopy_send_server", sock_opts.enable_zerocopy_send_server);
|
|
spdk_json_write_named_bool(w, "enable_zerocopy_send_client", sock_opts.enable_zerocopy_send_client);
|
|
spdk_json_write_named_uint32(w, "zerocopy_threshold", sock_opts.zerocopy_threshold);
|
|
spdk_json_write_object_end(w);
|
|
spdk_jsonrpc_end_result(request, w);
|
|
free(impl_name);
|
|
}
|
|
SPDK_RPC_REGISTER("sock_impl_get_options", rpc_sock_impl_get_options,
|
|
SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME)
|
|
|
|
struct spdk_rpc_sock_impl_set_opts {
|
|
char *impl_name;
|
|
struct spdk_sock_impl_opts sock_opts;
|
|
};
|
|
|
|
static const struct spdk_json_object_decoder rpc_sock_impl_set_opts_decoders[] = {
|
|
{
|
|
"impl_name", offsetof(struct spdk_rpc_sock_impl_set_opts, impl_name),
|
|
spdk_json_decode_string, false
|
|
},
|
|
{
|
|
"recv_buf_size", offsetof(struct spdk_rpc_sock_impl_set_opts, sock_opts.recv_buf_size),
|
|
spdk_json_decode_uint32, true
|
|
},
|
|
{
|
|
"send_buf_size", offsetof(struct spdk_rpc_sock_impl_set_opts, sock_opts.send_buf_size),
|
|
spdk_json_decode_uint32, true
|
|
},
|
|
{
|
|
"enable_recv_pipe", offsetof(struct spdk_rpc_sock_impl_set_opts, sock_opts.enable_recv_pipe),
|
|
spdk_json_decode_bool, true
|
|
},
|
|
{
|
|
"enable_quickack", offsetof(struct spdk_rpc_sock_impl_set_opts, sock_opts.enable_quickack),
|
|
spdk_json_decode_bool, true
|
|
},
|
|
{
|
|
"enable_placement_id", offsetof(struct spdk_rpc_sock_impl_set_opts, sock_opts.enable_placement_id),
|
|
spdk_json_decode_uint32, true
|
|
},
|
|
{
|
|
"enable_zerocopy_send_server", offsetof(struct spdk_rpc_sock_impl_set_opts, sock_opts.enable_zerocopy_send_server),
|
|
spdk_json_decode_bool, true
|
|
},
|
|
{
|
|
"enable_zerocopy_send_client", offsetof(struct spdk_rpc_sock_impl_set_opts, sock_opts.enable_zerocopy_send_client),
|
|
spdk_json_decode_bool, true
|
|
},
|
|
{
|
|
"zerocopy_threshold", offsetof(struct spdk_rpc_sock_impl_set_opts, sock_opts.zerocopy_threshold),
|
|
spdk_json_decode_uint32, true
|
|
}
|
|
};
|
|
|
|
static void
|
|
rpc_sock_impl_set_options(struct spdk_jsonrpc_request *request,
|
|
const struct spdk_json_val *params)
|
|
{
|
|
struct spdk_rpc_sock_impl_set_opts opts = {};
|
|
size_t len;
|
|
int rc;
|
|
|
|
/* Get type */
|
|
if (spdk_json_decode_object(params, rpc_sock_impl_set_opts_decoders,
|
|
SPDK_COUNTOF(rpc_sock_impl_set_opts_decoders), &opts)) {
|
|
SPDK_ERRLOG("spdk_json_decode_object() failed\n");
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
|
"Invalid parameters");
|
|
return;
|
|
}
|
|
|
|
/* Retrieve default opts for requested socket implementation */
|
|
len = sizeof(opts.sock_opts);
|
|
rc = spdk_sock_impl_get_opts(opts.impl_name, &opts.sock_opts, &len);
|
|
if (rc) {
|
|
free(opts.impl_name);
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
|
"Invalid parameters");
|
|
return;
|
|
}
|
|
|
|
/* Decode opts */
|
|
if (spdk_json_decode_object(params, rpc_sock_impl_set_opts_decoders,
|
|
SPDK_COUNTOF(rpc_sock_impl_set_opts_decoders), &opts)) {
|
|
SPDK_ERRLOG("spdk_json_decode_object() failed\n");
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
|
"Invalid parameters");
|
|
return;
|
|
}
|
|
|
|
rc = spdk_sock_impl_set_opts(opts.impl_name, &opts.sock_opts, sizeof(opts.sock_opts));
|
|
if (rc != 0) {
|
|
free(opts.impl_name);
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
|
"Invalid parameters");
|
|
return;
|
|
}
|
|
|
|
spdk_jsonrpc_send_bool_response(request, true);
|
|
free(opts.impl_name);
|
|
}
|
|
SPDK_RPC_REGISTER("sock_impl_set_options", rpc_sock_impl_set_options, SPDK_RPC_STARTUP)
|
|
|
|
static void
|
|
rpc_sock_set_default_impl(struct spdk_jsonrpc_request *request,
|
|
const struct spdk_json_val *params)
|
|
{
|
|
char *impl_name = NULL;
|
|
int rc;
|
|
|
|
/* Reuse get_opts decoder */
|
|
if (spdk_json_decode_object(params, rpc_sock_impl_get_opts_decoders,
|
|
SPDK_COUNTOF(rpc_sock_impl_get_opts_decoders), &impl_name)) {
|
|
SPDK_ERRLOG("spdk_json_decode_object() failed\n");
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
|
"Invalid parameters");
|
|
return;
|
|
}
|
|
|
|
rc = spdk_sock_set_default_impl(impl_name);
|
|
if (rc) {
|
|
free(impl_name);
|
|
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
|
"Invalid parameters");
|
|
return;
|
|
}
|
|
|
|
spdk_jsonrpc_send_bool_response(request, true);
|
|
free(impl_name);
|
|
}
|
|
SPDK_RPC_REGISTER("sock_set_default_impl", rpc_sock_set_default_impl, SPDK_RPC_STARTUP)
|