diff --git a/configure b/configure index 00274f1b34..e95915f2de 100755 --- a/configure +++ b/configure @@ -35,6 +35,8 @@ function usage() echo " No path required." echo " rdma [disabled]" echo " No path required." + echo " vtune Required to profile I/O under Intel VTune Amplifier XE." + echo " example: /opt/intel/vtune_amplifier_xe_version" echo "" } @@ -115,6 +117,14 @@ for i in "$@"; do FIO_SOURCE_DIR= CONFIG_FIO_PLUGIN=n ;; + --with-vtune=*) + VTUNE_SOURCE_DIR="${i#*=}" + CONFIG_VTUNE=y + ;; + --without-vtune) + VTUNE_SOURCE_DIR= + CONFIG_VTUNE=n + ;; --) break ;; @@ -145,6 +155,13 @@ if [ "$CONFIG_FIO_PLUGIN" = "y" ]; then fi fi +if [ "$CONFIG_VTUNE" = "y" ]; then + if [ -z "$VTUNE_SOURCE_DIR" ]; then + echo "When VTune is enabled, you must specify the VTune directory using --with-vtune=path" + exit 1 + fi +fi + if [ "$CONFIG_ASAN" = "y" -a "$CONFIG_TSAN" = "y" ]; then echo "ERROR: ASAN and TSAN cannot be enabled at the same time." exit 1 @@ -193,6 +210,12 @@ fi if [ -n "$CONFIG_RBD" ]; then echo "CONFIG_RBD?=$CONFIG_RBD" >> CONFIG.local fi +if [ -n "$CONFIG_VTUNE" ]; then + echo "CONFIG_VTUNE?=$CONFIG_VTUNE" >> CONFIG.local +fi +if [ -n "$VTUNE_SOURCE_DIR" ]; then + echo "VTUNE_SOURCE_DIR?=$VTUNE_SOURCE_DIR" >> CONFIG.local +fi python scripts/genconfig.py > config.h diff --git a/lib/bdev/Makefile b/lib/bdev/Makefile index 4e93af215e..539eaa01ec 100644 --- a/lib/bdev/Makefile +++ b/lib/bdev/Makefile @@ -35,7 +35,13 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..) include $(SPDK_ROOT_DIR)/mk/spdk.common.mk CFLAGS += $(ENV_CFLAGS) -I. +ifeq ($(CONFIG_VTUNE),y) +CFLAGS += -I$(VTUNE_SOURCE_DIR)/include +endif + C_SRCS = bdev.c scsi_nvme.c +C_SRCS-$(CONFIG_VTUNE) += $(VTUNE_SOURCE_DIR)/sdk/src/ittnotify/ittnotify_static.c + LIBNAME = bdev DIRS-y += error malloc null nvme rpc split diff --git a/lib/bdev/bdev.c b/lib/bdev/bdev.c index fed537a058..87856da73a 100644 --- a/lib/bdev/bdev.c +++ b/lib/bdev/bdev.c @@ -46,6 +46,11 @@ #include "spdk_internal/bdev.h" #include "spdk_internal/event.h" #include "spdk_internal/log.h" +#include "spdk/string.h" + +#ifdef SPDK_CONFIG_VTUNE +#include "ittnotify.h" +#endif #define SPDK_BDEV_IO_POOL_SIZE (64 * 1024) #define BUF_SMALL_POOL_SIZE 8192 @@ -63,6 +68,10 @@ struct spdk_bdev_mgr { TAILQ_HEAD(, spdk_bdev_module_if) vbdev_modules; TAILQ_HEAD(, spdk_bdev) bdevs; + +#ifdef SPDK_CONFIG_VTUNE + __itt_domain *domain; +#endif }; static struct spdk_bdev_mgr g_bdev_mgr = { @@ -89,6 +98,13 @@ struct spdk_bdev_channel { struct spdk_io_channel *mgmt_channel; struct spdk_bdev_io_stat stat; + +#ifdef SPDK_CONFIG_VTUNE + uint64_t start_tsc; + uint64_t interval_tsc; + __itt_string_handle *handle; +#endif + }; struct spdk_bdev * @@ -367,8 +383,13 @@ spdk_bdev_initialize(void) if (!g_bdev_mgr.buf_large_pool) { SPDK_ERRLOG("create rbuf large pool failed\n"); rc = -1; + goto end; } +#ifdef SPDK_CONFIG_VTUNE + g_bdev_mgr.domain = __itt_domain_create("spdk_bdev"); +#endif + spdk_io_device_register(&g_bdev_mgr, spdk_bdev_mgmt_channel_create, spdk_bdev_mgmt_channel_destroy, sizeof(struct spdk_bdev_mgmt_channel)); @@ -563,6 +584,21 @@ spdk_bdev_channel_create(void *io_device, void *ctx_buf) ch->mgmt_channel = spdk_get_io_channel(&g_bdev_mgr); memset(&ch->stat, 0, sizeof(ch->stat)); +#ifdef SPDK_CONFIG_VTUNE + { + char *name; + + name = spdk_sprintf_alloc("spdk_bdev_%s_%p", ch->bdev->name, ch); + if (!name) { + return -1; + } + ch->handle = __itt_string_handle_create(name); + free(name); + ch->start_tsc = spdk_get_ticks(); + ch->interval_tsc = spdk_get_ticks_hz() / 100; + } +#endif + return 0; } @@ -957,6 +993,11 @@ void spdk_bdev_get_io_stat(struct spdk_bdev *bdev, struct spdk_io_channel *ch, struct spdk_bdev_io_stat *stat) { +#ifdef SPDK_CONFIG_VTUNE + SPDK_ERRLOG("Calling spdk_bdev_get_io_stat is not allowed when VTune integration is enabled.\n"); + memset(stat, 0, sizeof(*stat)); + return; +#endif struct spdk_bdev_channel *channel = spdk_io_channel_get_ctx(ch); @@ -1128,6 +1169,24 @@ spdk_bdev_io_complete(struct spdk_bdev_io *bdev_io, enum spdk_bdev_io_status sta } } +#ifdef SPDK_CONFIG_VTUNE + uint64_t now_tsc = spdk_get_ticks(); + if (now_tsc > (bdev_io->ch->start_tsc + bdev_io->ch->interval_tsc)) { + uint64_t data[4]; + + data[0] = bdev_io->ch->stat.num_read_ops; + data[1] = bdev_io->ch->stat.bytes_read; + data[2] = bdev_io->ch->stat.num_write_ops; + data[3] = bdev_io->ch->stat.bytes_written; + + __itt_metadata_add(g_bdev_mgr.domain, __itt_null, bdev_io->ch->handle, + __itt_metadata_u64, 4, data); + + memset(&bdev_io->ch->stat, 0, sizeof(bdev_io->ch->stat)); + bdev_io->ch->start_tsc = now_tsc; + } +#endif + assert(bdev_io->cb != NULL); bdev_io->cb(bdev_io, status == SPDK_BDEV_IO_STATUS_SUCCESS, bdev_io->caller_ctx); }