xref: /spdk/module/scheduler/gscheduler/gscheduler.c (revision 8afdeef3becfe9409cc9e7372bd0bc10e8b7d46d)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2021 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/stdinc.h"
7 #include "spdk/likely.h"
8 
9 #include "spdk_internal/event.h"
10 #include "spdk/thread.h"
11 
12 #include "spdk/log.h"
13 #include "spdk/env.h"
14 #include "spdk/scheduler.h"
15 
16 static uint32_t g_max_threshold = 99;
17 static uint32_t g_adjust_threshold = 50;
18 static uint32_t g_min_threshold = 1;
19 
20 static int
21 init(void)
22 {
23 	return spdk_governor_set("dpdk_governor");
24 }
25 
26 static void
27 deinit(void)
28 {
29 	spdk_governor_set(NULL);
30 }
31 
32 static uint32_t
33 calculate_busy_pct(struct spdk_scheduler_core_info *core)
34 {
35 	uint64_t total_tsc;
36 
37 	total_tsc = core->current_busy_tsc + core->current_idle_tsc;
38 	return core->current_busy_tsc * 100 / total_tsc;
39 }
40 
41 struct check_sibling_ctx {
42 	struct spdk_scheduler_core_info *cores;
43 	uint32_t busy_pct;
44 };
45 
46 static void
47 check_sibling(void *_ctx, uint32_t i)
48 {
49 	struct check_sibling_ctx *ctx = _ctx;
50 	struct spdk_scheduler_core_info *core = &ctx->cores[i];
51 	uint32_t busy_pct = calculate_busy_pct(core);
52 
53 	ctx->busy_pct = spdk_max(ctx->busy_pct, busy_pct);
54 }
55 
56 static void
57 balance(struct spdk_scheduler_core_info *cores, uint32_t core_count)
58 {
59 	struct spdk_governor *governor;
60 	struct spdk_scheduler_core_info *core;
61 	struct spdk_governor_capabilities capabilities;
62 	uint32_t busy_pct;
63 	uint32_t i;
64 	int rc;
65 
66 	governor = spdk_governor_get();
67 	assert(governor != NULL);
68 
69 	/* Gather active/idle statistics */
70 	SPDK_ENV_FOREACH_CORE(i) {
71 		struct spdk_cpuset smt_siblings = {};
72 		core = &cores[i];
73 
74 		rc = governor->get_core_capabilities(core->lcore, &capabilities);
75 		if (rc < 0) {
76 			SPDK_ERRLOG("failed to get capabilities for core: %u\n", core->lcore);
77 			return;
78 		}
79 
80 		busy_pct = calculate_busy_pct(core);
81 		if (spdk_env_core_get_smt_cpuset(&smt_siblings, i)) {
82 			struct check_sibling_ctx ctx = {.cores = cores, .busy_pct = busy_pct};
83 
84 			spdk_cpuset_for_each_cpu(&smt_siblings, check_sibling, &ctx);
85 			busy_pct = ctx.busy_pct;
86 		}
87 
88 		if (busy_pct < g_min_threshold) {
89 			rc = governor->set_core_freq_min(core->lcore);
90 			if (rc < 0) {
91 				SPDK_ERRLOG("setting to minimal frequency for core %u failed\n", core->lcore);
92 			}
93 		} else if (busy_pct < g_adjust_threshold) {
94 			rc = governor->core_freq_down(core->lcore);
95 			if (rc < 0) {
96 				SPDK_ERRLOG("lowering frequency for core %u failed\n", core->lcore);
97 			}
98 		} else if (busy_pct >= g_max_threshold) {
99 			rc = governor->set_core_freq_max(core->lcore);
100 			if (rc < 0) {
101 				SPDK_ERRLOG("setting to maximal frequency for core %u failed\n", core->lcore);
102 			}
103 		} else {
104 			rc = governor->core_freq_up(core->lcore);
105 			if (rc < 0) {
106 				SPDK_ERRLOG("increasing frequency for core %u failed\n", core->lcore);
107 			}
108 		}
109 	}
110 }
111 
112 static struct spdk_scheduler gscheduler = {
113 	.name = "gscheduler",
114 	.init = init,
115 	.deinit = deinit,
116 	.balance = balance,
117 };
118 
119 SPDK_SCHEDULER_REGISTER(gscheduler);
120