GCC Code Coverage Report


Directory: src/
File: src/support/options.c
Date: 2025-11-21 10:34:40
Exec Total Coverage
Lines: 382 468 81.6%
Functions: 14 14 100.0%
Branches: 194 264 73.5%

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 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include "support/options.h"
25
26 #include "apis/dlb_types.h"
27 #include "apis/dlb_errors.h"
28 #include "support/types.h"
29 #include "support/mask_utils.h"
30 #include "support/debug.h"
31 #include "LB_core/spd.h"
32
33 #include <string.h>
34 #include <stddef.h>
35 #include <ctype.h>
36 #include <stdint.h>
37 #include <limits.h>
38
39 typedef enum OptionFlags {
40 OPT_CLEAR = 0,
41 OPT_READONLY = 1 << 0,
42 OPT_OPTIONAL = 1 << 1,
43 OPT_DEPRECATED = 1 << 2,
44 OPT_ADVANCED = 1 << 3,
45 OPT_HIDDEN = 1 << 4,
46 OPT_UNUSED = 1 << 5
47 } option_flags_t;
48
49 typedef enum OptionTypes {
50 OPT_BOOL_T,
51 OPT_NEG_BOOL_T,
52 OPT_INT_T,
53 OPT_STR_T,
54 OPT_PTR_PATH_T, // pointer to char[PATH_MAX]
55 OPT_VB_T, // verbose_opts_t
56 OPT_VBFMT_T, // verbose_fmt_t
57 OPT_INST_T, // instrument_items_t
58 OPT_DBG_T, // debug_opts_t
59 OPT_LEWI_AFF_T, // lewi_affinity_t
60 OPT_MASK_T, // cpu_set_t
61 OPT_MODE_T, // interaction_mode_t
62 OPT_MPISET_T, // mpi_set_t
63 OPT_OMPTOPTS_T, // omptool_opts_t
64 OPT_TLPSUM_T, // talp_summary_t
65 OPT_TLPMOD_T, // talp_model_t
66 OPT_OMPTM_T // omptm_version_t
67 } option_type_t;
68
69 typedef struct {
70 char var_name[MAX_OPTION_LENGTH]; // LB_OPTION
71 char arg_name[MAX_OPTION_LENGTH]; // --option
72 char default_value[MAX_OPTION_LENGTH];
73 char description[MAX_DESCRIPTION];
74 size_t offset;
75 option_type_t type;
76 option_flags_t flags;
77 } opts_dict_t;
78
79 /* Description is displaced 4 spaces */
80 #define OFFSET " "
81 static const opts_dict_t options_dictionary[] = {
82 // general options
83 {
84 .var_name = "LB_LEWI",
85 .arg_name = "--lewi",
86 .default_value = "no",
87 .description = OFFSET"Enable Lend When Idle. Processes using this mode can use LeWI\n"
88 OFFSET"API to lend and borrow resources.",
89 .offset = offsetof(options_t, lewi),
90 .type = OPT_BOOL_T,
91 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
92 }, {
93 .var_name = "LB_DROM",
94 .arg_name = "--drom",
95 .default_value = "no",
96 .description = OFFSET"Enable the Dynamic Resource Ownership Manager Module. Processes\n"
97 OFFSET"using this mode can receive requests from other processes to\n"
98 OFFSET"change its own process mask.",
99 .offset = offsetof(options_t, drom),
100 .type = OPT_BOOL_T,
101 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
102 }, {
103 .var_name = "LB_TALP",
104 .arg_name = "--talp",
105 .default_value = "no",
106 .description = OFFSET"Enable the TALP (Tracking Application Live Performance)\n"
107 OFFSET"module. Processes that enable this mode can obtain performance\n"
108 OFFSET"metrics at run time.",
109 .offset = offsetof(options_t, talp),
110 .type = OPT_BOOL_T,
111 .flags = (option_flags_t)(OPT_OPTIONAL)
112 },{
113 .var_name = "LB_BARRIER",
114 .arg_name = "--barrier",
115 .default_value = "yes",
116 .description = OFFSET"Enable the Shared Memory Barrier. Processes can perform\n"
117 OFFSET"intra-node barriers.",
118 .offset = offsetof(options_t, barrier),
119 .type = OPT_BOOL_T,
120 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
121 }, {
122 .var_name = "LB_NULL",
123 .arg_name = "--ompt",
124 .default_value = "no",
125 .description = OFFSET"Enable OpenMP performance tool. If running with an OMPT capable\n"
126 OFFSET"runtime, DLB can register itself as OpenMP Tool and perform\n"
127 OFFSET"some tasks, like thread pinning reallocation when the process\n"
128 OFFSET"mask changes or some LeWI features if enabled.",
129 .offset = offsetof(options_t, ompt),
130 .type = OPT_BOOL_T,
131 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
132 }, {
133 .var_name = "LB_MODE",
134 .arg_name = "--mode",
135 .default_value = "polling",
136 .description = OFFSET"Set interaction mode between DLB and the application. In polling\n"
137 OFFSET"mode, each process needs to poll DLB to acquire resources. In\n"
138 OFFSET"async mode, DLB creates a helper thread to call back the\n"
139 OFFSET"application when resources become available.",
140 .offset = offsetof(options_t, mode),
141 .type = OPT_MODE_T,
142 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
143 },
144 // verbose
145 {
146 .var_name = "LB_NULL",
147 .arg_name = "--quiet",
148 .default_value = "no",
149 .description = OFFSET"Suppress VERBOSE and INFO messages from DLB, still shows\n"
150 OFFSET"WARNING and PANIC messages.",
151 .offset = offsetof(options_t, quiet),
152 .type = OPT_BOOL_T,
153 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
154 }, {
155 .var_name = "LB_NULL",
156 .arg_name = "--silent",
157 .default_value = "no",
158 .description = OFFSET"Suppress all output from DLB, even error messages.",
159 .offset = offsetof(options_t, silent),
160 .type = OPT_BOOL_T,
161 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
162 }, {
163 .var_name = "LB_VERBOSE",
164 .arg_name = "--verbose",
165 .default_value = "no",
166 .description = OFFSET"Select which verbose components will be printed. Multiple\n"
167 OFFSET"components may be selected.",
168 .offset = offsetof(options_t, verbose),
169 .type = OPT_VB_T,
170 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
171 }, {
172 .var_name = "LB_VERBOSE_FORMAT",
173 .arg_name = "--verbose-format",
174 .default_value = "node:spid",
175 .description = OFFSET"Set the verbose format for the verbose messages. Multiple\n"
176 OFFSET"components may be selected but the order is predefined as\n"
177 OFFSET"shown in the possible values.",
178 .offset = offsetof(options_t, verbose_fmt),
179 .type = OPT_VBFMT_T,
180 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
181 },
182 // instrument
183 {
184 .var_name = "LB_NULL",
185 .arg_name = "--instrument",
186 .default_value = "all",
187 .description = OFFSET"Enable Extrae instrumentation. This option requires the\n"
188 OFFSET"instrumented DLB library and the Extrae library. If both\n"
189 OFFSET"conditions are met, DLB will emit events such as the DLB\n"
190 OFFSET"calls, DLB modes, etc.",
191 .offset = offsetof(options_t, instrument),
192 .type = OPT_INST_T,
193 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
194 }, {
195 .var_name = "LB_NULL",
196 .arg_name = "--instrument-counters",
197 .default_value = "no",
198 .description = OFFSET"Enable counters on DLB events. If this option is enabled, DLB\n"
199 OFFSET"will emit events to Extrae with hardware counters information.\n"
200 OFFSET"This may significantly increase the size of the tracefile.",
201 .offset = offsetof(options_t, instrument_counters),
202 .type = OPT_BOOL_T,
203 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
204 }, {
205 .var_name = "LB_NULL",
206 .arg_name = "--instrument-extrae-nthreads",
207 .default_value = "0",
208 .description = OFFSET"Invoke Extrae_change_num_threads with the provided parameter\n"
209 OFFSET"at the start of the execution to pre-allocate a buffer per\n"
210 OFFSET"thread.",
211 .offset = offsetof(options_t, instrument_extrae_nthreads),
212 .type = OPT_INT_T,
213 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL | OPT_ADVANCED)
214 },
215 // LeWI
216 {
217 .var_name = "LB_NULL",
218 .arg_name = "--lewi-keep-one-cpu",
219 .default_value = "no",
220 .description = OFFSET"Whether the CPU of the thread that encounters a blocking call\n"
221 OFFSET"(MPI blocking call or DLB_Barrier) is also lent in the LeWI policy.\n"
222 OFFSET"This flag replaces the option --lewi-mpi, although negated.",
223 .offset = offsetof(options_t, lewi_keep_cpu_on_blocking_call),
224 .type = OPT_BOOL_T,
225 .flags = (option_flags_t)(OPT_OPTIONAL)
226 }, {
227 .var_name = "LB_NULL",
228 .arg_name = "--lewi-respect-cpuset",
229 .default_value = "yes",
230 .description = OFFSET"Whether to respect the set of CPUs registered in DLB to\n"
231 OFFSET"use with LeWI. If disabled, all unknown CPUs are available\n"
232 OFFSET"for any process to borrow.",
233 .offset = offsetof(options_t, lewi_respect_cpuset),
234 .type = OPT_BOOL_T,
235 .flags = (option_flags_t)(OPT_OPTIONAL)
236 }, {
237 .var_name = "LB_NULL",
238 .arg_name = "--lewi-respect-mask",
239 .default_value = "yes",
240 .description = OFFSET"Deprecated in favor of --lewi-respect-cpuset.\n",
241 .offset = offsetof(options_t, lewi_respect_cpuset),
242 .type = OPT_BOOL_T,
243 .flags = (option_flags_t)(OPT_OPTIONAL | OPT_DEPRECATED)
244 }, {
245 /* This is a deprecated option that overlaps with --lewi-keep-one-cpu.
246 * It must be defined afterwards so that the default value of the
247 * previous option does not overwrite this one */
248 .var_name = "LB_NULL",
249 .arg_name = "--lewi-mpi",
250 .default_value = "no",
251 .description = OFFSET"This option is now deprecated, but its previous behavior is now\n"
252 OFFSET"enabled by default.\n"
253 OFFSET"If you want to lend a CPU when in a blocking call, you may safely\n"
254 OFFSET"remove this option.\n"
255 OFFSET"If you want to keep this CPU, use --lewi-keep-one-cpu instead.",
256 .offset = offsetof(options_t, lewi_keep_cpu_on_blocking_call),
257 .type = OPT_NEG_BOOL_T,
258 .flags = (option_flags_t)(OPT_OPTIONAL | OPT_DEPRECATED)
259 }, {
260 .var_name = "LB_NULL",
261 .arg_name = "--lewi-mpi-calls",
262 .default_value = "all",
263 .description = OFFSET"Select which type of MPI calls will make LeWI to lend their\n"
264 OFFSET"CPUs. If set to all, LeWI will act on all blocking MPI calls,\n"
265 OFFSET"If set to other values, only those types will trigger LeWI.",
266 .offset = offsetof(options_t, lewi_mpi_calls),
267 .type = OPT_MPISET_T,
268 .flags = (option_flags_t)(OPT_OPTIONAL)
269 }, {
270 .var_name = "LB_NULL",
271 .arg_name = "--lewi-barrier",
272 .default_value = "yes",
273 .description = OFFSET"Select whether DLB_Barrier calls (unnamed barriers only) will\n"
274 OFFSET"activate LeWI and lend their CPUs. Named barriers can be\n"
275 OFFSET"configured individually in the source code, or using the\n"
276 OFFSET"--lewi-barrier-select.",
277 .offset = offsetof(options_t, lewi_barrier),
278 .type = OPT_BOOL_T,
279 .flags = (option_flags_t)(OPT_OPTIONAL | OPT_READONLY)
280 }, {
281 .var_name = "LB_NULL",
282 .arg_name = "--lewi-barrier-select",
283 .default_value = "",
284 .description = OFFSET"Comma separated values of barrier names that will activate\n"
285 OFFSET"LeWI. Warning: by setting this option to any non-blank value,\n"
286 OFFSET"the option --lewi-barrier is ignored. Use 'default' to also\n"
287 OFFSET"control the default unnamed barrier.\n"
288 OFFSET"e.g.: --lewi-barrier-select=default,barrier3",
289 .offset = offsetof(options_t, lewi_barrier_select),
290 .type = OPT_STR_T,
291 .flags = (option_flags_t)(OPT_OPTIONAL | OPT_READONLY | OPT_ADVANCED)
292 }, {
293 .var_name = "LB_NULL",
294 .arg_name = "--lewi-affinity",
295 .default_value = "auto",
296 .description = OFFSET"Select which affinity policy to use.\n"
297 OFFSET"With 'auto', DLB will infer the LeWI policy for either classic\n"
298 OFFSET"(no mask support) or LeWI_mask depending on a number of factors.\n"
299 OFFSET"To override the automatic detection, use either 'none' or 'mask'\n"
300 OFFSET"to select the respective policy.\n"
301 OFFSET"The tokens 'nearby-first', 'nearby-only', and 'spread-ifempty'\n"
302 OFFSET"also enforce mask support with extended policies.\n"
303 OFFSET"'nearby-first' is the default policy when LeWI has mask support\n"
304 OFFSET"and will instruct LeWI to assign resources that share the same\n"
305 OFFSET"socket or NUMA node with the current process first, then the\n"
306 OFFSET"rest.\n"
307 OFFSET"'nearby-only' will make LeWI assign only those resources that\n"
308 OFFSET"are near the process.\n"
309 OFFSET"'spread-ifempty' will also prioritise nearby resources, but the\n"
310 OFFSET"rest will only be considered if all CPUs in that socket or NUMA\n"
311 OFFSET"node has been lent to DLB.",
312 .offset = offsetof(options_t, lewi_affinity),
313 .type = OPT_LEWI_AFF_T,
314 .flags = (option_flags_t)(OPT_OPTIONAL)
315 }, {
316 .var_name = "LB_NULL",
317 .arg_name = "--lewi-ompt",
318 .default_value = "borrow",
319 .description = OFFSET"OMPT option flags for LeWI. If OMPT mode is enabled, set when\n"
320 OFFSET"DLB can automatically invoke LeWI functions to lend or borrow\n"
321 OFFSET"CPUs. If 'none' is set, LeWI will not be invoked automatically.\n"
322 OFFSET"If 'borrow' is set, DLB will try to borrow CPUs in certain\n"
323 OFFSET"situations; typically, before non nested parallel constructs if\n"
324 OFFSET"the OMPT thread manager is omp5 and on each task creation and\n"
325 OFFSET"task switch in other thread managers. (This option is the default\n"
326 OFFSET"and should be enough in most of the cases). If the flag 'lend'\n"
327 OFFSET"is set, DLB will lend all non used CPUs after each non nested\n"
328 OFFSET"parallel construct and task completion on external threads.\n"
329 OFFSET"Multiple flags can be selected at the same time.",
330 .offset = offsetof(options_t, lewi_ompt),
331 .type = OPT_OMPTOPTS_T,
332 .flags = (option_flags_t)(OPT_OPTIONAL)
333 }, {
334 .var_name = "LB_NULL",
335 .arg_name = "--lewi-greedy",
336 .default_value = "no",
337 .description = OFFSET"Greedy option for LeWI policy.",
338 .offset = offsetof(options_t, lewi_greedy),
339 .type = OPT_BOOL_T,
340 .flags = (option_flags_t)(OPT_OPTIONAL)
341 }, {
342 .var_name = "LB_NULL",
343 .arg_name = "--lewi-warmup",
344 .default_value = "no",
345 .description = OFFSET"Create as many threads as necessary during the process startup.",
346 .offset = offsetof(options_t, lewi_warmup),
347 .type = OPT_BOOL_T,
348 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
349 }, {
350 .var_name = "LB_NULL",
351 .arg_name = "--lewi-max-parallelism",
352 .default_value = "0",
353 .description = OFFSET"Set the maximum level of parallelism for the LeWI algorithm.",
354 .offset = offsetof(options_t, lewi_max_parallelism),
355 .type = OPT_INT_T,
356 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
357 }, {
358 .var_name = "LB_NULL",
359 .arg_name = "--lewi-color",
360 .default_value = "0",
361 .description = OFFSET"Set the LeWI color of the process, allowing the creation of\n"
362 OFFSET"different disjoint subgroups for resource sharing. Processes\n"
363 OFFSET"will only share resources with other processes of the same color.",
364 .offset = offsetof(options_t, lewi_color),
365 .type = OPT_INT_T,
366 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
367 },
368 // talp
369 {
370 .var_name = "LB_NULL",
371 .arg_name = "--talp-openmp",
372 .default_value = "no",
373 .description = OFFSET"Select whether to measure OpenMP metrics. (Experimental)",
374 .offset = offsetof(options_t, talp_openmp),
375 .type = OPT_BOOL_T,
376 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
377 },
378 {
379 .var_name = "LB_NULL",
380 .arg_name = "--talp-papi",
381 .default_value = "no",
382 .description = OFFSET"Select whether to collect PAPI counters.",
383 .offset = offsetof(options_t, talp_papi),
384 .type = OPT_BOOL_T,
385 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
386 },
387 {
388 .var_name = "LB_TALP_SUMM",
389 .arg_name = "--talp-summary",
390 .default_value = "pop-metrics",
391 .description = OFFSET"Report TALP metrics at the end of the execution. If\n"
392 OFFSET"'--talp-output-file' is not specified, a short summary is\n"
393 OFFSET"printed. Otherwise, a more verbose file will be generated\n"
394 OFFSET"with all the metrics collected by TALP, depending on the list\n"
395 OFFSET"of requested summaries, separated by ':':\n"
396 OFFSET"'pop-metrics', the default option, will report a subset of\n"
397 OFFSET"the POP metrics.\n"
398 OFFSET"'process' will report the measurements of each process for\n"
399 OFFSET"each registered region.\n"
400 OFFSET"\n"
401 OFFSET"Deprecated options:\n"
402 OFFSET"'pop-raw' will be removed in the next release. The output \n"
403 OFFSET"will be available using the 'pop-metrics' summary.\n"
404 OFFSET"'node' will be removed in the next release. Its data may\n"
405 OFFSET"be derived from the 'process' report.",
406 .offset = offsetof(options_t, talp_summary),
407 .type = OPT_TLPSUM_T,
408 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
409 },
410 {
411 .var_name = "LB_NULL",
412 .arg_name = "--talp-output-file",
413 .default_value = "",
414 .description = OFFSET"Write extended TALP metrics to a file. If this option is\n"
415 OFFSET"omitted, the output is printed to stderr.\n"
416 OFFSET"The accepted formats are JSON and CSV, which are selected\n"
417 OFFSET"using the file extensions *.json and *.csv, respectively.\n"
418 OFFSET"Any other file extension will result in plain text output.\n"
419 OFFSET"\n"
420 OFFSET"Deprecated formats:\n"
421 OFFSET"The *.xml file extension is deprecated and will be removed in\n"
422 OFFSET"the next release.",
423 .offset = offsetof(options_t, talp_output_file),
424 .type = OPT_PTR_PATH_T,
425 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
426 },
427 {
428 /* In the future, consider using an interval update timer instead of a boolean */
429 .var_name = "LB_NULL",
430 .arg_name = "--talp-external-profiler",
431 .default_value = "no",
432 .description = OFFSET"Enable live metrics update to the shared memory. This flag\n"
433 OFFSET"is only needed if there is an external program monitoring\n"
434 OFFSET"the application.",
435 .offset = offsetof(options_t, talp_external_profiler),
436 .type = OPT_BOOL_T,
437 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
438 },
439 {
440 .var_name = "LB_NULL",
441 .arg_name = "--talp-regions-per-proc",
442 .default_value = "100",
443 .description = OFFSET"Number of TALP regions per process to allocate in the shared\n"
444 OFFSET"memory.\n"
445 OFFSET"Deprecated: use --shmem-size-multiplier instead.\n",
446 .offset = offsetof(options_t, talp_regions_per_proc),
447 .type = OPT_INT_T,
448 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL | OPT_DEPRECATED)
449 },
450 {
451 .var_name = "LB_NULL",
452 .arg_name = "--talp-region-select",
453 .default_value = "",
454 .description = OFFSET"Select TALP regions to enable. This option follows the format:\n"
455 OFFSET" --talp-region-select=[(include|exclude):]<region-list>\n"
456 OFFSET"\n"
457 OFFSET"The modifiers 'include:' and 'exclude:' are optional, but only\n"
458 OFFSET"one modifier can be used at a time. If neither is specified,\n"
459 OFFSET"'include:' is assumed by default.\n"
460 OFFSET"\n"
461 OFFSET"The '<region-list>' can be a comma-separared list of regions\n"
462 OFFSET"or a special token 'all' to refer to all regions. The global\n"
463 OFFSET"monitoring region may be specified with the special token\n"
464 OFFSET"'global'. If the modifier 'include:' is used, only the listed\n"
465 OFFSET"regions will be enabled. If 'exclude:' is used, all regions\n"
466 OFFSET"will be enabled except for the ones specified.\n"
467 OFFSET"\n"
468 OFFSET"Note that when using this feature, listed regions must not have\n"
469 OFFSET"spaces in their names.\n"
470 OFFSET"\n"
471 OFFSET"e.g.: --talp-region-select=all (default)\n"
472 OFFSET" --talp-region-select=exclude:all\n"
473 OFFSET" --talp-region-select=include:global,region3\n"
474 OFFSET" --talp-region-select=exclude:region4",
475 .offset = offsetof(options_t, talp_region_select),
476 .type = OPT_STR_T,
477 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
478 },
479 {
480 .var_name = "LB_NULL",
481 .arg_name = "--talp-model",
482 .default_value = "hybrid-v2",
483 .description = OFFSET"For development use only.\n"
484 OFFSET"Select which version of POP metrics to compute.",
485 .offset = offsetof(options_t, talp_model),
486 .type = OPT_TLPMOD_T,
487 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL | OPT_ADVANCED)
488 },
489 // barrier
490 {
491 .var_name = "LB_NULL",
492 .arg_name = "--barrier-id",
493 .default_value = "0",
494 .description = OFFSET"Barrier ID. Use different barrier id numbers for different\n"
495 OFFSET"processes to avoid unwanted synchronization.",
496 .offset = offsetof(options_t, barrier_id),
497 .type = OPT_INT_T,
498 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL | OPT_ADVANCED)
499 },
500 // misc
501 {
502 .var_name = "LB_SHM_KEY",
503 .arg_name = "--shm-key",
504 .default_value = "",
505 .description = OFFSET"Shared Memory key. By default, if key is empty, all processes\n"
506 OFFSET"will use a shared memory based on the user ID. If different\n"
507 OFFSET"processes start their execution with different keys, they will\n"
508 OFFSET"use different shared memories and they will not share resources.",
509 .offset = offsetof(options_t, shm_key),
510 .type = OPT_STR_T,
511 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL | OPT_ADVANCED)
512 }, {
513 .var_name = "LB_NULL",
514 .arg_name = "--shm-size-multiplier",
515 .default_value = "1",
516 .description = OFFSET"DLB allocates its shared memory at the start of execution, with\n"
517 OFFSET"its size based on the number of CPUs in the node. If you\n"
518 OFFSET"encounter a DLB_ERR_NOMEM error, you can adjust the multiplier\n"
519 OFFSET"to increase the shared memory size. As a reference, with the\n"
520 OFFSET"default multiplier, the typical shared memory size on HPC\n"
521 OFFSET"machines is under 10 megabytes, so keep that in mind if you\n"
522 OFFSET"increase its size to allocate more running processes or TALP\n"
523 OFFSET"regions.",
524 .offset = offsetof(options_t, shm_size_multiplier),
525 .type = OPT_INT_T,
526 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL | OPT_ADVANCED)
527 }, {
528 .var_name = "LB_PREINIT_PID",
529 .arg_name = "--preinit-pid",
530 .default_value = "0",
531 .description = OFFSET"Process ID that pre-initializes the DLB process for DROM.",
532 .offset = offsetof(options_t, preinit_pid),
533 .type = OPT_INT_T,
534 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL | OPT_HIDDEN)
535 }, {
536 .var_name = "LB_NULL",
537 .arg_name = "--ompt-thread-manager",
538 .default_value = "omp5",
539 .description = OFFSET"OMPT Thread Manager version.",
540 .offset = offsetof(options_t, omptm_version),
541 .type = OPT_OMPTM_T,
542 .flags = (option_flags_t)(OPT_OPTIONAL)
543 }, {
544 .var_name = "LB_NULL",
545 .arg_name = "--plugin",
546 .default_value = "",
547 .description = OFFSET"Select plugin to enable.\n"
548 OFFSET"For now, only 'cupti' and 'rocprofilerv2'.\n"
549 OFFSET"(Experimental)",
550 .offset = offsetof(options_t, plugins),
551 .type = OPT_STR_T,
552 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL | OPT_ADVANCED)
553 }, {
554 .var_name = "LB_DEBUG_OPTS",
555 .arg_name = "--debug-opts",
556 .default_value = "",
557 .description = OFFSET"Debug options.",
558 .offset = offsetof(options_t, debug_opts),
559 .type = OPT_DBG_T,
560 .flags = (option_flags_t)(OPT_OPTIONAL | OPT_ADVANCED)
561 }
562 };
563 #undef OFFSET
564
565 enum { NUM_OPTIONS = sizeof(options_dictionary)/sizeof(opts_dict_t) };
566
567
568 504 static const opts_dict_t* get_entry_by_name(const char *name) {
569 int i;
570
2/2
✓ Branch 0 taken 8868 times.
✓ Branch 1 taken 2 times.
8870 for (i=0; i<NUM_OPTIONS; ++i) {
571 8868 const opts_dict_t *entry = &options_dictionary[i];
572
1/2
✓ Branch 0 taken 8868 times.
✗ Branch 1 not taken.
8868 if (strcasecmp(entry->var_name, name) == 0
573
2/2
✓ Branch 0 taken 502 times.
✓ Branch 1 taken 8366 times.
8868 || strcasecmp(entry->arg_name, name) == 0) {
574 502 return entry;
575 }
576 }
577 2 return NULL;
578 }
579
580 180 static int set_ptr_path_value(void *option, const char *str_value) {
581 180 int path_len = snprintf(NULL, 0, "%s", str_value) + 1;
582
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 179 times.
180 if (path_len > 1) {
583 1 *(char**)option = malloc(sizeof(char) * path_len);
584 1 snprintf(*(char**)option, path_len, "%s", str_value);
585 } else {
586 179 *(char**)option = NULL;
587 }
588 180 return DLB_SUCCESS;
589 }
590
591 7085 static int set_value(option_type_t type, void *option, const char *str_value) {
592
16/18
✓ Branch 0 taken 2978 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1129 times.
✓ Branch 3 taken 745 times.
✓ Branch 4 taken 180 times.
✓ Branch 5 taken 238 times.
✓ Branch 6 taken 181 times.
✓ Branch 7 taken 181 times.
✓ Branch 8 taken 182 times.
✓ Branch 9 taken 181 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 181 times.
✓ Branch 12 taken 182 times.
✓ Branch 13 taken 181 times.
✓ Branch 14 taken 181 times.
✓ Branch 15 taken 181 times.
✓ Branch 16 taken 180 times.
✗ Branch 17 not taken.
7085 switch(type) {
593 2978 case OPT_BOOL_T:
594 2978 return parse_bool(str_value, (bool*)option);
595 4 case OPT_NEG_BOOL_T:
596 4 return parse_negated_bool(str_value, (bool*)option);
597 1129 case OPT_INT_T:
598 1129 return parse_int(str_value, (int*)option);
599 745 case OPT_STR_T:
600 745 snprintf(option, MAX_OPTION_LENGTH, "%s", str_value);
601 745 return DLB_SUCCESS;
602 180 case OPT_PTR_PATH_T:
603 180 return set_ptr_path_value(option, str_value);
604 238 case OPT_VB_T:
605 238 return parse_verbose_opts(str_value, (verbose_opts_t*)option);
606 181 case OPT_VBFMT_T:
607 181 return parse_verbose_fmt(str_value, (verbose_fmt_t*)option);
608 181 case OPT_INST_T:
609 181 return parse_instrument_items(str_value, (instrument_items_t*)option);
610 182 case OPT_DBG_T:
611 182 return parse_debug_opts(str_value, (debug_opts_t*)option);
612 181 case OPT_LEWI_AFF_T:
613 181 return parse_lewi_affinity(str_value, (lewi_affinity_t*)option);
614 case OPT_MASK_T:
615 mu_parse_mask(str_value, (cpu_set_t*)option);
616 return DLB_SUCCESS;
617 181 case OPT_MODE_T:
618 181 return parse_mode(str_value, (interaction_mode_t*)option);
619 182 case OPT_MPISET_T:
620 182 return parse_mpiset(str_value, (mpi_set_t*)option);
621 181 case OPT_OMPTOPTS_T:
622 181 return parse_omptool_opts(str_value, (omptool_opts_t*)option);
623 181 case OPT_TLPSUM_T:
624 181 return parse_talp_summary(str_value, (talp_summary_t*)option);
625 181 case OPT_TLPMOD_T:
626 181 return parse_talp_model(str_value, (talp_model_t*)option);
627 180 case OPT_OMPTM_T:
628 180 return parse_omptm_version(str_value, (omptm_version_t*)option);
629 }
630 return DLB_ERR_NOENT;
631 }
632
633 137 static const char * get_value(option_type_t type, const void *option) {
634 static char int_value[8];
635
15/18
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 4 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 8 times.
✓ Branch 12 taken 6 times.
✓ Branch 13 taken 4 times.
✓ Branch 14 taken 4 times.
✓ Branch 15 taken 1 times.
✓ Branch 16 taken 4 times.
✗ Branch 17 not taken.
137 switch(type) {
636 70 case OPT_BOOL_T:
637
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 56 times.
70 return *(bool*)option ? "yes" : "no";
638 case OPT_NEG_BOOL_T:
639 return *(bool*)option ? "no" : "yes";
640 11 case OPT_INT_T:
641 11 sprintf(int_value, "%d", *(int*)option);
642 11 return int_value;
643 8 case OPT_STR_T:
644 8 return (char*)option;
645 4 case OPT_PTR_PATH_T:
646
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 return *(const char**)option ? *(const char**)option : "";
647 4 case OPT_VB_T:
648 4 return verbose_opts_tostr(*(verbose_opts_t*)option);
649 4 case OPT_VBFMT_T:
650 4 return verbose_fmt_tostr(*(verbose_fmt_t*)option);
651 4 case OPT_INST_T:
652 4 return instrument_items_tostr(*(instrument_items_t*)option);
653 1 case OPT_DBG_T:
654 1 return debug_opts_tostr(*(debug_opts_t*)option);
655 4 case OPT_LEWI_AFF_T:
656 4 return lewi_affinity_tostr(*(lewi_affinity_t*)option);
657 case OPT_MASK_T:
658 return mu_to_str((cpu_set_t*)option);
659 8 case OPT_MODE_T:
660 8 return mode_tostr(*(interaction_mode_t*)option);
661 6 case OPT_MPISET_T:
662 6 return mpiset_tostr(*(mpi_set_t*)option);
663 4 case OPT_OMPTOPTS_T:
664 4 return omptool_opts_tostr(*(omptool_opts_t*)option);
665 4 case OPT_TLPSUM_T:
666 4 return talp_summary_tostr(*(talp_summary_t*)option);
667 1 case OPT_TLPMOD_T:
668 1 return talp_model_tostr(*(talp_model_t*)option);
669 4 case OPT_OMPTM_T:
670 4 return omptm_version_tostr(*(omptm_version_t*)option);
671 }
672 return "unknown";
673 }
674
675 1 static bool values_are_equivalent(option_type_t type, const char *value1, const char *value2) {
676
1/18
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1 switch(type) {
677 1 case OPT_BOOL_T:
678 1 return equivalent_bool(value1, value2);
679 case OPT_NEG_BOOL_T:
680 return equivalent_negated_bool(value1, value2);
681 case OPT_INT_T:
682 return equivalent_int(value1, value2);
683 case OPT_STR_T:
684 return strcmp(value1, value2) == 0;
685 case OPT_PTR_PATH_T:
686 return *(const char**)value1 && *(const char**)value2
687 && strcmp(*(const char**)value1, *(const char**)value2) == 0;
688 case OPT_VB_T:
689 return equivalent_verbose_opts(value1, value2);
690 case OPT_VBFMT_T:
691 return equivalent_verbose_fmt(value1, value2);
692 case OPT_INST_T:
693 return equivalent_instrument_items(value1, value2);
694 case OPT_DBG_T:
695 return equivalent_debug_opts(value1, value2);
696 case OPT_LEWI_AFF_T:
697 return equivalent_lewi_affinity(value1, value2);
698 case OPT_MASK_T:
699 return mu_equivalent_masks(value1, value2);
700 case OPT_MODE_T:
701 return equivalent_mode(value1, value2);
702 case OPT_MPISET_T:
703 return equivalent_mpiset(value1, value2);
704 case OPT_OMPTOPTS_T:
705 return equivalent_omptool_opts(value1, value2);
706 case OPT_TLPSUM_T:
707 return equivalent_talp_summary(value1, value2);
708 case OPT_TLPMOD_T:
709 return equivalent_talp_model(value1, value2);
710 case OPT_OMPTM_T:
711 return equivalent_omptm_version_opts(value1, value2);
712 }
713 return false;
714 }
715
716 16 static void copy_value(option_type_t type, void *dest, const char *src) {
717
13/18
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
✓ Branch 14 taken 1 times.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
16 switch(type) {
718 1 case OPT_BOOL_T:
719 1 memcpy(dest, src, sizeof(bool));
720 1 break;
721 1 case OPT_NEG_BOOL_T:
722 1 memcpy(dest, src, sizeof(bool));
723 1 break;
724 3 case OPT_INT_T:
725 3 memcpy(dest, src, sizeof(int));
726 3 break;
727 2 case OPT_STR_T:
728 2 memcpy(dest, src, sizeof(char)*MAX_OPTION_LENGTH);
729 2 break;
730 case OPT_PTR_PATH_T:
731 fatal("copy_value of type OPT_PTR_PATH_T not supported");
732 break;
733 1 case OPT_VB_T:
734 1 memcpy(dest, src, sizeof(verbose_opts_t));
735 1 break;
736 1 case OPT_VBFMT_T:
737 1 memcpy(dest, src, sizeof(verbose_fmt_t));
738 1 break;
739 1 case OPT_INST_T:
740 1 memcpy(dest, src, sizeof(instrument_items_t));
741 1 break;
742 case OPT_DBG_T:
743 memcpy(dest, src, sizeof(debug_opts_t));
744 break;
745 1 case OPT_LEWI_AFF_T:
746 1 memcpy(dest, src, sizeof(lewi_affinity_t));
747 1 break;
748 case OPT_MASK_T:
749 memcpy(dest, src, sizeof(cpu_set_t));
750 break;
751 1 case OPT_MODE_T:
752 1 memcpy(dest, src, sizeof(interaction_mode_t));
753 1 break;
754 1 case OPT_MPISET_T:
755 1 memcpy(dest, src, sizeof(mpi_set_t));
756 1 break;
757 1 case OPT_OMPTOPTS_T:
758 1 memcpy(dest, src, sizeof(omptool_opts_t));
759 1 break;
760 1 case OPT_TLPSUM_T:
761 1 memcpy(dest, src, sizeof(talp_summary_t));
762 1 break;
763 1 case OPT_TLPMOD_T:
764 1 memcpy(dest, src, sizeof(talp_model_t));
765 1 break;
766 case OPT_OMPTM_T:
767 memcpy(dest, src, sizeof(omptm_version_t));
768 break;
769 }
770 16 }
771
772 /* Parse DLB_ARGS and remove argument if found */
773 12534 static void parse_dlb_args(char *dlb_args, const char *arg_name, char* arg_value, size_t arg_max_len) {
774 12534 *arg_value = 0;
775 /* Tokenize a copy of dlb_args with " "(blank) delimiter */
776 12534 char *progress = dlb_args;
777 12534 char *end_space = NULL;
778 12534 size_t len = strlen(dlb_args) + 1;
779 12534 char *dlb_args_copy = malloc(sizeof(char)*len);
780 12534 strcpy(dlb_args_copy, dlb_args);
781 12534 char *token = strtok_r(dlb_args_copy, " ", &end_space);
782
2/2
✓ Branch 0 taken 8067 times.
✓ Branch 1 taken 12534 times.
20601 while (token) {
783 /* Each token is a complete string representing an option */
784
785 8067 bool remove_token = false;
786 /* token length must be computed before tokenizing into arg=val */
787 8067 size_t token_len = strlen(token);
788 /* progress pointer must be updated each iteration to skip spaces */
789
2/2
✓ Branch 0 taken 10310 times.
✓ Branch 1 taken 8067 times.
18377 while(isspace((unsigned char)*progress)) progress++;
790
791
2/2
✓ Branch 0 taken 7115 times.
✓ Branch 1 taken 952 times.
8067 if (strchr(token, '=')) {
792 /* Option is of the form --argument=value */
793 7115 char *end_equal = NULL;
794 7115 char *argument = strtok_r(token, "=", &end_equal);
795
2/2
✓ Branch 0 taken 299 times.
✓ Branch 1 taken 6816 times.
7115 if (strcmp(argument, arg_name) == 0) {
796 /* Obtain value */
797 299 char *value = strtok_r(NULL, "=", &end_equal);
798
2/2
✓ Branch 0 taken 298 times.
✓ Branch 1 taken 1 times.
299 if (value) {
799 298 snprintf(arg_value, arg_max_len, "%s", value);
800 } else {
801 1 warning("Bad format parsing of DLB_ARGS. Option %s with empty value", token);
802 }
803 299 remove_token = true;
804 }
805 } else {
806 /* Option is of the form --argument/--no-argument */
807 952 char *argument = token;
808
2/2
✓ Branch 0 taken 162 times.
✓ Branch 1 taken 790 times.
952 if (strcmp(argument, arg_name) == 0) {
809 /* Option value is 'yes' */
810 162 strcpy(arg_value, "yes");
811 162 remove_token = true;
812
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 766 times.
790 } else if (strncmp(argument, "--no-", 5) == 0
813
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 5 times.
24 && strcmp(argument+5, arg_name+2) == 0) {
814 /* Option value is 'no' */
815 19 strcpy(arg_value, "no");
816 19 remove_token = true;
817 }
818 }
819
820
2/2
✓ Branch 0 taken 480 times.
✓ Branch 1 taken 7587 times.
8067 if (remove_token) {
821 /* Remove token from dlb_args */
822 480 char *dest = progress;
823 480 char *src = progress + token_len;
824 480 size_t n = strlen(src) + 1;
825 480 memmove(dest, src, n);
826 } else {
827 /* Token is not removed, update parsed progress pointer */
828 7587 progress += token_len;
829 }
830
831 /* next token */
832 8067 token = strtok_r(NULL, " ", &end_space);
833 }
834 12534 free(dlb_args_copy);
835 12534 }
836
837 /* Initialize options struct from either argument, or env. variable */
838 180 void options_init(options_t *options, const char *dlb_args) {
839 /* Copy dlb_args into a local buffer */
840 180 char *dlb_args_from_api = NULL;
841
2/2
✓ Branch 0 taken 149 times.
✓ Branch 1 taken 31 times.
180 if (dlb_args) {
842 149 size_t len = strlen(dlb_args) + 1;
843 149 dlb_args_from_api = malloc(sizeof(char)*len);
844 149 strcpy(dlb_args_from_api, dlb_args);
845 }
846
847 /* Copy either DLB_ARGS or LB_ARGS into a local buffer */
848 180 char *dlb_args_from_env = NULL;
849 180 const char *env = getenv("DLB_ARGS");
850
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 151 times.
180 if (!env) {
851 29 env = getenv("LB_ARGS");
852
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 if (env) {
853 warning("LB_ARGS is deprecated, please use DLB_ARGS");
854 }
855 }
856
2/2
✓ Branch 0 taken 151 times.
✓ Branch 1 taken 29 times.
180 if (env) {
857 151 size_t len = strlen(env) + 1;
858 151 dlb_args_from_env = malloc(sizeof(char)*len);
859 151 strcpy(dlb_args_from_env, env);
860 }
861
862 /* Preallocate two buffers large enough to save any intermediate option value */
863 180 char *arg_value_from_api = malloc(sizeof(char)*PATH_MAX);
864 180 char *arg_value_from_env = malloc(sizeof(char)*PATH_MAX);
865
866 int i;
867
2/2
✓ Branch 0 taken 7380 times.
✓ Branch 1 taken 180 times.
7560 for (i=0; i<NUM_OPTIONS; ++i) {
868 7380 const opts_dict_t *entry = &options_dictionary[i];
869 7380 const char *rhs = NULL; /* pointer to rhs to be parsed */
870
871 /* Set-up specific argument length */
872 size_t arg_max_len;
873
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 7200 times.
7380 switch (entry->type) {
874 180 case OPT_PTR_PATH_T:
875 180 arg_max_len = PATH_MAX-1;
876 180 break;
877 7200 default:
878 7200 arg_max_len = MAX_OPTION_LENGTH-1;
879 7200 break;
880 }
881
882 /* Reset intermediate buffers */
883 7380 arg_value_from_api[0] = '\0';
884 7380 arg_value_from_env[0] = '\0';
885
886 /* Parse dlb_args from API */
887
2/2
✓ Branch 0 taken 6109 times.
✓ Branch 1 taken 1271 times.
7380 if (dlb_args_from_api) {
888 6109 parse_dlb_args(dlb_args_from_api, entry->arg_name, arg_value_from_api, arg_max_len);
889
2/2
✓ Branch 0 taken 357 times.
✓ Branch 1 taken 5752 times.
6109 if (strlen(arg_value_from_api) > 0) {
890 357 rhs = arg_value_from_api;
891 }
892 }
893
894 /* Parse DLB_ARGS from env */
895
2/2
✓ Branch 0 taken 6191 times.
✓ Branch 1 taken 1189 times.
7380 if (dlb_args_from_env) {
896 6191 parse_dlb_args(dlb_args_from_env, entry->arg_name, arg_value_from_env, arg_max_len);
897
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 6105 times.
6191 if (strlen(arg_value_from_env) > 0) {
898
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 85 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
86 if (rhs && !values_are_equivalent(entry->type, rhs, arg_value_from_env)) {
899 1 warning("Overwriting option %s = %s",
900 1 entry->arg_name, arg_value_from_env);
901 }
902 86 rhs = arg_value_from_env;
903 }
904 }
905
906 /* Parse LB_option (to be deprecated soon) */
907 7380 const char *arg_value = getenv(entry->var_name);
908
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7380 times.
7380 if (arg_value) {
909 if (rhs) {
910 warning("Ignoring option %s = %s due to DLB_ARGS precedence",
911 entry->var_name, arg_value);
912 } else {
913 warning("Option %s is to be deprecated in the near future, please use DLB_ARGS",
914 entry->var_name);
915 rhs = arg_value;
916 }
917 }
918
919 /* Warn if option is deprecated and has rhs */
920
4/4
✓ Branch 0 taken 540 times.
✓ Branch 1 taken 6840 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 537 times.
7380 if (entry->flags & OPT_DEPRECATED && rhs) {
921 3 warning("Option %s is deprecated:\n%s", entry->arg_name, entry->description);
922 }
923
924 /* Skip iteration if option is not used anymore */
925
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7380 times.
7380 if (entry->flags & OPT_UNUSED) {
926 continue;
927 }
928
929 /* Assign option = rhs, and nullify rhs if error */
930
2/2
✓ Branch 0 taken 442 times.
✓ Branch 1 taken 6938 times.
7380 if (rhs) {
931 442 int error = set_value(entry->type, (char*)options+entry->offset, rhs);
932
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 442 times.
442 if (error) {
933 warning("Unrecognized %s value: %s. Setting default %s",
934 entry->arg_name, rhs, entry->default_value);
935 rhs = NULL;
936 }
937 }
938
939 /* Set default value if needed */
940
4/4
✓ Branch 0 taken 6938 times.
✓ Branch 1 taken 442 times.
✓ Branch 2 taken 6401 times.
✓ Branch 3 taken 537 times.
7380 if (!rhs && !(entry->flags & OPT_DEPRECATED)) {
941
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6401 times.
6401 fatal_cond(!(entry->flags & OPT_OPTIONAL),
942 "Variable %s must be defined", entry->arg_name);
943 6401 int error = set_value(entry->type, (char*)options+entry->offset, entry->default_value);
944
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6401 times.
6401 fatal_cond(error, "Internal error parsing default value %s=%s. Please, report bug at %s.",
945 entry->arg_name, entry->default_value, PACKAGE_BUGREPORT);
946 }
947 }
948
949 /* Free intermediate buffers */
950 180 free(arg_value_from_api);
951 180 free(arg_value_from_env);
952
953 /* Safety checks and free local buffers */
954
2/2
✓ Branch 0 taken 149 times.
✓ Branch 1 taken 31 times.
180 if (dlb_args_from_api) {
955 149 char *str = dlb_args_from_api;
956
2/2
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 149 times.
381 while(isspace((unsigned char)*str)) str++;
957
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 146 times.
149 if (strlen(str) > 0) {
958
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (options->debug_opts & DBG_WERROR) {
959 fatal("Unrecognized flags from DLB_Init: %s", str);
960 } else {
961 3 warning("Unrecognized flags from DLB_Init: %s", str);
962 }
963 }
964 149 free(dlb_args_from_api);
965 }
966
2/2
✓ Branch 0 taken 151 times.
✓ Branch 1 taken 29 times.
180 if (dlb_args_from_env) {
967 151 char *str = dlb_args_from_env;
968
2/2
✓ Branch 0 taken 199 times.
✓ Branch 1 taken 151 times.
350 while(isspace((unsigned char)*str)) str++;
969
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 150 times.
151 if (strlen(str) > 0) {
970
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (options->debug_opts & DBG_WERROR) {
971 fatal("Unrecognized flags from DLB_ARGS: %s", str);
972 } else {
973 1 warning("Unrecognized flags from DLB_ARGS: %s", str);
974 }
975 }
976 151 free(dlb_args_from_env);
977 }
978 180 }
979
980 96 void options_finalize(options_t *options) {
981
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 95 times.
96 if (options->talp_output_file) {
982 1 free(options->talp_output_file);
983 1 options->talp_output_file = NULL;
984 }
985 96 }
986
987 /* Obtain value of specific entry, either from DLB_ARGS or from thread_spd->options */
988 254 void options_parse_entry(const char *var_name, void *option) {
989 254 const opts_dict_t *entry = get_entry_by_name(var_name);
990
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 254 times.
254 ensure(entry, "%s: bad variable name '%s'", __func__, var_name);
991
992
4/4
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 46 times.
254 if (thread_spd && thread_spd->dlb_initialized) {
993 16 copy_value(entry->type, option, (char*)&thread_spd->options + entry->offset);
994 } else {
995 /* Simplified options_init just for this entry */
996
997 /* Copy DLB_ARGS into a local buffer */
998 238 char *dlb_args_from_env = NULL;
999 238 const char *env = getenv("DLB_ARGS");
1000
2/2
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 4 times.
238 if (env) {
1001 234 size_t len = strlen(env) + 1;
1002 234 dlb_args_from_env = malloc(sizeof(char)*len);
1003 234 strcpy(dlb_args_from_env, env);
1004 }
1005
1006 /* Pointer to rhs to be parsed */
1007 238 const char *rhs = NULL;
1008
1009 /* Set-up specific argument length */
1010 size_t arg_max_len;
1011
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 238 times.
238 switch (entry->type) {
1012 case OPT_PTR_PATH_T:
1013 arg_max_len = PATH_MAX-1;
1014 break;
1015 238 default:
1016 238 arg_max_len = MAX_OPTION_LENGTH-1;
1017 238 break;
1018 }
1019
1020 /* Preallocate a buffer large enough to save the option value */
1021 238 char *arg_value_from_env = malloc(sizeof(char)*(arg_max_len+1));
1022 238 arg_value_from_env[0] = '\0';
1023
1024 /* Parse DLB_ARGS from env */
1025
2/2
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 4 times.
238 if (dlb_args_from_env) {
1026 234 parse_dlb_args(dlb_args_from_env, entry->arg_name, arg_value_from_env, arg_max_len);
1027
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 204 times.
234 if (strlen(arg_value_from_env) > 0) {
1028 30 rhs = arg_value_from_env;
1029 }
1030 }
1031
1032 /* Assign option = rhs, and nullify rhs if error */
1033
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 208 times.
238 if (rhs) {
1034 30 int error = set_value(entry->type, option, rhs);
1035
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (error) {
1036 rhs = NULL;
1037 }
1038 }
1039
1040 /* Set default value if needed */
1041
2/2
✓ Branch 0 taken 208 times.
✓ Branch 1 taken 30 times.
238 if (!rhs) {
1042 208 set_value(entry->type, option, entry->default_value);
1043 }
1044
1045 /* Free buffers */
1046 238 free(arg_value_from_env);
1047
2/2
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 4 times.
238 if (dlb_args_from_env) {
1048 234 free(dlb_args_from_env);
1049 }
1050 }
1051 254 }
1052
1053 /* API Setter */
1054 8 int options_set_variable(options_t *options, const char *var_name, const char *value) {
1055 int error;
1056 8 const opts_dict_t *entry = get_entry_by_name(var_name);
1057
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
8 if (entry) {
1058
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (entry->flags & OPT_READONLY) {
1059 3 error = DLB_ERR_PERM;
1060 } else {
1061 4 error = set_value(entry->type, (char*)options+entry->offset, value);
1062 }
1063 } else {
1064 1 error = DLB_ERR_NOENT;
1065 }
1066
1067 8 return error;
1068 }
1069
1070 /* API Getter */
1071 14 int options_get_variable(const options_t *options, const char *var_name, char *value) {
1072 int error;
1073 14 const opts_dict_t *entry = get_entry_by_name(var_name);
1074
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 if (entry) {
1075 13 sprintf(value, "%s", get_value(entry->type, (char*)options+entry->offset));
1076 13 error = DLB_SUCCESS;
1077 } else {
1078 1 error = DLB_ERR_NOENT;
1079 }
1080
1081 14 return error;
1082 }
1083
1084 /* API Printer. Also, dlb -h/-hh output */
1085 4 void options_print_variables(const options_t *options, bool print_extended) {
1086
1087 /* Initialize buffer */
1088 print_buffer_t buffer;
1089 4 printbuffer_init(&buffer);
1090
1091 /* Set up intermediate buffer per entry */
1092 enum { MAX_ENTRY_LEN = 256 };
1093 char entry_buffer[MAX_ENTRY_LEN];
1094
1095 /* Header (last \n is not needed) */
1096 4 printbuffer_append(&buffer,
1097 "DLB Options:\n\n"
1098 "DLB is configured by setting these flags in the DLB_ARGS environment variable.\n"
1099 "Possible options are listed below:\n\n"
1100 "Option Current value Possible value (type) / [choice] / {val1:val2}\n"
1101 "--------------------------------------------------------------------------------------"
1102 );
1103
1104 int i;
1105
2/2
✓ Branch 0 taken 164 times.
✓ Branch 1 taken 4 times.
168 for (i=0; i<NUM_OPTIONS; ++i) {
1106 164 const opts_dict_t *entry = &options_dictionary[i];
1107
1108 /* Skip if deprecated */
1109
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 152 times.
164 if (entry->flags & OPT_DEPRECATED) continue;
1110
1111 /* Skip if hidden */
1112
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 148 times.
152 if (entry->flags & OPT_HIDDEN) continue;
1113
1114 /* Skip if advanced (unless print_extended) */
1115
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 116 times.
148 if (entry->flags & OPT_ADVANCED
1116
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 && !print_extended) continue;
1117
1118 /* Reset entry buffer */
1119 124 entry_buffer[0] = '\0';
1120 124 char *b = entry_buffer;
1121 124 size_t max_entry_len = MAX_ENTRY_LEN;
1122
1123 /* Name */
1124 124 size_t name_len = strlen(entry->arg_name) + 1;
1125
2/2
✓ Branch 0 taken 119 times.
✓ Branch 1 taken 5 times.
124 if (name_len < 24) {
1126 /* Option + tabs until column 24 */
1127
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 20 times.
218 b += snprintf(b, max_entry_len, "%s:%s",
1128 119 entry->arg_name,
1129
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 42 times.
99 name_len < 8 ? "\t\t\t" : name_len < 16 ? "\t\t" : "\t");
1130 } else {
1131 /* Long option, break line */
1132 5 b += snprintf(b, max_entry_len, "%s:\n\t\t\t",
1133 5 entry->arg_name);
1134 }
1135
1136 /* Check if output was truncated, and update remaining entry length */
1137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
124 fatal_cond((b - entry_buffer) >= MAX_ENTRY_LEN,
1138 "Output truncated in in %s. Please report bug at %s",
1139 __func__, PACKAGE_BUGREPORT);
1140 124 max_entry_len = MAX_ENTRY_LEN - (b - entry_buffer);
1141
1142 /* Value */
1143 124 const char *value = get_value(entry->type, (char*)options+entry->offset);
1144 124 size_t value_len = strlen(value) + 1;
1145
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 111 times.
137 b += snprintf(b, max_entry_len, "%s %s",
1146 value,
1147
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 value_len < 8 ? "\t\t" : value_len < 16 ? "\t" : "");
1148
1149 /* Check if output was truncated, and update remaining entry length */
1150
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
124 fatal_cond((b - entry_buffer) >= MAX_ENTRY_LEN,
1151 "Output truncated in in %s. Please report bug at %s",
1152 __func__, PACKAGE_BUGREPORT);
1153 124 max_entry_len = MAX_ENTRY_LEN - (b - entry_buffer);
1154
1155 /* Choices */
1156
15/18
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 4 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 4 times.
✓ Branch 12 taken 4 times.
✓ Branch 13 taken 4 times.
✓ Branch 14 taken 4 times.
✓ Branch 15 taken 1 times.
✓ Branch 16 taken 4 times.
✗ Branch 17 not taken.
124 switch(entry->type) {
1157 64 case OPT_BOOL_T:
1158 64 b += snprintf(b, max_entry_len, "(bool)");
1159 64 break;
1160 case OPT_NEG_BOOL_T:
1161 b += snprintf(b, max_entry_len, "(bool)");
1162 break;
1163 11 case OPT_INT_T:
1164 11 b += snprintf(b, max_entry_len, "(int)");
1165 11 break;
1166 7 case OPT_STR_T:
1167 7 b += snprintf(b, max_entry_len, "(string)");
1168 7 break;
1169 4 case OPT_PTR_PATH_T:
1170 4 b += snprintf(b, max_entry_len, "(path)");
1171 4 break;
1172 4 case OPT_VB_T:
1173 4 b += snprintf(b, max_entry_len, "{%s}", get_verbose_opts_choices());
1174 4 break;
1175 4 case OPT_VBFMT_T:
1176 4 b += snprintf(b, max_entry_len, "{%s}", get_verbose_fmt_choices());
1177 4 break;
1178 4 case OPT_INST_T:
1179 4 b += snprintf(b, max_entry_len, "{%s}", get_instrument_items_choices());
1180 4 break;
1181 1 case OPT_DBG_T:
1182 1 b += snprintf(b, max_entry_len, "{%s}", get_debug_opts_choices());
1183 1 break;
1184 4 case OPT_LEWI_AFF_T:
1185 4 b += snprintf(b, max_entry_len, "[%s]", get_lewi_affinity_choices());
1186 4 break;
1187 case OPT_MASK_T:
1188 b += snprintf(b, max_entry_len, "(cpuset)");
1189 break;
1190 4 case OPT_MODE_T:
1191 4 b += snprintf(b, max_entry_len, "[%s]", get_mode_choices());
1192 4 break;
1193 4 case OPT_MPISET_T:
1194 4 b += snprintf(b, max_entry_len, "[%s]", get_mpiset_choices());
1195 4 break;
1196 4 case OPT_OMPTOPTS_T:
1197 4 b += snprintf(b, max_entry_len, "[%s]", get_omptool_opts_choices());
1198 4 break;
1199 4 case OPT_TLPSUM_T:
1200 4 b += snprintf(b, max_entry_len, "{%s}", get_talp_summary_choices());
1201 4 break;
1202 1 case OPT_TLPMOD_T:
1203 1 b += snprintf(b, max_entry_len, "[%s]", get_talp_model_choices());
1204 1 break;
1205 4 case OPT_OMPTM_T:
1206 4 b += snprintf(b, max_entry_len, "[%s]", get_omptm_version_choices());
1207 4 break;
1208 }
1209
1210 /* Check if output was truncated */
1211
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
124 fatal_cond((b - entry_buffer) >= MAX_ENTRY_LEN,
1212 "Buffer overflow in %s. Please report bug at %s",
1213 __func__, PACKAGE_BUGREPORT);
1214
1215 /* Append entry listing */
1216 124 printbuffer_append(&buffer, entry_buffer);
1217
1218 /* Append long description if print_extended */
1219
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 87 times.
124 if (print_extended) {
1220 37 printbuffer_append(&buffer, entry->description);
1221 37 printbuffer_append(&buffer, "");
1222 }
1223
1224 }
1225
1226 /* Footer (last \n is not needed) */
1227 4 printbuffer_append(&buffer,
1228 "\n"
1229 "Boolean options accept both standalone flags and 'yes'/'no' parameters.\n"
1230 "These are equivalent flags:\n"
1231 " export DLB_ARGS=\"--lewi --no-drom\"\n"
1232 " export DLB_ARGS=\"--lewi=yes --drom=no\"");
1233
1234 /* This function must print always and ignore options --quiet and --silent */
1235 4 info0_force_print("%s", buffer.addr);
1236
1237 4 printbuffer_destroy(&buffer);
1238 4 }
1239
1240 /* Print which LeWI flags are enabled during DLB_Init */
1241 57 void options_print_lewi_flags(const options_t *options) {
1242 const opts_dict_t *entry;
1243
1244 // --lewi-mpi
1245 bool default_lewi_keep_one_cpu;
1246 57 entry = get_entry_by_name("--lewi-keep-one-cpu");
1247 57 parse_bool(entry->default_value, &default_lewi_keep_one_cpu);
1248
1249 // --lewi-mpi-calls
1250 mpi_set_t default_lewi_mpi_calls;
1251 57 entry = get_entry_by_name("--lewi-mpi-calls");
1252 57 parse_mpiset(entry->default_value, &default_lewi_mpi_calls);
1253
1254 // --lewi-affinity
1255 lewi_affinity_t default_lewi_affinity;
1256 57 entry = get_entry_by_name("--lewi-affinity");
1257 57 parse_lewi_affinity(entry->default_value, &default_lewi_affinity);
1258
1259 // --lewi-ompt
1260 omptool_opts_t default_lewi_ompt;
1261 57 entry = get_entry_by_name("--lewi-ompt");
1262 57 parse_omptool_opts(entry->default_value, &default_lewi_ompt);
1263
1264
1/2
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
57 if (options->lewi_keep_cpu_on_blocking_call != default_lewi_keep_one_cpu
1265
1/2
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
57 || options->lewi_mpi_calls != default_lewi_mpi_calls
1266
1/2
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
57 || options->lewi_affinity != default_lewi_affinity
1267
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 || options->lewi_ompt != default_lewi_ompt) {
1268 info0("LeWI options:");
1269 if (options->lewi_keep_cpu_on_blocking_call != default_lewi_keep_one_cpu) {
1270 info0(" --lewi-keep-one-cpu");
1271 }
1272 if (options->lewi_mpi_calls != default_lewi_mpi_calls) {
1273 info0(" --lewi-mpi-calls=%s", mpiset_tostr(options->lewi_mpi_calls));
1274 }
1275 if (options->lewi_affinity != default_lewi_affinity) {
1276 info0(" --lewi-affinity=%s", lewi_affinity_tostr(options->lewi_affinity));
1277 }
1278 if (options->lewi_ompt != default_lewi_ompt) {
1279 info0(" --lewi-ompt=%s", omptool_opts_tostr(options->lewi_ompt));
1280 }
1281 }
1282 57 }
1283