Commit 7bbba48a authored by Jacek Kalwas's avatar Jacek Kalwas Committed by Tomasz Zawadzki
Browse files

thread: add iobuf stats



These could help to find quickly misconfig and misbehavior of overall
system under workload.

Change-Id: I0d90afbeeb6f73ef83a849619350eca9995105e3
Signed-off-by: default avatarJacek Kalwas <jacek.kalwas@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/18465


Reviewed-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
parent 847e8915
Loading
Loading
Loading
Loading
+70 −0
Original line number Diff line number Diff line
@@ -11984,6 +11984,76 @@ Example response:
}
~~~

### iobuf_get_stats {#rpc_iobuf_get_stats}

Retrieve iobuf's statistics.

#### Parameters

None.

#### Example

Example request:

~~~json
{
  "jsonrpc": "2.0",
  "method": "iobuf_get_stats",
  "id": 1
}
~~~

Example response:

~~~json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "module": "accel",
      "small_pool": {
        "cache": 0,
        "main": 0,
        "retry": 0
      },
      "large_pool": {
        "cache": 0,
        "main": 0,
        "retry": 0
      }
    },
    {
      "module": "bdev",
      "small_pool": {
        "cache": 421965,
        "main": 1218,
        "retry": 0
      },
      "large_pool": {
        "cache": 0,
        "main": 0,
        "retry": 0
      }
    },
    {
      "module": "spdk_nvmf_TCP_data",
      "small_pool": {
        "cache": 7,
        "main": 0,
        "retry": 0
      },
      "large_pool": {
        "cache": 0,
        "main": 0,
        "retry": 0
      }
    }
  ]
}
~~~

### bdev_nvme_start_mdns_discovery {#rpc_bdev_nvme_start_mdns_discovery}

Starts an mDNS based discovery service for the specified service type for the
+30 −1
Original line number Diff line number Diff line
@@ -993,6 +993,21 @@ struct spdk_iobuf_opts {
	uint32_t large_bufsize;
};

struct spdk_iobuf_pool_stats {
	/** Buffer got from local per-thread cache */
	uint64_t	cache;
	/** Buffer got from the main shared pool */
	uint64_t	main;
	/** Buffer missed and request to get buffer was queued */
	uint64_t	retry;
};

struct spdk_iobuf_module_stats {
	struct spdk_iobuf_pool_stats	small_pool;
	struct spdk_iobuf_pool_stats	large_pool;
	const char			*module;
};

struct spdk_iobuf_entry;

typedef void (*spdk_iobuf_get_cb)(struct spdk_iobuf_entry *entry, void *buf);
@@ -1004,7 +1019,6 @@ struct spdk_iobuf_entry {
	STAILQ_ENTRY(spdk_iobuf_entry)	stailq;
};


struct spdk_iobuf_buffer {
	STAILQ_ENTRY(spdk_iobuf_buffer)	stailq;
};
@@ -1025,6 +1039,8 @@ struct spdk_iobuf_pool {
	spdk_iobuf_entry_stailq_t	*queue;
	/** Buffer size */
	uint32_t			bufsize;
	/** Pool usage statistics */
	struct spdk_iobuf_pool_stats	stats;
};

/** iobuf channel */
@@ -1165,6 +1181,19 @@ void *spdk_iobuf_get(struct spdk_iobuf_channel *ch, uint64_t len, struct spdk_io
 */
void spdk_iobuf_put(struct spdk_iobuf_channel *ch, void *buf, uint64_t len);

typedef void (*spdk_iobuf_get_stats_cb)(struct spdk_iobuf_module_stats *modules,
					uint32_t num_modules, void *cb_arg);

/**
 * Get iobuf statistics.
 *
 * \param cb_fn Callback to be executed once stats are gathered.
 * \param cb_arg Argument passed to the callback function.
 *
 * \return 0 on success, negative errno otherwise.
 */
int spdk_iobuf_get_stats(spdk_iobuf_get_stats_cb cb_fn, void *cb_arg);

#ifdef __cplusplus
}
#endif
+2 −2
Original line number Diff line number Diff line
@@ -6,8 +6,8 @@
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk

