Branch data 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 : 943 : init_static(void)
22 : : {
23 [ + + + + ]: 943 : if (g_first_load) {
24 : : /* There is no scheduling performed by static scheduler,
25 : : * do not set the scheduling period. */
26 : 942 : spdk_scheduler_set_period(0);
27 : 69 : } 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 : 1 : spdk_scheduler_set_period(1);
33 : : }
34 : :
35 : 943 : return 0;
36 : : }
37 : :
38 : : static void
39 : 943 : deinit_static(void)
40 : : {
41 : 943 : g_first_load = false;
42 : 943 : }
43 : :
44 : : static void
45 : 2 : balance_static(struct spdk_scheduler_core_info *cores, uint32_t core_count)
46 : : {
47 : : struct spdk_scheduler_core_info *core_info;
48 : : struct spdk_scheduler_thread_info *thread_info;
49 : : struct spdk_lw_thread *lw_thread;
50 : : struct spdk_thread *thread;
51 : : uint32_t i, j;
52 : :
53 [ + + ]: 84 : for (i = 0; i < core_count; i++) {
54 [ # # ]: 82 : core_info = &cores[i];
55 [ # # # # ]: 82 : core_info->interrupt_mode = false;
56 [ + + # # : 116 : for (j = 0; j < core_info->threads_count; j++) {
# # ]
57 [ # # # # : 34 : thread_info = &core_info->thread_infos[j];
# # ]
58 [ # # # # ]: 34 : thread = spdk_thread_get_by_id(thread_info->thread_id);
59 : 34 : lw_thread = spdk_thread_get_ctx(thread);
60 [ # # # # : 34 : 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 : 2 : spdk_scheduler_set_period(0);
68 : 2 : }
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 : 45 : set_opts_static(const struct spdk_json_val *opts)
76 : : {
77 : 45 : char *tok, *mappings = NULL, *copy;
78 : : bool valid;
79 : :
80 [ + + ]: 45 : if (opts != NULL) {
81 [ - + ]: 45 : 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 : 3 : }
88 : :
89 [ + + ]: 45 : if (mappings == NULL) {
90 : 44 : return 0;
91 : : }
92 : :
93 [ - + ]: 1 : copy = strdup(mappings);
94 [ - + ]: 1 : if (copy == NULL) {
95 : 0 : free(mappings);
96 : 0 : return -ENOMEM;
97 : : }
98 : :
99 : 1 : valid = true;
100 [ - + ]: 1 : tok = strtok(mappings, ":");
101 [ + + ]: 2 : while (tok) {
102 : 1 : struct spdk_lw_thread *lw_thread = NULL;
103 : : struct spdk_thread *thread;
104 : : int thread_id, core;
105 : :
106 : 1 : thread_id = spdk_strtol(tok, 10);
107 [ + - ]: 1 : if (thread_id > 0) {
108 : 1 : thread = spdk_thread_get_by_id(thread_id);
109 [ + - ]: 1 : if (thread != NULL) {
110 : 1 : lw_thread = spdk_thread_get_ctx(thread);
111 : 0 : }
112 : 0 : }
113 [ - + ]: 1 : 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 [ - + ]: 1 : tok = strtok(NULL, ",");
120 : 1 : core = spdk_strtol(tok, 10);
121 [ + - - + ]: 1 : 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 [ - + ]: 1 : 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 [ - + ]: 1 : tok = strtok(NULL, ":");
134 : : }
135 : 1 : free(mappings);
136 [ - + # # ]: 1 : if (!valid) {
137 : 0 : free(copy);
138 : 0 : return -EINVAL;
139 : : }
140 : :
141 [ - + ]: 1 : tok = strtok(copy, ":");
142 [ + + ]: 2 : while (tok) {
143 : 1 : struct spdk_lw_thread *lw_thread = NULL;
144 : : struct spdk_thread *thread;
145 : : int thread_id, core;
146 : :
147 : 1 : thread_id = spdk_strtol(tok, 10);
148 : 1 : thread = spdk_thread_get_by_id(thread_id);
149 : 1 : lw_thread = spdk_thread_get_ctx(thread);
150 [ - + ]: 1 : tok = strtok(NULL, ",");
151 : 1 : 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 [ # # # # ]: 1 : lw_thread->initial_lcore = core;
159 [ - + ]: 1 : tok = strtok(NULL, ":");
160 : : }
161 : 1 : free(copy);
162 : :
163 : : /* We have updated some core placements, so kick the scheduler to
164 : : * apply those new placements.
165 : : */
166 : 1 : spdk_scheduler_set_period(1);
167 : 1 : return 0;
168 : 3 : }
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 : 2403 : SPDK_SCHEDULER_REGISTER(scheduler);
|