Line data Source code
1 : /* SPDX-License-Identifier: BSD-3-Clause
2 : * Copyright (C) 2020 Intel Corporation.
3 : * Copyright (C) 2024 Samsung Electronics Co., Ltd.
4 : * All rights reserved.
5 : */
6 :
7 : #include "spdk/stdinc.h"
8 : #include "spdk/likely.h"
9 : #include "spdk/event.h"
10 : #include "spdk/log.h"
11 : #include "spdk/env.h"
12 : #include "spdk/string.h"
13 : #include "spdk/scheduler.h"
14 :
15 : #include "spdk_internal/event.h"
16 : #include "event_internal.h"
17 :
18 : static bool g_first_load = true;
19 :
20 : static int
21 0 : init_static(void)
22 : {
23 0 : if (g_first_load) {
24 : /* There is no scheduling performed by static scheduler,
25 : * do not set the scheduling period. */
26 0 : spdk_scheduler_set_period(0);
27 0 : } else {
28 : /* Schedule a balance to happen immediately, so that
29 : * we can reset each thread's lcore back to its original
30 : * state.
31 : */
32 0 : spdk_scheduler_set_period(1);
33 : }
34 :
35 0 : return 0;
36 : }
37 :
38 : static void
39 0 : deinit_static(void)
40 : {
41 0 : g_first_load = false;
42 0 : }
43 :
44 : static void
45 0 : balance_static(struct spdk_scheduler_core_info *cores, uint32_t core_count)
46 : {
47 0 : struct spdk_scheduler_core_info *core_info;
48 0 : struct spdk_scheduler_thread_info *thread_info;
49 0 : struct spdk_lw_thread *lw_thread;
50 0 : struct spdk_thread *thread;
51 0 : uint32_t i, j;
52 :
53 0 : for (i = 0; i < core_count; i++) {
54 0 : core_info = &cores[i];
55 0 : core_info->interrupt_mode = false;
56 0 : for (j = 0; j < core_info->threads_count; j++) {
57 0 : thread_info = &core_info->thread_infos[j];
58 0 : thread = spdk_thread_get_by_id(thread_info->thread_id);
59 0 : lw_thread = spdk_thread_get_ctx(thread);
60 0 : thread_info->lcore = lw_thread->initial_lcore;
61 0 : }
62 0 : }
63 :
64 : /* We've restored the original state now, so we don't need to
65 : * balance() anymore.
66 : */
67 0 : spdk_scheduler_set_period(0);
68 0 : }
69 :
70 : static const struct spdk_json_object_decoder static_sched_decoders[] = {
71 : {"mappings", 0, spdk_json_decode_string, true},
72 : };
73 :
74 : static int
75 0 : set_opts_static(const struct spdk_json_val *opts)
76 : {
77 0 : char *tok, *mappings = NULL, *copy, *sp = NULL;
78 0 : bool valid;
79 :
80 0 : if (opts != NULL) {
81 0 : if (spdk_json_decode_object_relaxed(opts, static_sched_decoders,
82 : SPDK_COUNTOF(static_sched_decoders),
83 : &mappings)) {
84 0 : SPDK_ERRLOG("Decoding scheduler opts JSON failed\n");
85 0 : return -EINVAL;
86 : }
87 0 : }
88 :
89 0 : if (mappings == NULL) {
90 0 : return 0;
91 : }
92 :
93 0 : copy = strdup(mappings);
94 0 : if (copy == NULL) {
95 0 : free(mappings);
96 0 : return -ENOMEM;
97 : }
98 :
99 0 : valid = true;
100 0 : tok = strtok_r(mappings, ":", &sp);
101 0 : while (tok) {
102 0 : struct spdk_lw_thread *lw_thread = NULL;
103 0 : struct spdk_thread *thread;
104 0 : int thread_id, core;
105 :
106 0 : thread_id = spdk_strtol(tok, 10);
107 0 : if (thread_id > 0) {
108 0 : thread = spdk_thread_get_by_id(thread_id);
109 0 : if (thread != NULL) {
110 0 : lw_thread = spdk_thread_get_ctx(thread);
111 0 : }
112 0 : }
113 0 : if (lw_thread == NULL) {
114 0 : SPDK_ERRLOG("invalid thread ID '%s' in mappings '%s'\n", tok, copy);
115 0 : valid = false;
116 0 : break;
117 : }
118 :
119 0 : tok = strtok_r(NULL, ",", &sp);
120 0 : core = spdk_strtol(tok, 10);
121 0 : if (core < 0 || spdk_reactor_get(core) == NULL) {
122 0 : SPDK_ERRLOG("invalid core number '%s' in mappings '%s'\n", tok, copy);
123 0 : valid = false;
124 0 : break;
125 : }
126 :
127 0 : if (!spdk_cpuset_get_cpu(spdk_thread_get_cpumask(thread), core)) {
128 0 : SPDK_ERRLOG("core %d not in thread %d cpumask\n", core, thread_id);
129 0 : valid = false;
130 0 : break;
131 : }
132 :
133 0 : tok = strtok_r(NULL, ":", &sp);
134 0 : }
135 0 : free(mappings);
136 0 : if (!valid) {
137 0 : free(copy);
138 0 : return -EINVAL;
139 : }
140 :
141 0 : tok = strtok_r(copy, ":", &sp);
142 0 : while (tok) {
143 0 : struct spdk_lw_thread *lw_thread = NULL;
144 0 : struct spdk_thread *thread;
145 0 : int thread_id, core;
146 :
147 0 : thread_id = spdk_strtol(tok, 10);
148 0 : thread = spdk_thread_get_by_id(thread_id);
149 0 : lw_thread = spdk_thread_get_ctx(thread);
150 0 : tok = strtok_r(NULL, ",", &sp);
151 0 : core = spdk_strtol(tok, 10);
152 : /* initial_lcore saves the static scheduler's lcore mapping.
153 : * This is used to restore the previous mapping if we
154 : * change to another scheduler and then back. So we can just
155 : * change the ->initial_lcore here and kick the scheduler to
156 : * put the new mapping into effect.
157 : */
158 0 : lw_thread->initial_lcore = core;
159 0 : tok = strtok_r(NULL, ":", &sp);
160 0 : }
161 0 : free(copy);
162 :
163 : /* We have updated some core placements, so kick the scheduler to
164 : * apply those new placements.
165 : */
166 0 : spdk_scheduler_set_period(1);
167 0 : return 0;
168 0 : }
169 :
170 : static struct spdk_scheduler scheduler = {
171 : .name = "static",
172 : .init = init_static,
173 : .deinit = deinit_static,
174 : .balance = balance_static,
175 : .set_opts = set_opts_static,
176 : };
177 1 : SPDK_SCHEDULER_REGISTER(scheduler);
|