Commit 1f3b17e9 authored by Sebastian Brzezinka's avatar Sebastian Brzezinka Committed by Jim Harris
Browse files

lib/event: add parsers for `/proc/stat`



This patch adds parsers for /proc/ files to gather statistics about
time spent processing interrupts, and amount of time spent in kernel
or user mode.

Also, add system statistics to `framework_get_reactors`
Add information about time spent by system processing interrupts,
kernel mode and user mode since start of spdk application to
`framework_get_reactors` rpc response.

Signed-off-by: default avatarSebastian Brzezinka <sebastian.brzezinka@intel.com>
Change-Id: Ia9f8fb1246825a8b26815d62b40cbe1d21120b06
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/20989


Reviewed-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
Community-CI: Mellanox Build Bot
parent 5c366748
Loading
Loading
Loading
Loading
+88 −1
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include "spdk/rpc.h"
#include "spdk/util.h"
#include "spdk/file.h"
#include "event_internal.h"

#define SPDK_APP_DEFAULT_LOG_LEVEL		SPDK_LOG_NOTICE
#define SPDK_APP_DEFAULT_LOG_PRINT_LEVEL	SPDK_LOG_INFO
@@ -67,6 +68,12 @@ static bool g_disable_cpumask_locks = false;

static int g_core_locks[MAX_CPU_CORES];

static struct {
	uint64_t irq;
	uint64_t usr;
	uint64_t sys;
} g_initial_stat[MAX_CPU_CORES];

int
spdk_app_get_shm_id(void)
{
@@ -145,6 +152,80 @@ static const struct option g_cmdline_options[] = {
	{"no-rpc-server",		no_argument,		NULL, NO_RPC_SERVER_OPT_IDX},
};

static int
parse_proc_stat(unsigned int core, uint64_t *user, uint64_t *sys, uint64_t *irq)
{
	FILE *f;
	uint64_t i, soft_irq, cpu = 0;
	int rc, found = 0;

	f = fopen("/proc/stat", "r");
	if (!f) {
		return -1;
	}

	for (i = 0; i <= core + 1; i++) {
		/* scanf discards input with '*' in format,
		 * cpu;user;nice;system;idle;iowait;irq;softirq;steal;guest;guest_nice */
		rc = fscanf(f, "cpu%li %li %*i %li %*i %*i %li %li %*i %*i %*i\n",
			    &cpu, user, sys, irq, &soft_irq);
		if (rc != 5) {
			continue;
		}

		/* some cores can be disabled, list may not be in order */
		if (cpu == core) {
			found = 1;
			break;
		}
	}

	*irq += soft_irq;

	fclose(f);
	return found ? 0 : -1;
}

static int
init_proc_stat(unsigned int core)
{
	uint64_t usr, sys, irq;

	if (core >= MAX_CPU_CORES) {
		return -1;
	}

	if (parse_proc_stat(core, &usr, &sys, &irq) < 0) {
		return -1;
	}

	g_initial_stat[core].irq = irq;
	g_initial_stat[core].usr = usr;
	g_initial_stat[core].sys = sys;

	return 0;
}

int
app_get_proc_stat(unsigned int core, uint64_t *usr, uint64_t *sys, uint64_t *irq)
{
	uint64_t _usr, _sys, _irq;

	if (core >= MAX_CPU_CORES) {
		return -1;
	}

	if (parse_proc_stat(core, &_usr, &_sys, &_irq) < 0) {
		return -1;
	}

	*irq = _irq - g_initial_stat[core].irq;
	*usr = _usr - g_initial_stat[core].usr;
	*sys = _sys - g_initial_stat[core].sys;

	return 0;
}

static void
app_start_shutdown(void *ctx)
{
@@ -723,7 +804,7 @@ spdk_app_start(struct spdk_app_opts *opts_user, spdk_msg_fn start_fn,
	static bool		g_env_was_setup = false;
	struct spdk_app_opts opts_local = {};
	struct spdk_app_opts *opts = &opts_local;
	uint32_t i;
	uint32_t i, core;

	if (!opts_user) {
		SPDK_ERRLOG("opts_user should not be NULL\n");
@@ -841,6 +922,12 @@ spdk_app_start(struct spdk_app_opts *opts_user, spdk_msg_fn start_fn,
		return 1;
	}

	SPDK_ENV_FOREACH_CORE(core) {
		rc = init_proc_stat(core);
		if (rc) {
			SPDK_NOTICELOG("Unable to parse /proc/stat [core: %d].\n", core);
		}
	}
	/*
	 * Disable and ignore trace setup if setting num_entries
	 * to be 0.
+9 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include "spdk/log.h"
#include "spdk_internal/event.h"
#include "spdk_internal/thread.h"
#include "event_internal.h"

struct rpc_spdk_kill_instance {
	char *sig_name;
@@ -356,6 +357,7 @@ _rpc_framework_get_reactors(void *arg1, void *arg2)
	struct rpc_get_stats_ctx *ctx = arg1;
	uint32_t current_core;
	uint32_t curr_core_freq;
	uint64_t sys, usr, irq;
	struct spdk_reactor *reactor;
	struct spdk_lw_thread *lw_thread;
	struct spdk_thread *thread;
@@ -373,6 +375,13 @@ _rpc_framework_get_reactors(void *arg1, void *arg2)
	spdk_json_write_named_uint64(ctx->w, "idle", reactor->idle_tsc);
	spdk_json_write_named_bool(ctx->w, "in_interrupt", reactor->in_interrupt);

	if (app_get_proc_stat(current_core, &usr, &sys, &irq) != 0) {
		irq = sys = usr = 0;
	}
	spdk_json_write_named_uint64(ctx->w, "irq", irq);
	spdk_json_write_named_uint64(ctx->w, "sys", sys);
	spdk_json_write_named_uint64(ctx->w, "usr", usr);

	governor = spdk_governor_get();
	if (governor != NULL) {
		/* Governor returns core freqs in kHz, we want MHz. */
+30 −0
Original line number Diff line number Diff line
/*   SPDX-License-Identifier: BSD-3-Clause
 *   Copyright (C) 2024 Intel Corporation.
 *   All rights reserved.
 */
#ifndef EVENT_INTERNAL_H
#define EVENT_INTERNAL_H

#include "spdk/stdinc.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * Parse proc/stat and get time spent processing system mode and user mode
 *
 * \param core Core which will be queried
 * \param usr Holds time [USER_HZ] spent processing in user mode
 * \param sys Holds time [USER_HZ] spent processing in system mode
 * \param irq Holds time [USER_HZ] spent processing interrupts
 *
 * \return 0 on success -1 on fail
 */
int app_get_proc_stat(unsigned int core, uint64_t *usr, uint64_t *sys, uint64_t *irq);

#ifdef __cplusplus
}
#endif

#endif