Line | Branch | Exec | Source |
---|---|---|---|
1 | /*********************************************************************************/ | ||
2 | /* Copyright 2009-2024 Barcelona Supercomputing Center */ | ||
3 | /* */ | ||
4 | /* This file is part of the DLB library. */ | ||
5 | /* */ | ||
6 | /* DLB is free software: you can redistribute it and/or modify */ | ||
7 | /* it under the terms of the GNU Lesser General Public License as published by */ | ||
8 | /* the Free Software Foundation, either version 3 of the License, or */ | ||
9 | /* (at your option) any later version. */ | ||
10 | /* */ | ||
11 | /* DLB is distributed in the hope that it will be useful, */ | ||
12 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ | ||
13 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ | ||
14 | /* GNU Lesser General Public License for more details. */ | ||
15 | /* */ | ||
16 | /* You should have received a copy of the GNU Lesser General Public License */ | ||
17 | /* along with DLB. If not, see <https://www.gnu.org/licenses/>. */ | ||
18 | /*********************************************************************************/ | ||
19 | |||
20 | #include "LB_policies/lewi_mask.h" | ||
21 | |||
22 | #include "LB_core/spd.h" | ||
23 | #include "LB_comm/shmem_cpuinfo.h" | ||
24 | #include "LB_comm/shmem_async.h" | ||
25 | #include "apis/dlb_errors.h" | ||
26 | #include "support/debug.h" | ||
27 | #include "support/gslist.h" | ||
28 | #include "support/mask_utils.h" | ||
29 | #include "support/small_array.h" | ||
30 | #include "support/types.h" | ||
31 | |||
32 | #include <sched.h> | ||
33 | #include <stdlib.h> | ||
34 | #include <string.h> | ||
35 | #include <pthread.h> | ||
36 | |||
37 | /* array_cpuid_t */ | ||
38 | #define ARRAY_T cpuid_t | ||
39 | #include "support/array_template.h" | ||
40 | |||
41 | /* array_cpuinfo_task_t */ | ||
42 | #define ARRAY_T cpuinfo_task_t | ||
43 | #define ARRAY_KEY_T pid_t | ||
44 | #include "support/array_template.h" | ||
45 | |||
46 | |||
47 | /* Node size will be the same for all processes in the node, | ||
48 | * it is safe to be out of the shared memory */ | ||
49 | static int node_size = -1; | ||
50 | |||
51 | /* LeWI_mask data is private for each process */ | ||
52 | typedef struct LeWI_mask_info { | ||
53 | int64_t last_borrow; | ||
54 | int max_parallelism; | ||
55 | array_cpuid_t cpus_priority_array; | ||
56 | cpu_set_t pending_reclaimed_cpus; /* CPUs that become reclaimed after an MPI */ | ||
57 | cpu_set_t in_mpi_cpus; /* CPUs inside an MPI call */ | ||
58 | GSList *cpuid_arrays; /* thread-private pointers to free at finalize */ | ||
59 | GSList *cpuinfo_task_arrays; /* thread-private pointers to free at finalize */ | ||
60 | pthread_mutex_t mutex; /* Mutex to protect lewi_info */ | ||
61 | } lewi_info_t; | ||
62 | |||
63 | |||
64 | /* Compute the common elements between a cpuid array a cpu_set: | ||
65 | * cpuid_t *result = cpuid_t *op1 AND cpu_set_t *op2 | ||
66 | * (cpu_set_t* may be NULL, meaning neutral value) | ||
67 | */ | ||
68 | 72 | static inline void cpu_array_and(array_cpuid_t *result, | |
69 | const array_cpuid_t *op1, const cpu_set_t *op2) { | ||
70 |
2/2✓ Branch 0 taken 612 times.
✓ Branch 1 taken 72 times.
|
684 | for (unsigned int i = 0; i < op1->count; ++i) { |
71 |
7/8✓ Branch 0 taken 144 times.
✓ Branch 1 taken 468 times.
✓ Branch 2 taken 144 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 88 times.
✓ Branch 5 taken 56 times.
✓ Branch 6 taken 88 times.
✓ Branch 7 taken 56 times.
|
612 | if (op2 == NULL || CPU_ISSET(op1->items[i], op2)) { |
72 | 556 | array_cpuid_t_push(result, op1->items[i]); | |
73 | } | ||
74 | } | ||
75 | 72 | } | |
76 | |||
77 | /* Construct a cpuid array from a cpu_set_t */ | ||
78 | 4 | static inline void cpu_array_from_cpuset(array_cpuid_t *result, | |
79 | const cpu_set_t *cpu_set) { | ||
80 | 4 | for (int cpuid = mu_get_first_cpu(cpu_set); | |
81 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
8 | cpuid >= 0; |
82 | 4 | cpuid = mu_get_next_cpu(cpu_set, cpuid)) { | |
83 | 4 | array_cpuid_t_push(result, cpuid); | |
84 | } | ||
85 | 4 | } | |
86 | |||
87 | |||
88 | /* Construct a priority list of CPUs considering the topology and the affinity mask */ | ||
89 | 23 | static void lewi_mask_UpdateOwnershipInfo(const subprocess_descriptor_t *spd, | |
90 | const cpu_set_t *process_mask) { | ||
91 | |||
92 | 23 | lewi_info_t *lewi_info = spd->lewi_info; | |
93 | 23 | lewi_affinity_t lewi_affinity = spd->options.lewi_affinity; | |
94 | |||
95 | cpu_set_t affinity_mask; | ||
96 | 23 | mu_get_nodes_intersecting_with_cpuset(&affinity_mask, process_mask); | |
97 | |||
98 | /* Reset current priority array */ | ||
99 | 23 | array_cpuid_t *cpus_priority_array = &lewi_info->cpus_priority_array; | |
100 | 23 | array_cpuid_t_clear(cpus_priority_array); | |
101 | |||
102 | /* First, construct a list of potentially available CPUs | ||
103 | * (owned + nearby, depending on the affinity policy) */ | ||
104 | cpu_set_t system_mask; | ||
105 | 23 | mu_get_system_mask(&system_mask); | |
106 | 23 | for (int cpuid = mu_get_first_cpu(&system_mask); | |
107 |
2/2✓ Branch 0 taken 368 times.
✓ Branch 1 taken 23 times.
|
391 | cpuid >= 0; |
108 | 368 | cpuid = mu_get_next_cpu(&system_mask, cpuid)) { | |
109 |
5/6✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 140 times.
✓ Branch 3 taken 228 times.
✓ Branch 4 taken 140 times.
✓ Branch 5 taken 228 times.
|
368 | if (CPU_ISSET(cpuid, process_mask)) { |
110 | 140 | array_cpuid_t_push(cpus_priority_array, cpuid); | |
111 | } else { | ||
112 |
1/5✓ Branch 0 taken 228 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
228 | switch (lewi_affinity) { |
113 | 228 | case LEWI_AFFINITY_AUTO: | |
114 | case LEWI_AFFINITY_MASK: | ||
115 | case LEWI_AFFINITY_NEARBY_FIRST: | ||
116 | 228 | array_cpuid_t_push(cpus_priority_array, cpuid); | |
117 | 228 | break; | |
118 | ✗ | case LEWI_AFFINITY_NEARBY_ONLY: | |
119 | ✗ | if (CPU_ISSET(cpuid, &affinity_mask)) { | |
120 | ✗ | array_cpuid_t_push(cpus_priority_array, cpuid); | |
121 | } | ||
122 | ✗ | break; | |
123 | ✗ | case LEWI_AFFINITY_SPREAD_IFEMPTY: | |
124 | // This case cannot be pre-computed | ||
125 | ✗ | break; | |
126 | ✗ | case LEWI_AFFINITY_NONE: | |
127 | /* LEWI_AFFINITY_NONE should force LeWI without mask support */ | ||
128 | ✗ | fatal("Unhandled LEWI_AFFINITY_NONE in LeWI mask. " | |
129 | "Please report bug"); | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | |||
134 | /* Sort available CPUs according to the affinity */ | ||
135 | cpu_set_t affinity[3]; | ||
136 | 23 | memcpy(&affinity[0], process_mask, sizeof(cpu_set_t)); | |
137 | 23 | memcpy(&affinity[1], &affinity_mask, sizeof(cpu_set_t)); | |
138 | 23 | CPU_ZERO(&affinity[2]); | |
139 | 23 | qsort_r(cpus_priority_array->items, cpus_priority_array->count, | |
140 | sizeof(cpuid_t), mu_cmp_cpuids_by_affinity, &affinity); | ||
141 | 23 | } | |
142 | |||
143 | |||
144 | /*********************************************************************************/ | ||
145 | /* Thread-local pointers for temporary storage during LeWI calls */ | ||
146 | /*********************************************************************************/ | ||
147 | |||
148 | /* Array of eligible CPUs. Usually a subset of the CPUs priority array. */ | ||
149 | static __thread array_cpuid_t _cpu_subset = {}; | ||
150 | |||
151 | 76 | static inline array_cpuid_t* get_cpu_subset(const subprocess_descriptor_t *spd) { | |
152 | /* Thread already has an allocated array, return it */ | ||
153 |
2/2✓ Branch 0 taken 67 times.
✓ Branch 1 taken 9 times.
|
76 | if (likely(_cpu_subset.items != NULL)) { |
154 | 67 | array_cpuid_t_clear(&_cpu_subset); | |
155 | 67 | return &_cpu_subset; | |
156 | } | ||
157 | |||
158 | /* Otherwise, allocate */ | ||
159 | 9 | array_cpuid_t_init(&_cpu_subset, node_size); | |
160 | |||
161 | /* Add pointer to lewi_info to deallocate later */ | ||
162 | 9 | lewi_info_t *lewi_info = spd->lewi_info; | |
163 | 9 | pthread_mutex_lock(&lewi_info->mutex); | |
164 | { | ||
165 | 9 | lewi_info->cpuid_arrays = | |
166 | 9 | g_slist_prepend(lewi_info->cpuid_arrays, &_cpu_subset); | |
167 | } | ||
168 | 9 | pthread_mutex_unlock(&lewi_info->mutex); | |
169 | |||
170 | 9 | return &_cpu_subset; | |
171 | } | ||
172 | |||
173 | /* Array of cpuinfo tasks. For enabling or disabling CPUs. */ | ||
174 | static __thread array_cpuinfo_task_t _tasks = {}; | ||
175 | |||
176 | 218 | static inline array_cpuinfo_task_t* get_tasks(const subprocess_descriptor_t *spd) { | |
177 | /* Thread already has an allocated array, return it */ | ||
178 |
2/2✓ Branch 0 taken 195 times.
✓ Branch 1 taken 23 times.
|
218 | if (likely(_tasks.items != NULL)) { |
179 | 195 | array_cpuinfo_task_t_clear(&_tasks); | |
180 | 195 | return &_tasks; | |
181 | } | ||
182 | |||
183 | /* Otherwise, allocate */ | ||
184 | 23 | array_cpuinfo_task_t_init(&_tasks, node_size*2); | |
185 | |||
186 | /* Add pointer to lewi_info to deallocate later */ | ||
187 | 23 | lewi_info_t *lewi_info = spd->lewi_info; | |
188 | 23 | pthread_mutex_lock(&lewi_info->mutex); | |
189 | { | ||
190 | 23 | lewi_info->cpuinfo_task_arrays = | |
191 | 23 | g_slist_prepend(lewi_info->cpuinfo_task_arrays, &_tasks); | |
192 | } | ||
193 | 23 | pthread_mutex_unlock(&lewi_info->mutex); | |
194 | |||
195 | 23 | return &_tasks; | |
196 | } | ||
197 | |||
198 | |||
199 | /*********************************************************************************/ | ||
200 | /* Resolve cpuinfo tasks */ | ||
201 | /*********************************************************************************/ | ||
202 | |||
203 | 122 | static void resolve_cpuinfo_tasks(const subprocess_descriptor_t *restrict spd, | |
204 | array_cpuinfo_task_t *restrict tasks) { | ||
205 | |||
206 | 122 | size_t tasks_count = tasks->count; | |
207 | |||
208 | /* We don't need it strictly sorted, but if there are 3 or more tasks | ||
209 | * we need to group them by pid */ | ||
210 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 105 times.
|
122 | if (tasks_count > 2 ) { |
211 | 17 | array_cpuinfo_task_t_sort(tasks); | |
212 | } | ||
213 | |||
214 | /* Iterate tasks by group of PIDs */ | ||
215 |
2/2✓ Branch 0 taken 114 times.
✓ Branch 1 taken 122 times.
|
236 | for (size_t i=0; i<tasks_count; ) { |
216 | |||
217 | /* count how many times this PID is repeated */ | ||
218 | 114 | size_t j = i+1; | |
219 | 114 | while (j < tasks_count | |
220 |
4/4✓ Branch 0 taken 68 times.
✓ Branch 1 taken 98 times.
✓ Branch 2 taken 52 times.
✓ Branch 3 taken 16 times.
|
166 | && tasks->items[j].pid == tasks->items[i].pid) { |
221 | 52 | ++j; | |
222 | } | ||
223 | 114 | size_t num_tasks = j - i; | |
224 | |||
225 |
2/2✓ Branch 0 taken 77 times.
✓ Branch 1 taken 37 times.
|
114 | if (num_tasks == 1) { |
226 | /* resolve single task */ | ||
227 | 77 | const cpuinfo_task_t *task = &tasks->items[i]; | |
228 |
2/2✓ Branch 0 taken 70 times.
✓ Branch 1 taken 7 times.
|
77 | if (task->pid == spd->id) { |
229 |
2/2✓ Branch 0 taken 55 times.
✓ Branch 1 taken 15 times.
|
70 | if (task->action == ENABLE_CPU) { |
230 | 55 | enable_cpu(&spd->pm, task->cpuid); | |
231 | } | ||
232 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | else if (task->action == DISABLE_CPU) { |
233 | 15 | disable_cpu(&spd->pm, task->cpuid); | |
234 | } | ||
235 | } | ||
236 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
|
7 | else if (spd->options.mode == MODE_ASYNC) { |
237 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (task->action == ENABLE_CPU) { |
238 | ✗ | shmem_async_enable_cpu(task->pid, task->cpuid); | |
239 | } | ||
240 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | else if (task->action == DISABLE_CPU) { |
241 | 1 | shmem_async_disable_cpu(task->pid, task->cpuid); | |
242 | 1 | shmem_cpuinfo__return_async_cpu(task->pid, task->cpuid); | |
243 | } | ||
244 | } | ||
245 | } else { | ||
246 | /* group tasks */ | ||
247 | 37 | cpu_set_t cpus_to_enable = {}; | |
248 | 37 | cpu_set_t cpus_to_disable = {}; | |
249 |
2/2✓ Branch 0 taken 89 times.
✓ Branch 1 taken 37 times.
|
126 | for (size_t k = i; k < i+num_tasks; ++k) { |
250 | 89 | const cpuinfo_task_t *task = &tasks->items[k]; | |
251 |
2/2✓ Branch 0 taken 65 times.
✓ Branch 1 taken 24 times.
|
89 | if (task->action == ENABLE_CPU) { |
252 |
1/2✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
|
65 | CPU_SET(task->cpuid, &cpus_to_enable); |
253 | } | ||
254 |
1/2✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
|
24 | else if (task->action == DISABLE_CPU) { |
255 |
1/2✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
|
24 | CPU_SET(task->cpuid, &cpus_to_disable); |
256 | } | ||
257 | } | ||
258 | |||
259 | /* resolve group of tasks for the same PID */ | ||
260 | 37 | const cpuinfo_task_t *task = &tasks->items[i]; | |
261 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 9 times.
|
37 | if (task->pid == spd->id) { |
262 |
2/2✓ Branch 1 taken 25 times.
✓ Branch 2 taken 3 times.
|
28 | if (CPU_COUNT(&cpus_to_enable) > 0) { |
263 | 25 | enable_cpu_set(&spd->pm, &cpus_to_enable); | |
264 | } | ||
265 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 25 times.
|
28 | if (CPU_COUNT(&cpus_to_disable) > 0) { |
266 | 3 | disable_cpu_set(&spd->pm, &cpus_to_disable); | |
267 | } | ||
268 | } | ||
269 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | else if (spd->options.mode == MODE_ASYNC) { |
270 | ✗ | if (CPU_COUNT(&cpus_to_enable) > 0) { | |
271 | ✗ | shmem_async_enable_cpu_set(task->pid, &cpus_to_enable); | |
272 | } | ||
273 | ✗ | if (CPU_COUNT(&cpus_to_disable) > 0) { | |
274 | ✗ | shmem_async_disable_cpu_set(task->pid, &cpus_to_disable); | |
275 | ✗ | shmem_cpuinfo__return_async_cpu_mask(task->pid, &cpus_to_disable); | |
276 | } | ||
277 | } | ||
278 | } | ||
279 | |||
280 | 114 | i += num_tasks; | |
281 | } | ||
282 | 122 | } | |
283 | |||
284 | |||
285 | /*********************************************************************************/ | ||
286 | /* Init / Finalize */ | ||
287 | /*********************************************************************************/ | ||
288 | |||
289 | 23 | int lewi_mask_Init(subprocess_descriptor_t *spd) { | |
290 | /* Value is always updated to allow testing different node sizes */ | ||
291 | 23 | node_size = mu_get_system_size(); | |
292 | |||
293 | /* Allocate and initialize private structure */ | ||
294 | 23 | spd->lewi_info = malloc(sizeof(lewi_info_t)); | |
295 | 23 | lewi_info_t *lewi_info = spd->lewi_info; | |
296 | 23 | *lewi_info = (const lewi_info_t) { | |
297 | 23 | .max_parallelism = spd->options.lewi_max_parallelism, | |
298 | .mutex = PTHREAD_MUTEX_INITIALIZER, | ||
299 | }; | ||
300 | 23 | array_cpuid_t_init(&lewi_info->cpus_priority_array, node_size); | |
301 | 23 | lewi_mask_UpdateOwnershipInfo(spd, &spd->process_mask); | |
302 | |||
303 | /* Enable request queues only in async mode */ | ||
304 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if (spd->options.mode == MODE_ASYNC) { |
305 | 5 | shmem_cpuinfo__enable_request_queues(); | |
306 | } | ||
307 | |||
308 | 23 | return DLB_SUCCESS; | |
309 | } | ||
310 | |||
311 | 23 | int lewi_mask_Finalize(subprocess_descriptor_t *spd) { | |
312 | /* De-register subprocess from the shared memory */ | ||
313 | 23 | array_cpuinfo_task_t *tasks = get_tasks(spd); | |
314 | 23 | int error = shmem_cpuinfo__deregister(spd->id, tasks); | |
315 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (error == DLB_SUCCESS) { |
316 | 23 | resolve_cpuinfo_tasks(spd, tasks); | |
317 | } | ||
318 | |||
319 | /* Deallocate thread private arrays */ | ||
320 | 23 | lewi_info_t *lewi_info = spd->lewi_info; | |
321 | 23 | pthread_mutex_lock(&lewi_info->mutex); | |
322 | { | ||
323 | 23 | for (GSList *node = lewi_info->cpuid_arrays; | |
324 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 23 times.
|
32 | node != NULL; |
325 | 9 | node = node->next) { | |
326 | 9 | array_cpuid_t *array = node->data; | |
327 | 9 | array_cpuid_t_destroy(array); | |
328 | } | ||
329 | 23 | g_slist_free(lewi_info->cpuid_arrays); | |
330 | |||
331 | 23 | for (GSList *node = lewi_info->cpuinfo_task_arrays; | |
332 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
|
46 | node != NULL; |
333 | 23 | node = node->next) { | |
334 | 23 | array_cpuid_t *array = node->data; | |
335 | 23 | array_cpuid_t_destroy(array); | |
336 | } | ||
337 | 23 | g_slist_free(lewi_info->cpuinfo_task_arrays); | |
338 | } | ||
339 | 23 | pthread_mutex_unlock(&lewi_info->mutex); | |
340 | |||
341 | |||
342 | /* Deallocate private structure */ | ||
343 | 23 | array_cpuid_t_destroy(&lewi_info->cpus_priority_array); | |
344 | 23 | free(lewi_info); | |
345 | 23 | lewi_info = NULL; | |
346 | |||
347 | 23 | return (error >= 0) ? DLB_SUCCESS : error; | |
348 | } | ||
349 | |||
350 | |||
351 | /*********************************************************************************/ | ||
352 | /* LeWI Modes (enable/disable, max_parallelism, ...) */ | ||
353 | /*********************************************************************************/ | ||
354 | |||
355 | 2 | int lewi_mask_EnableDLB(const subprocess_descriptor_t *spd) { | |
356 | /* Reset value of last_borrow */ | ||
357 | 2 | ((lewi_info_t*)spd->lewi_info)->last_borrow = 0; | |
358 | 2 | return DLB_SUCCESS; | |
359 | } | ||
360 | |||
361 | 2 | int lewi_mask_DisableDLB(const subprocess_descriptor_t *spd) { | |
362 | 2 | array_cpuinfo_task_t *tasks = get_tasks(spd); | |
363 | 2 | int error = shmem_cpuinfo__reset(spd->id, tasks); | |
364 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (error == DLB_SUCCESS) { |
365 | 2 | resolve_cpuinfo_tasks(spd, tasks); | |
366 | } | ||
367 | 2 | return error; | |
368 | } | ||
369 | |||
370 | 2 | int lewi_mask_SetMaxParallelism(const subprocess_descriptor_t *spd, int max) { | |
371 | 2 | int error = DLB_SUCCESS; | |
372 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (max > 0) { |
373 | 2 | lewi_info_t *lewi_info = spd->lewi_info; | |
374 | 2 | lewi_info->max_parallelism = max; | |
375 | 2 | array_cpuinfo_task_t *tasks = get_tasks(spd); | |
376 | 2 | error = shmem_cpuinfo__update_max_parallelism(spd->id, max, tasks); | |
377 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (error == DLB_SUCCESS) { |
378 | 2 | resolve_cpuinfo_tasks(spd, tasks); | |
379 | } | ||
380 | } | ||
381 | 2 | return error; | |
382 | } | ||
383 | |||
384 | 2 | int lewi_mask_UnsetMaxParallelism(const subprocess_descriptor_t *spd) { | |
385 | 2 | lewi_info_t *lewi_info = spd->lewi_info; | |
386 | 2 | lewi_info->max_parallelism = 0; | |
387 | 2 | return DLB_SUCCESS; | |
388 | } | ||
389 | |||
390 | |||
391 | /*********************************************************************************/ | ||
392 | /* MPI */ | ||
393 | /*********************************************************************************/ | ||
394 | |||
395 | /* Obtain thread mask and remove first core if keep_cpu_on_blocking_call */ | ||
396 | 10 | static inline void get_mask_for_blocking_call( | |
397 | cpu_set_t *cpu_set, bool keep_cpu_on_blocking_call) { | ||
398 | |||
399 | /* Obtain current thread's affinity mask */ | ||
400 | 10 | pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), cpu_set); | |
401 | |||
402 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
|
10 | if (keep_cpu_on_blocking_call) { |
403 | /* Remove the first core */ | ||
404 | 2 | int first_cpuid = mu_get_first_cpu(cpu_set); | |
405 | 2 | const mu_cpuset_t *first_core = mu_get_core_mask(first_cpuid); | |
406 | 2 | mu_substract(cpu_set, cpu_set, first_core->set); | |
407 | } | ||
408 | 10 | } | |
409 | |||
410 | /* Lend the CPUs of the thread encountering the blocking call */ | ||
411 | 5 | int lewi_mask_IntoBlockingCall(const subprocess_descriptor_t *spd) { | |
412 | 5 | int error = DLB_NOUPDT; | |
413 | |||
414 | /* Obtain affinity mask to lend */ | ||
415 | cpu_set_t cpu_set; | ||
416 | 5 | get_mask_for_blocking_call(&cpu_set, | |
417 | 5 | spd->options.lewi_keep_cpu_on_blocking_call); | |
418 | |||
419 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 times.
|
5 | if (mu_count(&cpu_set) > 0) { |
420 | #ifdef DEBUG_VERSION | ||
421 | /* Add cpu_set to in_mpi_cpus */ | ||
422 | 4 | lewi_info_t *lewi_info = spd->lewi_info; | |
423 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | fatal_cond(mu_intersects(&lewi_info->in_mpi_cpus, &cpu_set), |
424 | "Some CPU in %s already into blocking call", mu_to_str(&cpu_set)); | ||
425 | 4 | mu_or(&lewi_info->in_mpi_cpus, &lewi_info->in_mpi_cpus, &cpu_set); | |
426 | #endif | ||
427 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | verbose(VB_MICROLB, "In blocking call, lending %s", mu_to_str(&cpu_set)); |
428 | |||
429 | /* Finally, lend mask */ | ||
430 | 4 | error = lewi_mask_LendCpuMask(spd, &cpu_set); | |
431 | } | ||
432 | 5 | return error; | |
433 | } | ||
434 | |||
435 | /* Reclaim the CPUs that were lent when encountering the blocking call. | ||
436 | * The thread must have not change its affinity mask since then. */ | ||
437 | 5 | int lewi_mask_OutOfBlockingCall(const subprocess_descriptor_t *spd) { | |
438 | 5 | int error = DLB_NOUPDT; | |
439 | |||
440 | /* Obtain affinity mask to reclaim */ | ||
441 | cpu_set_t cpu_set; | ||
442 | 5 | get_mask_for_blocking_call(&cpu_set, | |
443 | 5 | spd->options.lewi_keep_cpu_on_blocking_call); | |
444 | |||
445 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 times.
|
5 | if (mu_count(&cpu_set) > 0) { |
446 | 4 | lewi_info_t *lewi_info = spd->lewi_info; | |
447 | #ifdef DEBUG_VERSION | ||
448 | /* Clear cpu_set from in_mpi_cpus */ | ||
449 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | fatal_cond(!mu_is_subset(&lewi_info->in_mpi_cpus, &cpu_set), |
450 | "Some CPU in %s is not into blocking call", mu_to_str(&cpu_set)); | ||
451 | 4 | mu_substract(&lewi_info->in_mpi_cpus, &lewi_info->in_mpi_cpus, &cpu_set); | |
452 | #endif | ||
453 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | verbose(VB_MICROLB, "Out of blocking call, acquiring %s", mu_to_str(&cpu_set)); |
454 | |||
455 | /* If there are owned CPUs to reclaim: */ | ||
456 | cpu_set_t owned_cpus; | ||
457 | 4 | mu_and(&owned_cpus, &cpu_set, &spd->process_mask); | |
458 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
|
4 | if (mu_count(&owned_cpus) > 0) { |
459 | |||
460 | /* Construct a CPU array from owned_cpus */ | ||
461 | 2 | array_cpuid_t *cpu_subset = get_cpu_subset(spd); | |
462 | 2 | cpu_array_from_cpuset(cpu_subset, &owned_cpus); | |
463 | |||
464 | /* Acquire CPUs, but do not call any enable CPU callback */ | ||
465 | 2 | array_cpuinfo_task_t *tasks = get_tasks(spd); | |
466 | 2 | error = shmem_cpuinfo__acquire_from_cpu_subset(spd->id, cpu_subset, tasks); | |
467 | |||
468 | /* Once CPUs are acquired from the shmem, we don't need to call | ||
469 | * any ENABLE callback because they weren't disabled in IntoBlockingCall. | ||
470 | * Only if asynchronous mode, keep DISABLE tasks, otherwise remove all. */ | ||
471 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (error == DLB_NOTED |
472 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | && spd->options.mode == MODE_ASYNC) { |
473 | ✗ | for (size_t i = 0, i_write = 0; i < tasks->count; ++i) { | |
474 | ✗ | const cpuinfo_task_t *task = &tasks->items[i]; | |
475 | ✗ | if (task->action == DISABLE_CPU) { | |
476 | ✗ | if (i != i_write) { | |
477 | ✗ | tasks->items[i_write] = tasks->items[i]; | |
478 | } | ||
479 | ✗ | ++i_write; | |
480 | } | ||
481 | } | ||
482 | /* Async: resolve only DISABLE tasks */ | ||
483 | ✗ | resolve_cpuinfo_tasks(spd, tasks); | |
484 | } else { | ||
485 | /* Polling: clear tasks */ | ||
486 | 2 | array_cpuinfo_task_t_clear(tasks); | |
487 | } | ||
488 | } | ||
489 | |||
490 | /* If there are ONLY non-owned CPUs to reclaim: | ||
491 | * (if some owned CPU was already reclaimed, we forget about non-owned) */ | ||
492 | cpu_set_t non_owned_cpus; | ||
493 | 4 | mu_substract(&non_owned_cpus, &cpu_set, &spd->process_mask); | |
494 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
|
4 | if (mu_count(&non_owned_cpus) > 0 |
495 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | && mu_count(&owned_cpus) == 0) { |
496 | |||
497 | /* Construct a CPU array from non_owned_cpus */ | ||
498 | 2 | array_cpuid_t *cpu_subset = get_cpu_subset(spd); | |
499 | 2 | cpu_array_from_cpuset(cpu_subset, &non_owned_cpus); | |
500 | |||
501 | /* Borrow CPUs, but also ignoring the enable callbacks */ | ||
502 | 2 | array_cpuinfo_task_t *tasks = get_tasks(spd); | |
503 | 2 | error = shmem_cpuinfo__borrow_from_cpu_subset(spd->id, cpu_subset, tasks); | |
504 | |||
505 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (error != DLB_SUCCESS) { |
506 | /* Annotate the CPU as pending to bypass the shared memory for the next query */ | ||
507 | 1 | mu_or(&lewi_info->pending_reclaimed_cpus, &lewi_info->pending_reclaimed_cpus, | |
508 | &non_owned_cpus); | ||
509 | |||
510 | /* We lost the CPU while in MPI. | ||
511 | * In async mode, we can just disable the CPU. | ||
512 | * In polling mode, the process needs to call Return */ | ||
513 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (spd->options.mode == MODE_ASYNC) { |
514 | ✗ | disable_cpu_set(&spd->pm, &non_owned_cpus); | |
515 | } | ||
516 | } | ||
517 | } | ||
518 | } | ||
519 | |||
520 | 5 | return error; | |
521 | } | ||
522 | |||
523 | |||
524 | /*********************************************************************************/ | ||
525 | /* Lend */ | ||
526 | /*********************************************************************************/ | ||
527 | |||
528 | ✗ | int lewi_mask_Lend(const subprocess_descriptor_t *spd) { | |
529 | cpu_set_t mask; | ||
530 | ✗ | mu_get_system_mask(&mask); | |
531 | ✗ | return lewi_mask_LendCpuMask(spd, &mask); | |
532 | } | ||
533 | |||
534 | 43 | int lewi_mask_LendCpu(const subprocess_descriptor_t *spd, int cpuid) { | |
535 | 43 | array_cpuinfo_task_t *tasks = get_tasks(spd); | |
536 | 43 | int error = shmem_cpuinfo__lend_cpu(spd->id, cpuid, tasks); | |
537 | |||
538 |
1/2✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
|
43 | if (error == DLB_SUCCESS) { |
539 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 39 times.
|
43 | if (spd->options.mode == MODE_ASYNC) { |
540 | 4 | resolve_cpuinfo_tasks(spd, tasks); | |
541 | } | ||
542 | |||
543 | /* Clear possible pending reclaimed CPUs */ | ||
544 | 43 | lewi_info_t *lewi_info = spd->lewi_info; | |
545 |
1/2✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
|
43 | CPU_CLR(cpuid, &lewi_info->pending_reclaimed_cpus); |
546 | } | ||
547 | 43 | return error; | |
548 | } | ||
549 | |||
550 | 21 | int lewi_mask_LendCpuMask(const subprocess_descriptor_t *spd, const cpu_set_t *mask) { | |
551 | 21 | array_cpuinfo_task_t *tasks = get_tasks(spd); | |
552 | 21 | int error = shmem_cpuinfo__lend_cpu_mask(spd->id, mask, tasks); | |
553 |
1/2✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
|
21 | if (error == DLB_SUCCESS) { |
554 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (spd->options.mode == MODE_ASYNC) { |
555 | ✗ | resolve_cpuinfo_tasks(spd, tasks); | |
556 | } | ||
557 | |||
558 | /* Clear possible pending reclaimed CPUs */ | ||
559 | 21 | lewi_info_t *lewi_info = spd->lewi_info; | |
560 | 21 | mu_substract(&lewi_info->pending_reclaimed_cpus, | |
561 | 21 | &lewi_info->pending_reclaimed_cpus, mask); | |
562 | } | ||
563 | 21 | return error; | |
564 | } | ||
565 | |||
566 | |||
567 | /*********************************************************************************/ | ||
568 | /* Reclaim */ | ||
569 | /*********************************************************************************/ | ||
570 | |||
571 | 2 | int lewi_mask_Reclaim(const subprocess_descriptor_t *spd) { | |
572 | /* Even though shmem_cpuinfo__reclaim_all exists, | ||
573 | * iterating the mask should be more efficient */ | ||
574 | 2 | return lewi_mask_ReclaimCpuMask(spd, &spd->process_mask); | |
575 | } | ||
576 | |||
577 | 5 | int lewi_mask_ReclaimCpu(const subprocess_descriptor_t *spd, int cpuid) { | |
578 | 5 | array_cpuinfo_task_t *tasks = get_tasks(spd); | |
579 | 5 | int error = shmem_cpuinfo__reclaim_cpu(spd->id, cpuid, tasks); | |
580 |
4/4✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 times.
|
5 | if (error == DLB_SUCCESS || error == DLB_NOTED) { |
581 | 4 | resolve_cpuinfo_tasks(spd, tasks); | |
582 | } | ||
583 | 5 | return error; | |
584 | } | ||
585 | |||
586 | ✗ | int lewi_mask_ReclaimCpus(const subprocess_descriptor_t *spd, int ncpus) { | |
587 | ✗ | array_cpuinfo_task_t *tasks = get_tasks(spd); | |
588 | ✗ | int error = shmem_cpuinfo__reclaim_cpus(spd->id, ncpus, tasks); | |
589 | ✗ | if (error == DLB_SUCCESS || error == DLB_NOTED) { | |
590 | ✗ | resolve_cpuinfo_tasks(spd, tasks); | |
591 | } | ||
592 | ✗ | return error; | |
593 | } | ||
594 | |||
595 | 8 | int lewi_mask_ReclaimCpuMask(const subprocess_descriptor_t *spd, const cpu_set_t *mask) { | |
596 | 8 | array_cpuinfo_task_t *tasks = get_tasks(spd); | |
597 | 8 | int error = shmem_cpuinfo__reclaim_cpu_mask(spd->id, mask, tasks); | |
598 | 8 | resolve_cpuinfo_tasks(spd, tasks); | |
599 | 8 | return error; | |
600 | } | ||
601 | |||
602 | |||
603 | /*********************************************************************************/ | ||
604 | /* Acquire */ | ||
605 | /*********************************************************************************/ | ||
606 | |||
607 | 18 | int lewi_mask_AcquireCpu(const subprocess_descriptor_t *spd, int cpuid) { | |
608 | 18 | array_cpuinfo_task_t *tasks = get_tasks(spd); | |
609 | 18 | int error = shmem_cpuinfo__acquire_cpu(spd->id, cpuid, tasks); | |
610 |
4/4✓ Branch 0 taken 7 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 4 times.
|
18 | if (error == DLB_SUCCESS || error == DLB_NOTED) { |
611 | 14 | resolve_cpuinfo_tasks(spd, tasks); | |
612 | } | ||
613 | 18 | return error; | |
614 | } | ||
615 | |||
616 | 38 | int lewi_mask_AcquireCpus(const subprocess_descriptor_t *spd, int ncpus) { | |
617 | 38 | int error = DLB_NOUPDT; | |
618 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 36 times.
|
38 | if (ncpus == 0) { |
619 | /* AcquireCPUs(0) has a special meaning of removing any previous request */ | ||
620 | 2 | shmem_cpuinfo__remove_requests(spd->id); | |
621 | 2 | error = DLB_SUCCESS; | |
622 |
1/2✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
|
36 | } else if (ncpus > 0) { |
623 | 36 | error = lewi_mask_AcquireCpusInMask(spd, ncpus, NULL); | |
624 | } | ||
625 | 38 | return error; | |
626 | } | ||
627 | |||
628 | 10 | int lewi_mask_AcquireCpuMask(const subprocess_descriptor_t *spd, const cpu_set_t *mask) { | |
629 | 10 | return lewi_mask_AcquireCpusInMask(spd, 0, mask); | |
630 | } | ||
631 | |||
632 | 57 | int lewi_mask_AcquireCpusInMask(const subprocess_descriptor_t *spd, int ncpus, | |
633 | const cpu_set_t *mask) { | ||
634 | 57 | lewi_info_t *lewi_info = spd->lewi_info; | |
635 | 57 | bool async = spd->options.mode == MODE_ASYNC; | |
636 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
|
57 | int64_t *last_borrow = async ? NULL : &lewi_info->last_borrow; |
637 | |||
638 | /* Construct a CPU array based on cpus_priority_array and mask (if present) */ | ||
639 | 57 | array_cpuid_t *cpu_subset = get_cpu_subset(spd); | |
640 | 57 | cpu_array_and(cpu_subset, &lewi_info->cpus_priority_array, mask); | |
641 | |||
642 | /* Provide a number of requested CPUs only if needed */ | ||
643 |
2/2✓ Branch 0 taken 47 times.
✓ Branch 1 taken 10 times.
|
57 | int *requested_ncpus = ncpus > 0 ? &ncpus : NULL; |
644 | |||
645 | 57 | array_cpuinfo_task_t *tasks = get_tasks(spd); | |
646 | 57 | int error = shmem_cpuinfo__acquire_ncpus_from_cpu_subset(spd->id, | |
647 | 57 | requested_ncpus, cpu_subset, spd->options.lewi_affinity, | |
648 | lewi_info->max_parallelism, last_borrow, tasks); | ||
649 | |||
650 |
2/2✓ Branch 0 taken 37 times.
✓ Branch 1 taken 20 times.
|
57 | if (error != DLB_NOUPDT) { |
651 | 37 | resolve_cpuinfo_tasks(spd, tasks); | |
652 | } | ||
653 | 57 | return error; | |
654 | } | ||
655 | |||
656 | |||
657 | /*********************************************************************************/ | ||
658 | /* Borrow */ | ||
659 | /*********************************************************************************/ | ||
660 | |||
661 | 4 | int lewi_mask_Borrow(const subprocess_descriptor_t *spd) { | |
662 | cpu_set_t system_mask; | ||
663 | 4 | mu_get_system_mask(&system_mask); | |
664 | 4 | return lewi_mask_BorrowCpusInMask(spd, 0, &system_mask); | |
665 | } | ||
666 | |||
667 | 5 | int lewi_mask_BorrowCpu(const subprocess_descriptor_t *spd, int cpuid) { | |
668 | 5 | array_cpuinfo_task_t *tasks = get_tasks(spd); | |
669 | 5 | int error = shmem_cpuinfo__borrow_cpu(spd->id, cpuid, tasks); | |
670 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | if (error == DLB_SUCCESS) { |
671 | 5 | resolve_cpuinfo_tasks(spd, tasks); | |
672 | } | ||
673 | 5 | return error; | |
674 | } | ||
675 | |||
676 | 7 | int lewi_mask_BorrowCpus(const subprocess_descriptor_t *spd, int ncpus) { | |
677 | 7 | return lewi_mask_BorrowCpusInMask(spd, ncpus, NULL); | |
678 | } | ||
679 | |||
680 | ✗ | int lewi_mask_BorrowCpuMask(const subprocess_descriptor_t *spd, const cpu_set_t *mask) { | |
681 | ✗ | return lewi_mask_BorrowCpusInMask(spd, 0, mask); | |
682 | } | ||
683 | |||
684 | 15 | int lewi_mask_BorrowCpusInMask(const subprocess_descriptor_t *spd, int ncpus, const cpu_set_t *mask) { | |
685 | 15 | lewi_info_t *lewi_info = spd->lewi_info; | |
686 | 15 | bool async = spd->options.mode == MODE_ASYNC; | |
687 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | int64_t *last_borrow = async ? NULL : &lewi_info->last_borrow; |
688 | |||
689 | /* Construct a CPU array based on cpus_priority_array and mask (if present) */ | ||
690 | 15 | array_cpuid_t *cpu_subset = get_cpu_subset(spd); | |
691 | 15 | cpu_array_and(cpu_subset, &lewi_info->cpus_priority_array, mask); | |
692 | |||
693 | /* Provide a number of requested CPUs only if needed */ | ||
694 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 4 times.
|
15 | int *requested_ncpus = ncpus > 0 ? &ncpus : NULL; |
695 | |||
696 | 15 | array_cpuinfo_task_t *tasks = get_tasks(spd); | |
697 | 15 | int error = shmem_cpuinfo__borrow_ncpus_from_cpu_subset(spd->id, | |
698 | 15 | requested_ncpus, cpu_subset, spd->options.lewi_affinity, | |
699 | lewi_info->max_parallelism, last_borrow, tasks); | ||
700 | |||
701 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 6 times.
|
15 | if (error == DLB_SUCCESS) { |
702 | 9 | resolve_cpuinfo_tasks(spd, tasks); | |
703 | } | ||
704 | |||
705 | 15 | return error; | |
706 | } | ||
707 | |||
708 | |||
709 | /*********************************************************************************/ | ||
710 | /* Return */ | ||
711 | /*********************************************************************************/ | ||
712 | |||
713 | 1 | int lewi_mask_Return(const subprocess_descriptor_t *spd) { | |
714 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (spd->options.mode == MODE_ASYNC) { |
715 | // Return should not be called in async mode | ||
716 | ✗ | return DLB_ERR_NOCOMP; | |
717 | } | ||
718 | |||
719 | 1 | array_cpuinfo_task_t *tasks = get_tasks(spd); | |
720 | 1 | int error = shmem_cpuinfo__return_all(spd->id, tasks); | |
721 | 1 | resolve_cpuinfo_tasks(spd, tasks); | |
722 | |||
723 | /* Check possible pending reclaimed CPUs */ | ||
724 | 1 | lewi_info_t *lewi_info = spd->lewi_info; | |
725 | 1 | int cpuid = mu_get_first_cpu(&lewi_info->pending_reclaimed_cpus); | |
726 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (cpuid >= 0) { |
727 | do { | ||
728 | ✗ | disable_cpu(&spd->pm, cpuid); | |
729 | ✗ | cpuid = mu_get_next_cpu(&lewi_info->pending_reclaimed_cpus, cpuid); | |
730 | ✗ | } while (cpuid >= 0); | |
731 | ✗ | CPU_ZERO(&lewi_info->pending_reclaimed_cpus); | |
732 | ✗ | error = DLB_SUCCESS; | |
733 | } | ||
734 | |||
735 | 1 | return error; | |
736 | } | ||
737 | |||
738 | 14 | int lewi_mask_ReturnCpu(const subprocess_descriptor_t *spd, int cpuid) { | |
739 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (spd->options.mode == MODE_ASYNC) { |
740 | // Return should not be called in async mode | ||
741 | ✗ | return DLB_ERR_NOCOMP; | |
742 | } | ||
743 | |||
744 | 14 | array_cpuinfo_task_t *tasks = get_tasks(spd); | |
745 | 14 | int error = shmem_cpuinfo__return_cpu(spd->id, cpuid, tasks); | |
746 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
14 | if (error == DLB_SUCCESS || error == DLB_ERR_REQST) { |
747 | 13 | resolve_cpuinfo_tasks(spd, tasks); | |
748 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | } else if (error == DLB_ERR_PERM) { |
749 | /* Check possible pending reclaimed CPUs */ | ||
750 | 1 | lewi_info_t *lewi_info = spd->lewi_info; | |
751 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | if (CPU_ISSET(cpuid, &lewi_info->pending_reclaimed_cpus)) { |
752 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | CPU_CLR(cpuid, &lewi_info->pending_reclaimed_cpus); |
753 | 1 | disable_cpu(&spd->pm, cpuid); | |
754 | 1 | error = DLB_SUCCESS; | |
755 | } | ||
756 | } | ||
757 | 14 | return error; | |
758 | } | ||
759 | |||
760 | ✗ | int lewi_mask_ReturnCpuMask(const subprocess_descriptor_t *spd, const cpu_set_t *mask) { | |
761 | ✗ | if (spd->options.mode == MODE_ASYNC) { | |
762 | // Return should not be called in async mode | ||
763 | ✗ | return DLB_ERR_NOCOMP; | |
764 | } | ||
765 | |||
766 | ✗ | array_cpuinfo_task_t *tasks = get_tasks(spd); | |
767 | ✗ | int error = shmem_cpuinfo__return_cpu_mask(spd->id, mask, tasks); | |
768 | ✗ | resolve_cpuinfo_tasks(spd, tasks); | |
769 | |||
770 | /* Check possible pending reclaimed CPUs */ | ||
771 | ✗ | lewi_info_t *lewi_info = spd->lewi_info; | |
772 | ✗ | if (CPU_COUNT(&lewi_info->pending_reclaimed_cpus) > 0) { | |
773 | cpu_set_t cpus_to_return; | ||
774 | ✗ | CPU_AND(&cpus_to_return, &lewi_info->pending_reclaimed_cpus, mask); | |
775 | ✗ | for (int cpuid = mu_get_first_cpu(&cpus_to_return); cpuid >= 0; | |
776 | ✗ | cpuid = mu_get_next_cpu(&cpus_to_return, cpuid)) { | |
777 | ✗ | disable_cpu(&spd->pm, cpuid); | |
778 | } | ||
779 | ✗ | mu_substract(&lewi_info->pending_reclaimed_cpus, | |
780 | ✗ | &lewi_info->pending_reclaimed_cpus, &cpus_to_return); | |
781 | ✗ | error = DLB_SUCCESS; | |
782 | } | ||
783 | |||
784 | ✗ | return error; | |
785 | } | ||
786 | |||
787 | |||
788 | // Others | ||
789 | |||
790 | 32 | int lewi_mask_CheckCpuAvailability(const subprocess_descriptor_t *spd, int cpuid) { | |
791 | 32 | return shmem_cpuinfo__check_cpu_availability(spd->id, cpuid); | |
792 | } | ||
793 | |||
794 | ✗ | int lewi_mask_UpdateOwnership(const subprocess_descriptor_t *spd, | |
795 | const cpu_set_t *process_mask) { | ||
796 | /* Update priority array */ | ||
797 | ✗ | lewi_mask_UpdateOwnershipInfo(spd, process_mask); | |
798 | |||
799 | /* Update cpuinfo data and return reclaimed CPUs */ | ||
800 | ✗ | array_cpuinfo_task_t *tasks = get_tasks(spd); | |
801 | ✗ | shmem_cpuinfo__update_ownership(spd->id, process_mask, tasks); | |
802 | ✗ | resolve_cpuinfo_tasks(spd, tasks); | |
803 | |||
804 | /* Check possible pending reclaimed CPUs */ | ||
805 | ✗ | lewi_info_t *lewi_info = spd->lewi_info; | |
806 | ✗ | int cpuid = mu_get_first_cpu(&lewi_info->pending_reclaimed_cpus); | |
807 | ✗ | if (cpuid >= 0) { | |
808 | do { | ||
809 | ✗ | disable_cpu(&spd->pm, cpuid); | |
810 | ✗ | cpuid = mu_get_next_cpu(&lewi_info->pending_reclaimed_cpus, cpuid); | |
811 | ✗ | } while (cpuid >= 0); | |
812 | ✗ | CPU_ZERO(&lewi_info->pending_reclaimed_cpus); | |
813 | } | ||
814 | |||
815 | ✗ | return DLB_SUCCESS; | |
816 | } | ||
817 |