SO_VER := 8
SO_MINOR := 1
SO_VER := 9
SO_MINOR := 0

C_SRCS = thread.c iobuf.c
LIBNAME = thread
+117 −2
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
 * are explicitly configured, the math is instead done properly. This is only
 * for the default. */
#define IOBUF_DEFAULT_LARGE_BUFSIZE	(132 * 1024)
#define IOBUF_MAX_CHANNELS		64

SPDK_STATIC_ASSERT(sizeof(struct spdk_iobuf_buffer) <= IOBUF_MIN_SMALL_BUFSIZE,
		   "Invalid data offset");
@@ -29,6 +30,7 @@ SPDK_STATIC_ASSERT(sizeof(struct spdk_iobuf_buffer) <= IOBUF_MIN_SMALL_BUFSIZE,
struct iobuf_channel {
	spdk_iobuf_entry_stailq_t	small_queue;
	spdk_iobuf_entry_stailq_t	large_queue;
	struct spdk_iobuf_channel	*channels[IOBUF_MAX_CHANNELS];
};

struct iobuf_module {
@@ -61,6 +63,13 @@ static struct iobuf g_iobuf = {
	},
};

struct iobuf_get_stats_ctx {
	struct spdk_iobuf_module_stats	*modules;
	uint32_t			num_modules;
	spdk_iobuf_get_stats_cb		cb_fn;
	void				*cb_arg;
};

static int
iobuf_channel_create_cb(void *io_device, void *ctx)
{
@@ -260,6 +269,18 @@ spdk_iobuf_channel_init(struct spdk_iobuf_channel *ch, const char *name,

	iobuf_ch = spdk_io_channel_get_ctx(ioch);

	for (i = 0; i < IOBUF_MAX_CHANNELS; ++i) {
		if (iobuf_ch->channels[i] == NULL) {
			iobuf_ch->channels[i] = ch;
			break;
		}
	}

	if (i == IOBUF_MAX_CHANNELS) {
		SPDK_ERRLOG("Max number of iobuf channels (%" PRIu32 ") exceeded.\n", i);
		goto error;
	}

	ch->small.queue = &iobuf_ch->small_queue;
	ch->large.queue = &iobuf_ch->large_queue;
	ch->small.pool = g_iobuf.small_pool;
@@ -313,6 +334,8 @@ spdk_iobuf_channel_fini(struct spdk_iobuf_channel *ch)
{
	struct spdk_iobuf_entry *entry __attribute__((unused));
	struct spdk_iobuf_buffer *buf;
	struct iobuf_channel *iobuf_ch;
	uint32_t i;

	/* Make sure none of the wait queue entries are coming from this module */
	STAILQ_FOREACH(entry, ch->small.queue, stailq) {
@@ -339,6 +362,14 @@ spdk_iobuf_channel_fini(struct spdk_iobuf_channel *ch)
	assert(ch->small.cache_count == 0);
	assert(ch->large.cache_count == 0);

	iobuf_ch = spdk_io_channel_get_ctx(ch->parent);
	for (i = 0; i < IOBUF_MAX_CHANNELS; ++i) {
		if (iobuf_ch->channels[i] == ch) {
			iobuf_ch->channels[i] = NULL;
			break;
		}
	}

	spdk_put_io_channel(ch->parent);
	ch->parent = NULL;
}
@@ -447,6 +478,7 @@ spdk_iobuf_get(struct spdk_iobuf_channel *ch, uint64_t len,
		STAILQ_REMOVE_HEAD(&pool->cache, stailq);
		assert(pool->cache_count > 0);
		pool->cache_count--;
		pool->stats.cache++;
	} else {
		struct spdk_iobuf_buffer *bufs[IOBUF_BATCH_SIZE];
		size_t sz, i;
@@ -459,11 +491,13 @@ spdk_iobuf_get(struct spdk_iobuf_channel *ch, uint64_t len,
				STAILQ_INSERT_TAIL(pool->queue, entry, stailq);
				entry->module = ch->module;
				entry->cb_fn = cb_fn;
				pool->stats.retry++;
			}

			return NULL;
		}

		pool->stats.main++;
		for (i = 0; i < (sz - 1); i++) {
			STAILQ_INSERT_HEAD(&pool->cache, bufs[i], stailq);
			pool->cache_count++;
@@ -525,3 +559,84 @@ spdk_iobuf_put(struct spdk_iobuf_channel *ch, void *buf, uint64_t len)
		entry->cb_fn(entry, buf);
	}
}

static void
iobuf_get_channel_stats_done(struct spdk_io_channel_iter *iter, int status)
{
	struct iobuf_get_stats_ctx *ctx = spdk_io_channel_iter_get_ctx(iter);

	ctx->cb_fn(ctx->modules, ctx->num_modules, ctx->cb_arg);
	free(ctx->modules);
	free(ctx);
}

static void
iobuf_get_channel_stats(struct spdk_io_channel_iter *iter)
{
	struct iobuf_get_stats_ctx *ctx = spdk_io_channel_iter_get_ctx(iter);
	struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(iter);
	struct iobuf_channel *iobuf_ch = spdk_io_channel_get_ctx(ch);
	struct spdk_iobuf_channel *channel;
	struct iobuf_module *module;
	struct spdk_iobuf_module_stats *it;
	uint32_t i, j;

	for (i = 0; i < ctx->num_modules; ++i) {
		for (j = 0; j < IOBUF_MAX_CHANNELS; ++j) {
			channel = iobuf_ch->channels[j];
			if (channel == NULL) {
				continue;
			}

			it = &ctx->modules[i];
			module = (struct iobuf_module *)channel->module;
			if (strcmp(it->module, module->name) == 0) {
				it->small_pool.cache += channel->small.stats.cache;
				it->small_pool.main += channel->small.stats.main;
				it->small_pool.retry += channel->small.stats.retry;
				it->large_pool.cache += channel->large.stats.cache;
				it->large_pool.main += channel->large.stats.main;
				it->large_pool.retry += channel->large.stats.retry;
				break;
			}
		}
	}

	spdk_for_each_channel_continue(iter, 0);
}

int
spdk_iobuf_get_stats(spdk_iobuf_get_stats_cb cb_fn, void *cb_arg)
{
	struct iobuf_module *module;
	struct iobuf_get_stats_ctx *ctx;
	uint32_t i;

	ctx = calloc(1, sizeof(*ctx));
	if (ctx == NULL) {
		return -ENOMEM;
	}

	TAILQ_FOREACH(module, &g_iobuf.modules, tailq) {
		++ctx->num_modules;
	}

	ctx->modules = calloc(ctx->num_modules, sizeof(struct spdk_iobuf_module_stats));
	if (ctx->modules == NULL) {
		free(ctx);
		return -ENOMEM;
	}

	i = 0;
	TAILQ_FOREACH(module, &g_iobuf.modules, tailq) {
		ctx->modules[i].module = module->name;
		++i;
	}

	ctx->cb_fn = cb_fn;
	ctx->cb_arg = cb_arg;

	spdk_for_each_channel(&g_iobuf, iobuf_get_channel_stats, ctx,
			      iobuf_get_channel_stats_done);
	return 0;
}
+1 −0
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@
	spdk_iobuf_entry_abort;
	spdk_iobuf_get;
	spdk_iobuf_put;
	spdk_iobuf_get_stats;

	# internal functions in spdk_internal/thread.h
	spdk_poller_get_name;
Loading