GCC Code Coverage Report


Directory: src/
File: src/support/options.c
Date: 2026-02-23 15:13:19
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, selected based on the\n"
417 OFFSET"file extensions *.json and *.csv, respectively. JSON files\n"
418 OFFSET"will be overwritten if they already exist, while CSV files\n"
419 OFFSET"will be appended as new rows.\n"
420 OFFSET"Any other file extension will result in plain text output.\n"
421 OFFSET"\n"
422 OFFSET"Deprecated formats:\n"
423 OFFSET"The *.xml file extension is deprecated and will be removed in\n"
424 OFFSET"the next release.",
425 .offset = offsetof(options_t, talp_output_file),
426 .type = OPT_PTR_PATH_T,
427 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
428 },
429 {
430 /* In the future, consider using an interval update timer instead of a boolean */
431 .var_name = "LB_NULL",
432 .arg_name = "--talp-external-profiler",
433 .default_value = "no",
434 .description = OFFSET"Enable live metrics update to the shared memory. This flag\n"
435 OFFSET"is only needed if there is an external program monitoring\n"
436 OFFSET"the application.",
437 .offset = offsetof(options_t, talp_external_profiler),
438 .type = OPT_BOOL_T,
439 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
440 },
441 {
442 .var_name = "LB_NULL",
443 .arg_name = "--talp-regions-per-proc",
444 .default_value = "100",
445 .description = OFFSET"Number of TALP regions per process to allocate in the shared\n"
446 OFFSET"memory.\n"
447 OFFSET"Deprecated: use --shmem-size-multiplier instead.\n",
448 .offset = offsetof(options_t, talp_regions_per_proc),
449 .type = OPT_INT_T,
450 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL | OPT_DEPRECATED)
451 },
452 {
453 .var_name = "LB_NULL",
454 .arg_name = "--talp-region-select",
455 .default_value = "",
456 .description = OFFSET"Select TALP regions to enable. This option follows the format:\n"
457 OFFSET" --talp-region-select=[(include|exclude):]<region-list>\n"
458 OFFSET"\n"
459 OFFSET"The modifiers 'include:' and 'exclude:' are optional, but only\n"
460 OFFSET"one modifier can be used at a time. If neither is specified,\n"
461 OFFSET"'include:' is assumed by default.\n"
462 OFFSET"\n"
463 OFFSET"The '<region-list>' can be a comma-separated list of regions\n"
464 OFFSET"or a special token 'all' to refer to all regions. The global\n"
465 OFFSET"monitoring region may be specified with the special token\n"
466 OFFSET"'global'. If the modifier 'include:' is used, only the listed\n"
467 OFFSET"regions will be enabled. If 'exclude:' is used, all regions\n"
468 OFFSET"will be enabled except for the ones specified.\n"
469 OFFSET"\n"
470 OFFSET"Note that when using this feature, listed regions must not have\n"
471 OFFSET"spaces in their names.\n"
472 OFFSET"\n"
473 OFFSET"e.g.: --talp-region-select=all (default)\n"
474 OFFSET" --talp-region-select=exclude:all\n"
475 OFFSET" --talp-region-select=include:global,region3\n"
476 OFFSET" --talp-region-select=exclude:region4",
477 .offset = offsetof(options_t, talp_region_select),
478 .type = OPT_STR_T,
479 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL)
480 },
481 {
482 .var_name = "LB_NULL",
483 .arg_name = "--talp-model",
484 .default_value = "hybrid-v2",
485 .description = OFFSET"For development use only.\n"
486 OFFSET"Select which version of POP metrics to compute.",
487 .offset = offsetof(options_t, talp_model),
488 .type = OPT_TLPMOD_T,
489 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL | OPT_ADVANCED)
490 },
491 // barrier
492 {
493 .var_name = "LB_NULL",
494 .arg_name = "--barrier-id",
495 .default_value = "0",
496 .description = OFFSET"Barrier ID. Use different barrier id numbers for different\n"
497 OFFSET"processes to avoid unwanted synchronization.",
498 .offset = offsetof(options_t, barrier_id),
499 .type = OPT_INT_T,
500 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL | OPT_ADVANCED)
501 },
502 // misc
503 {
504 .var_name = "LB_SHM_KEY",
505 .arg_name = "--shm-key",
506 .default_value = "",
507 .description = OFFSET"Shared Memory key. By default, if key is empty, all processes\n"
508 OFFSET"will use a shared memory based on the user ID. If different\n"
509 OFFSET"processes start their execution with different keys, they will\n"
510 OFFSET"use different shared memories and they will not share resources.",
511 .offset = offsetof(options_t, shm_key),
512 .type = OPT_STR_T,
513 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL | OPT_ADVANCED)
514 }, {
515 .var_name = "LB_NULL",
516 .arg_name = "--shm-size-multiplier",
517 .default_value = "1",
518 .description = OFFSET"DLB allocates its shared memory at the start of execution, with\n"
519 OFFSET"its size based on the number of CPUs in the node. If you\n"
520 OFFSET"encounter a DLB_ERR_NOMEM error, you can adjust the multiplier\n"
521 OFFSET"to increase the shared memory size. As a reference, with the\n"
522 OFFSET"default multiplier, the typical shared memory size on HPC\n"
523 OFFSET"machines is under 10 megabytes, so keep that in mind if you\n"
524 OFFSET"increase its size to allocate more running processes or TALP\n"
525 OFFSET"regions.",
526 .offset = offsetof(options_t, shm_size_multiplier),
527 .type = OPT_INT_T,
528 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL | OPT_ADVANCED)
529 }, {
530 .var_name = "LB_PREINIT_PID",
531 .arg_name = "--preinit-pid",
532 .default_value = "0",
533 .description = OFFSET"Process ID that pre-initializes the DLB process for DROM.",
534 .offset = offsetof(options_t, preinit_pid),
535 .type = OPT_INT_T,
536 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL | OPT_HIDDEN)
537 }, {
538 .var_name = "LB_NULL",
539 .arg_name = "--ompt-thread-manager",
540 .default_value = "omp5",
541 .description = OFFSET"OMPT Thread Manager version.",
542 .offset = offsetof(options_t, omptm_version),
543 .type = OPT_OMPTM_T,
544 .flags = (option_flags_t)(OPT_OPTIONAL)
545 }, {
546 .var_name = "LB_NULL",
547 .arg_name = "--plugin",
548 .default_value = "",
549 .description = OFFSET"Select plugin to enable.\n"
550 OFFSET"For now, only 'cupti', 'rocprofiler-sdk', and 'rocprofilerv2'.\n"
551 OFFSET"(Experimental)",
552 .offset = offsetof(options_t, plugins),
553 .type = OPT_STR_T,
554 .flags = (option_flags_t)(OPT_READONLY | OPT_OPTIONAL | OPT_ADVANCED)
555 }, {
556 .var_name = "LB_DEBUG_OPTS",
557 .arg_name = "--debug-opts",
558 .default_value = "",
559 .description = OFFSET"Debug options.",
560 .offset = offsetof(options_t, debug_opts),
561 .type = OPT_DBG_T,
562 .flags = (option_flags_t)(OPT_OPTIONAL | OPT_ADVANCED)
563 }
564 };
565 #undef OFFSET
566
567 enum { NUM_OPTIONS = sizeof(options_dictionary)/sizeof(opts_dict_t) };
568
569
570 535 static const opts_dict_t* get_entry_by_name(const char *name) {
571 int i;
572
2/2
✓ Branch 0 taken 9095 times.
✓ Branch 1 taken 2 times.
9097 for (i=0; i<NUM_OPTIONS; ++i) {
573 9095 const opts_dict_t *entry = &options_dictionary[i];
574
1/2
✓ Branch 0 taken 9095 times.
✗ Branch 1 not taken.
9095 if (strcasecmp(entry->var_name, name) == 0
575
2/2
✓ Branch 0 taken 533 times.
✓ Branch 1 taken 8562 times.
9095 || strcasecmp(entry->arg_name, name) == 0) {
576 533 return entry;
577 }
578 }
579 2 return NULL;
580 }
581
582 175 static int set_ptr_path_value(void *option, const char *str_value) {
583 175 int path_len = snprintf(NULL, 0, "%s", str_value) + 1;
584
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 174 times.
175 if (path_len > 1) {
585 1 *(char**)option = malloc(sizeof(char) * path_len);
586 1 snprintf(*(char**)option, path_len, "%s", str_value);
587 } else {
588 174 *(char**)option = NULL;
589 }
590 175 return DLB_SUCCESS;
591 }
592
593 6926 static int set_value(option_type_t type, void *option, const char *str_value) {
594
16/18
✓ Branch 0 taken 2933 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1099 times.
✓ Branch 3 taken 725 times.
✓ Branch 4 taken 175 times.
✓ Branch 5 taken 229 times.
✓ Branch 6 taken 176 times.
✓ Branch 7 taken 176 times.
✓ Branch 8 taken 177 times.
✓ Branch 9 taken 176 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 176 times.
✓ Branch 12 taken 177 times.
✓ Branch 13 taken 176 times.
✓ Branch 14 taken 176 times.
✓ Branch 15 taken 176 times.
✓ Branch 16 taken 175 times.
✗ Branch 17 not taken.
6926 switch(type) {
595 2933 case OPT_BOOL_T:
596 2933 return parse_bool(str_value, (bool*)option);
597 4 case OPT_NEG_BOOL_T:
598 4 return parse_negated_bool(str_value, (bool*)option);
599 1099 case OPT_INT_T:
600 1099 return parse_int(str_value, (int*)option);
601 725 case OPT_STR_T:
602 725 snprintf(option, MAX_OPTION_LENGTH, "%s", str_value);
603 725 return DLB_SUCCESS;
604 175 case OPT_PTR_PATH_T:
605 175 return set_ptr_path_value(option, str_value);
606 229 case OPT_VB_T:
607 229 return parse_verbose_opts(str_value, (verbose_opts_t*)option);
608 176 case OPT_VBFMT_T:
609 176 return parse_verbose_fmt(str_value, (verbose_fmt_t*)option);
610 176 case OPT_INST_T:
611 176 return parse_instrument_items(str_value, (instrument_items_t*)option);
612 177 case OPT_DBG_T:
613 177 return parse_debug_opts(str_value, (debug_opts_t*)option);
614 176 case OPT_LEWI_AFF_T:
615 176 return parse_lewi_affinity(str_value, (lewi_affinity_t*)option);
616 case OPT_MASK_T:
617 mu_parse_mask(str_value, (cpu_set_t*)option);
618 return DLB_SUCCESS;
619 176 case OPT_MODE_T:
620 176 return parse_mode(str_value, (interaction_mode_t*)option);
621 177 case OPT_MPISET_T:
622 177 return parse_mpiset(str_value, (mpi_set_t*)option);
623 176 case OPT_OMPTOPTS_T:
624 176 return parse_omptool_opts(str_value, (omptool_opts_t*)option);
625 176 case OPT_TLPSUM_T:
626 176 return parse_talp_summary(str_value, (talp_summary_t*)option);
627 176 case OPT_TLPMOD_T:
628 176 return parse_talp_model(str_value, (talp_model_t*)option);
629 175 case OPT_OMPTM_T:
630 175 return parse_omptm_version(str_value, (omptm_version_t*)option);
631 }
632 return DLB_ERR_NOENT;
633 }
634
635 137 static const char * get_value(option_type_t type, const void *option) {
636 static char int_value[8];
637
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) {
638 70 case OPT_BOOL_T:
639
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 56 times.
70 return *(bool*)option ? "yes" : "no";
640 case OPT_NEG_BOOL_T:
641 return *(bool*)option ? "no" : "yes";
642 11 case OPT_INT_T:
643 11 sprintf(int_value, "%d", *(int*)option);
644 11 return int_value;
645 8 case OPT_STR_T:
646 8 return (char*)option;
647 4 case OPT_PTR_PATH_T:
648
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 return *(const char**)option ? *(const char**)option : "";
649 4 case OPT_VB_T:
650 4 return verbose_opts_tostr(*(verbose_opts_t*)option);
651 4 case OPT_VBFMT_T:
652 4 return verbose_fmt_tostr(*(verbose_fmt_t*)option);
653 4 case OPT_INST_T:
654 4 return instrument_items_tostr(*(instrument_items_t*)option);
655 1 case OPT_DBG_T:
656 1 return debug_opts_tostr(*(debug_opts_t*)option);
657 4 case OPT_LEWI_AFF_T:
658 4 return lewi_affinity_tostr(*(lewi_affinity_t*)option);
659 case OPT_MASK_T:
660 return mu_to_str((cpu_set_t*)option);
661 8 case OPT_MODE_T:
662 8 return mode_tostr(*(interaction_mode_t*)option);
663 6 case OPT_MPISET_T:
664 6 return mpiset_tostr(*(mpi_set_t*)option);
665 4 case OPT_OMPTOPTS_T:
666 4 return omptool_opts_tostr(*(omptool_opts_t*)option);
667 4 case OPT_TLPSUM_T:
668 4 return talp_summary_tostr(*(talp_summary_t*)option);
669 1 case OPT_TLPMOD_T:
670 1 return talp_model_tostr(*(talp_model_t*)option);
671 4 case OPT_OMPTM_T:
672 4 return omptm_version_tostr(*(omptm_version_t*)option);
673 }
674 return "unknown";
675 }
676
677 1 static bool values_are_equivalent(option_type_t type, const char *value1, const char *value2) {
678
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) {
679 1 case OPT_BOOL_T:
680 1 return equivalent_bool(value1, value2);
681 case OPT_NEG_BOOL_T:
682 return equivalent_negated_bool(value1, value2);
683 case OPT_INT_T:
684 return equivalent_int(value1, value2);
685 case OPT_STR_T:
686 return strcmp(value1, value2) == 0;
687 case OPT_PTR_PATH_T:
688 return *(const char**)value1 && *(const char**)value2
689 && strcmp(*(const char**)value1, *(const char**)value2) == 0;
690 case OPT_VB_T:
691 return equivalent_verbose_opts(value1, value2);
692 case OPT_VBFMT_T:
693 return equivalent_verbose_fmt(value1, value2);
694 case OPT_INST_T:
695 return equivalent_instrument_items(value1, value2);
696 case OPT_DBG_T:
697 return equivalent_debug_opts(value1, value2);
698 case OPT_LEWI_AFF_T:
699 return equivalent_lewi_affinity(value1, value2);
700 case OPT_MASK_T:
701 return mu_equivalent_masks(value1, value2);
702 case OPT_MODE_T:
703 return equivalent_mode(value1, value2);
704 case OPT_MPISET_T:
705 return equivalent_mpiset(value1, value2);
706 case OPT_OMPTOPTS_T:
707 return equivalent_omptool_opts(value1, value2);
708 case OPT_TLPSUM_T:
709 return equivalent_talp_summary(value1, value2);
710 case OPT_TLPMOD_T:
711 return equivalent_talp_model(value1, value2);
712 case OPT_OMPTM_T:
713 return equivalent_omptm_version_opts(value1, value2);
714 }
715 return false;
716 }
717
718 16 static void copy_value(option_type_t type, void *dest, const char *src) {
719
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) {
720 1 case OPT_BOOL_T:
721 1 memcpy(dest, src, sizeof(bool));
722 1 break;
723 1 case OPT_NEG_BOOL_T:
724 1 memcpy(dest, src, sizeof(bool));
725 1 break;
726 3 case OPT_INT_T:
727 3 memcpy(dest, src, sizeof(int));
728 3 break;
729 2 case OPT_STR_T:
730 2 memcpy(dest, src, sizeof(char)*MAX_OPTION_LENGTH);
731 2 break;
732 case OPT_PTR_PATH_T:
733 fatal("copy_value of type OPT_PTR_PATH_T not supported");
734 break;
735 1 case OPT_VB_T:
736 1 memcpy(dest, src, sizeof(verbose_opts_t));
737 1 break;
738 1 case OPT_VBFMT_T:
739 1 memcpy(dest, src, sizeof(verbose_fmt_t));
740 1 break;
741 1 case OPT_INST_T:
742 1 memcpy(dest, src, sizeof(instrument_items_t));
743 1 break;
744 case OPT_DBG_T:
745 memcpy(dest, src, sizeof(debug_opts_t));
746 break;
747 1 case OPT_LEWI_AFF_T:
748 1 memcpy(dest, src, sizeof(lewi_affinity_t));
749 1 break;
750 case OPT_MASK_T:
751 memcpy(dest, src, sizeof(cpu_set_t));
752 break;
753 1 case OPT_MODE_T:
754 1 memcpy(dest, src, sizeof(interaction_mode_t));
755 1 break;
756 1 case OPT_MPISET_T:
757 1 memcpy(dest, src, sizeof(mpi_set_t));
758 1 break;
759 1 case OPT_OMPTOPTS_T:
760 1 memcpy(dest, src, sizeof(omptool_opts_t));
761 1 break;
762 1 case OPT_TLPSUM_T:
763 1 memcpy(dest, src, sizeof(talp_summary_t));
764 1 break;
765 1 case OPT_TLPMOD_T:
766 1 memcpy(dest, src, sizeof(talp_model_t));
767 1 break;
768 case OPT_OMPTM_T:
769 memcpy(dest, src, sizeof(omptm_version_t));
770 break;
771 }
772 16 }
773
774 /* Parse DLB_ARGS and remove argument if found */
775 12073 static void parse_dlb_args(char *dlb_args, const char *arg_name, char* arg_value, size_t arg_max_len) {
776 12073 *arg_value = 0;
777 /* Tokenize a copy of dlb_args with " "(blank) delimiter */
778 12073 char *progress = dlb_args;
779 12073 char *end_space = NULL;
780 12073 size_t len = strlen(dlb_args) + 1;
781 12073 char *dlb_args_copy = malloc(sizeof(char)*len);
782 12073 strcpy(dlb_args_copy, dlb_args);
783 12073 char *token = strtok_r(dlb_args_copy, " ", &end_space);
784
2/2
✓ Branch 0 taken 7848 times.
✓ Branch 1 taken 12073 times.
19921 while (token) {
785 /* Each token is a complete string representing an option */
786
787 7848 bool remove_token = false;
788 /* token length must be computed before tokenizing into arg=val */
789 7848 size_t token_len = strlen(token);
790 /* progress pointer must be updated each iteration to skip spaces */
791
2/2
✓ Branch 0 taken 10084 times.
✓ Branch 1 taken 7848 times.
17932 while(isspace((unsigned char)*progress)) progress++;
792
793
2/2
✓ Branch 0 taken 6918 times.
✓ Branch 1 taken 930 times.
7848 if (strchr(token, '=')) {
794 /* Option is of the form --argument=value */
795 6918 char *end_equal = NULL;
796 6918 char *argument = strtok_r(token, "=", &end_equal);
797
2/2
✓ Branch 0 taken 295 times.
✓ Branch 1 taken 6623 times.
6918 if (strcmp(argument, arg_name) == 0) {
798 /* Obtain value */
799 295 char *value = strtok_r(NULL, "=", &end_equal);
800
2/2
✓ Branch 0 taken 294 times.
✓ Branch 1 taken 1 times.
295 if (value) {
801 294 snprintf(arg_value, arg_max_len, "%s", value);
802 } else {
803 1 warning("Bad format parsing of DLB_ARGS. Option %s with empty value", token);
804 }
805 295 remove_token = true;
806 }
807 } else {
808 /* Option is of the form --argument/--no-argument */
809 930 char *argument = token;
810
2/2
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 775 times.
930 if (strcmp(argument, arg_name) == 0) {
811 /* Option value is 'yes' */
812 155 strcpy(arg_value, "yes");
813 155 remove_token = true;
814
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 757 times.
775 } else if (strncmp(argument, "--no-", 5) == 0
815
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 5 times.
18 && strcmp(argument+5, arg_name+2) == 0) {
816 /* Option value is 'no' */
817 13 strcpy(arg_value, "no");
818 13 remove_token = true;
819 }
820 }
821
822
2/2
✓ Branch 0 taken 463 times.
✓ Branch 1 taken 7385 times.
7848 if (remove_token) {
823 /* Remove token from dlb_args */
824 463 char *dest = progress;
825 463 char *src = progress + token_len;
826 463 size_t n = strlen(src) + 1;
827 463 memmove(dest, src, n);
828 } else {
829 /* Token is not removed, update parsed progress pointer */
830 7385 progress += token_len;
831 }
832
833 /* next token */
834 7848 token = strtok_r(NULL, " ", &end_space);
835 }
836 12073 free(dlb_args_copy);
837 12073 }
838
839 /* Initialize options struct from either argument, or env. variable */
840 175 void options_init(options_t *options, const char *dlb_args) {
841 /* Copy dlb_args into a local buffer */
842 175 char *dlb_args_from_api = NULL;
843
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 31 times.
175 if (dlb_args) {
844 144 size_t len = strlen(dlb_args) + 1;
845 144 dlb_args_from_api = malloc(sizeof(char)*len);
846 144 strcpy(dlb_args_from_api, dlb_args);
847 }
848
849 /* Copy either DLB_ARGS or LB_ARGS into a local buffer */
850 175 char *dlb_args_from_env = NULL;
851 175 const char *env = getenv("DLB_ARGS");
852
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 144 times.
175 if (!env) {
853 31 env = getenv("LB_ARGS");
854
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
31 if (env) {
855 warning("LB_ARGS is deprecated, please use DLB_ARGS");
856 }
857 }
858
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 31 times.
175 if (env) {
859 144 size_t len = strlen(env) + 1;
860 144 dlb_args_from_env = malloc(sizeof(char)*len);
861 144 strcpy(dlb_args_from_env, env);
862 }
863
864 /* Preallocate two buffers large enough to save any intermediate option value */
865 175 char *arg_value_from_api = malloc(sizeof(char)*PATH_MAX);
866 175 char *arg_value_from_env = malloc(sizeof(char)*PATH_MAX);
867
868 int i;
869
2/2
✓ Branch 0 taken 7175 times.
✓ Branch 1 taken 175 times.
7350 for (i=0; i<NUM_OPTIONS; ++i) {
870 7175 const opts_dict_t *entry = &options_dictionary[i];
871 7175 const char *rhs = NULL; /* pointer to rhs to be parsed */
872
873 /* Set-up specific argument length */
874 size_t arg_max_len;
875
2/2
✓ Branch 0 taken 175 times.
✓ Branch 1 taken 7000 times.
7175 switch (entry->type) {
876 175 case OPT_PTR_PATH_T:
877 175 arg_max_len = PATH_MAX-1;
878 175 break;
879 7000 default:
880 7000 arg_max_len = MAX_OPTION_LENGTH-1;
881 7000 break;
882 }
883
884 /* Reset intermediate buffers */
885 7175 arg_value_from_api[0] = '\0';
886 7175 arg_value_from_env[0] = '\0';
887
888 /* Parse dlb_args from API */
889
2/2
✓ Branch 0 taken 5904 times.
✓ Branch 1 taken 1271 times.
7175 if (dlb_args_from_api) {
890 5904 parse_dlb_args(dlb_args_from_api, entry->arg_name, arg_value_from_api, arg_max_len);
891
2/2
✓ Branch 0 taken 340 times.
✓ Branch 1 taken 5564 times.
5904 if (strlen(arg_value_from_api) > 0) {
892 340 rhs = arg_value_from_api;
893 }
894 }
895
896 /* Parse DLB_ARGS from env */
897
2/2
✓ Branch 0 taken 5904 times.
✓ Branch 1 taken 1271 times.
7175 if (dlb_args_from_env) {
898 5904 parse_dlb_args(dlb_args_from_env, entry->arg_name, arg_value_from_env, arg_max_len);
899
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 5818 times.
5904 if (strlen(arg_value_from_env) > 0) {
900
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)) {
901 1 warning("Overwriting option %s = %s",
902 1 entry->arg_name, arg_value_from_env);
903 }
904 86 rhs = arg_value_from_env;
905 }
906 }
907
908 /* Parse LB_option (to be deprecated soon) */
909 7175 const char *arg_value = getenv(entry->var_name);
910
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7175 times.
7175 if (arg_value) {
911 if (rhs) {
912 warning("Ignoring option %s = %s due to DLB_ARGS precedence",
913 entry->var_name, arg_value);
914 } else {
915 warning("Option %s is to be deprecated in the near future, please use DLB_ARGS",
916 entry->var_name);
917 rhs = arg_value;
918 }
919 }
920
921 /* Warn if option is deprecated and has rhs */
922
4/4
✓ Branch 0 taken 525 times.
✓ Branch 1 taken 6650 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 522 times.
7175 if (entry->flags & OPT_DEPRECATED && rhs) {
923 3 warning("Option %s is deprecated:\n%s", entry->arg_name, entry->description);
924 }
925
926 /* Skip iteration if option is not used anymore */
927
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7175 times.
7175 if (entry->flags & OPT_UNUSED) {
928 continue;
929 }
930
931 /* Assign option = rhs, and nullify rhs if error */
932
2/2
✓ Branch 0 taken 425 times.
✓ Branch 1 taken 6750 times.
7175 if (rhs) {
933 425 int error = set_value(entry->type, (char*)options+entry->offset, rhs);
934
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 425 times.
425 if (error) {
935 warning("Unrecognized %s value: %s. Setting default %s",
936 entry->arg_name, rhs, entry->default_value);
937 rhs = NULL;
938 }
939 }
940
941 /* Set default value if needed */
942
4/4
✓ Branch 0 taken 6750 times.
✓ Branch 1 taken 425 times.
✓ Branch 2 taken 6228 times.
✓ Branch 3 taken 522 times.
7175 if (!rhs && !(entry->flags & OPT_DEPRECATED)) {
943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6228 times.
6228 fatal_cond(!(entry->flags & OPT_OPTIONAL),
944 "Variable %s must be defined", entry->arg_name);
945 6228 int error = set_value(entry->type, (char*)options+entry->offset, entry->default_value);
946
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6228 times.
6228 fatal_cond(error, "Internal error parsing default value %s=%s. Please, report bug at %s.",
947 entry->arg_name, entry->default_value, PACKAGE_BUGREPORT);
948 }
949 }
950
951 /* Free intermediate buffers */
952 175 free(arg_value_from_api);
953 175 free(arg_value_from_env);
954
955 /* Safety checks and free local buffers */
956
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 31 times.
175 if (dlb_args_from_api) {
957 144 char *str = dlb_args_from_api;
958
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 144 times.
364 while(isspace((unsigned char)*str)) str++;
959
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 141 times.
144 if (strlen(str) > 0) {
960
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (options->debug_opts & DBG_WERROR) {
961 fatal("Unrecognized flags from DLB_Init: %s", str);
962 } else {
963 3 warning("Unrecognized flags from DLB_Init: %s", str);
964 }
965 }
966 144 free(dlb_args_from_api);
967 }
968
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 31 times.
175 if (dlb_args_from_env) {
969 144 char *str = dlb_args_from_env;
970
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 144 times.
336 while(isspace((unsigned char)*str)) str++;
971
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 143 times.
144 if (strlen(str) > 0) {
972
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (options->debug_opts & DBG_WERROR) {
973 fatal("Unrecognized flags from DLB_ARGS: %s", str);
974 } else {
975 1 warning("Unrecognized flags from DLB_ARGS: %s", str);
976 }
977 }
978 144 free(dlb_args_from_env);
979 }
980 175 }
981
982 89 void options_finalize(options_t *options) {
983
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 88 times.
89 if (options->talp_output_file) {
984 1 free(options->talp_output_file);
985 1 options->talp_output_file = NULL;
986 }
987 89 }
988
989 /* Obtain value of specific entry, either from DLB_ARGS or from thread_spd->options */
990 285 void options_parse_entry(const char *var_name, void *option) {
991 285 const opts_dict_t *entry = get_entry_by_name(var_name);
992
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285 times.
285 ensure(entry, "%s: bad variable name '%s'", __func__, var_name);
993
994
4/4
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 223 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 46 times.
285 if (thread_spd && thread_spd->dlb_initialized) {
995 16 copy_value(entry->type, option, (char*)&thread_spd->options + entry->offset);
996 } else {
997 /* Simplified options_init just for this entry */
998
999 /* Copy DLB_ARGS into a local buffer */
1000 269 char *dlb_args_from_env = NULL;
1001 269 const char *env = getenv("DLB_ARGS");
1002
2/2
✓ Branch 0 taken 265 times.
✓ Branch 1 taken 4 times.
269 if (env) {
1003 265 size_t len = strlen(env) + 1;
1004 265 dlb_args_from_env = malloc(sizeof(char)*len);
1005 265 strcpy(dlb_args_from_env, env);
1006 }
1007
1008 /* Pointer to rhs to be parsed */
1009 269 const char *rhs = NULL;
1010
1011 /* Set-up specific argument length */
1012 size_t arg_max_len;
1013
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 269 times.
269 switch (entry->type) {
1014 case OPT_PTR_PATH_T:
1015 arg_max_len = PATH_MAX-1;
1016 break;
1017 269 default:
1018 269 arg_max_len = MAX_OPTION_LENGTH-1;
1019 269 break;
1020 }
1021
1022 /* Preallocate a buffer large enough to save the option value */
1023 269 char *arg_value_from_env = malloc(sizeof(char)*(arg_max_len+1));
1024 269 arg_value_from_env[0] = '\0';
1025
1026 /* Parse DLB_ARGS from env */
1027
2/2
✓ Branch 0 taken 265 times.
✓ Branch 1 taken 4 times.
269 if (dlb_args_from_env) {
1028 265 parse_dlb_args(dlb_args_from_env, entry->arg_name, arg_value_from_env, arg_max_len);
1029
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 235 times.
265 if (strlen(arg_value_from_env) > 0) {
1030 30 rhs = arg_value_from_env;
1031 }
1032 }
1033
1034 /* Assign option = rhs, and nullify rhs if error */
1035
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 239 times.
269 if (rhs) {
1036 30 int error = set_value(entry->type, option, rhs);
1037
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (error) {
1038 rhs = NULL;
1039 }
1040 }
1041
1042 /* Set default value if needed */
1043
2/2
✓ Branch 0 taken 239 times.
✓ Branch 1 taken 30 times.
269 if (!rhs) {
1044 239 set_value(entry->type, option, entry->default_value);
1045 }
1046
1047 /* Free buffers */
1048 269 free(arg_value_from_env);
1049
2/2
✓ Branch 0 taken 265 times.
✓ Branch 1 taken 4 times.
269 if (dlb_args_from_env) {
1050 265 free(dlb_args_from_env);
1051 }
1052 }
1053 285 }
1054
1055 /* API Setter */
1056 8 int options_set_variable(options_t *options, const char *var_name, const char *value) {
1057 int error;
1058 8 const opts_dict_t *entry = get_entry_by_name(var_name);
1059
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
8 if (entry) {
1060
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (entry->flags & OPT_READONLY) {
1061 3 error = DLB_ERR_PERM;
1062 } else {
1063 4 error = set_value(entry->type, (char*)options+entry->offset, value);
1064 }
1065 } else {
1066 1 error = DLB_ERR_NOENT;
1067 }
1068
1069 8 return error;
1070 }
1071
1072 /* API Getter */
1073 14 int options_get_variable(const options_t *options, const char *var_name, char *value) {
1074 int error;
1075 14 const opts_dict_t *entry = get_entry_by_name(var_name);
1076
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 if (entry) {
1077 13 sprintf(value, "%s", get_value(entry->type, (char*)options+entry->offset));
1078 13 error = DLB_SUCCESS;
1079 } else {
1080 1 error = DLB_ERR_NOENT;
1081 }
1082
1083 14 return error;
1084 }
1085
1086 /* API Printer. Also, dlb -h/-hh output */
1087 4 void options_print_variables(const options_t *options, bool print_extended) {
1088
1089 /* Initialize buffer */
1090 print_buffer_t buffer;
1091 4 printbuffer_init(&buffer);
1092
1093 /* Set up intermediate buffer per entry */
1094 enum { MAX_ENTRY_LEN = 256 };
1095 char entry_buffer[MAX_ENTRY_LEN];
1096
1097 /* Header (last \n is not needed) */
1098 4 printbuffer_append(&buffer,
1099 "DLB Options:\n\n"
1100 "DLB is configured by setting these flags in the DLB_ARGS environment variable.\n"
1101 "Possible options are listed below:\n\n"
1102 "Option Current value Possible value (type) / [choice] / {val1:val2}\n"
1103 "--------------------------------------------------------------------------------------"
1104 );
1105
1106 int i;
1107
2/2
✓ Branch 0 taken 164 times.
✓ Branch 1 taken 4 times.
168 for (i=0; i<NUM_OPTIONS; ++i) {
1108 164 const opts_dict_t *entry = &options_dictionary[i];
1109
1110 /* Skip if deprecated */
1111
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 152 times.
164 if (entry->flags & OPT_DEPRECATED) continue;
1112
1113 /* Skip if hidden */
1114
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 148 times.
152 if (entry->flags & OPT_HIDDEN) continue;
1115
1116 /* Skip if advanced (unless print_extended) */
1117
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 116 times.
148 if (entry->flags & OPT_ADVANCED
1118
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 && !print_extended) continue;
1119
1120 /* Reset entry buffer */
1121 124 entry_buffer[0] = '\0';
1122 124 char *b = entry_buffer;
1123 124 size_t max_entry_len = MAX_ENTRY_LEN;
1124
1125 /* Name */
1126 124 size_t name_len = strlen(entry->arg_name) + 1;
1127
2/2
✓ Branch 0 taken 119 times.
✓ Branch 1 taken 5 times.
124 if (name_len < 24) {
1128 /* Option + tabs until column 24 */
1129
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 20 times.
218 b += snprintf(b, max_entry_len, "%s:%s",
1130 119 entry->arg_name,
1131
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");
1132 } else {
1133 /* Long option, break line */
1134 5 b += snprintf(b, max_entry_len, "%s:\n\t\t\t",
1135 5 entry->arg_name);
1136 }
1137
1138 /* Check if output was truncated, and update remaining entry length */
1139
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
124 fatal_cond((b - entry_buffer) >= MAX_ENTRY_LEN,
1140 "Output truncated in in %s. Please report bug at %s",
1141 __func__, PACKAGE_BUGREPORT);
1142 124 max_entry_len = MAX_ENTRY_LEN - (b - entry_buffer);
1143
1144 /* Value */
1145 124 const char *value = get_value(entry->type, (char*)options+entry->offset);
1146 124 size_t value_len = strlen(value) + 1;
1147
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 111 times.
137 b += snprintf(b, max_entry_len, "%s %s",
1148 value,
1149
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 value_len < 8 ? "\t\t" : value_len < 16 ? "\t" : "");
1150
1151 /* Check if output was truncated, and update remaining entry length */
1152
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
124 fatal_cond((b - entry_buffer) >= MAX_ENTRY_LEN,
1153 "Output truncated in in %s. Please report bug at %s",
1154 __func__, PACKAGE_BUGREPORT);
1155 124 max_entry_len = MAX_ENTRY_LEN - (b - entry_buffer);
1156
1157 /* Choices */
1158
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) {
1159 64 case OPT_BOOL_T:
1160 64 b += snprintf(b, max_entry_len, "(bool)");
1161 64 break;
1162 case OPT_NEG_BOOL_T:
1163 b += snprintf(b, max_entry_len, "(bool)");
1164 break;
1165 11 case OPT_INT_T:
1166 11 b += snprintf(b, max_entry_len, "(int)");
1167 11 break;
1168 7 case OPT_STR_T:
1169 7 b += snprintf(b, max_entry_len, "(string)");
1170 7 break;
1171 4 case OPT_PTR_PATH_T:
1172 4 b += snprintf(b, max_entry_len, "(path)");
1173 4 break;
1174 4 case OPT_VB_T:
1175 4 b += snprintf(b, max_entry_len, "{%s}", get_verbose_opts_choices());
1176 4 break;
1177 4 case OPT_VBFMT_T:
1178 4 b += snprintf(b, max_entry_len, "{%s}", get_verbose_fmt_choices());
1179 4 break;
1180 4 case OPT_INST_T:
1181 4 b += snprintf(b, max_entry_len, "{%s}", get_instrument_items_choices());
1182 4 break;
1183 1 case OPT_DBG_T:
1184 1 b += snprintf(b, max_entry_len, "{%s}", get_debug_opts_choices());
1185 1 break;
1186 4 case OPT_LEWI_AFF_T:
1187 4 b += snprintf(b, max_entry_len, "[%s]", get_lewi_affinity_choices());
1188 4 break;
1189 case OPT_MASK_T:
1190 b += snprintf(b, max_entry_len, "(cpuset)");
1191 break;
1192 4 case OPT_MODE_T:
1193 4 b += snprintf(b, max_entry_len, "[%s]", get_mode_choices());
1194 4 break;
1195 4 case OPT_MPISET_T:
1196 4 b += snprintf(b, max_entry_len, "[%s]", get_mpiset_choices());
1197 4 break;
1198 4 case OPT_OMPTOPTS_T:
1199 4 b += snprintf(b, max_entry_len, "[%s]", get_omptool_opts_choices());
1200 4 break;
1201 4 case OPT_TLPSUM_T:
1202 4 b += snprintf(b, max_entry_len, "{%s}", get_talp_summary_choices());
1203 4 break;
1204 1 case OPT_TLPMOD_T:
1205 1 b += snprintf(b, max_entry_len, "[%s]", get_talp_model_choices());
1206 1 break;
1207 4 case OPT_OMPTM_T:
1208 4 b += snprintf(b, max_entry_len, "[%s]", get_omptm_version_choices());
1209 4 break;
1210 }
1211
1212 /* Check if output was truncated */
1213
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
124 fatal_cond((b - entry_buffer) >= MAX_ENTRY_LEN,
1214 "Buffer overflow in %s. Please report bug at %s",
1215 __func__, PACKAGE_BUGREPORT);
1216
1217 /* Append entry listing */
1218 124 printbuffer_append(&buffer, entry_buffer);
1219
1220 /* Append long description if print_extended */
1221
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 87 times.
124 if (print_extended) {
1222 37 printbuffer_append(&buffer, entry->description);
1223 37 printbuffer_append(&buffer, "");
1224 }
1225
1226 }
1227
1228 /* Footer (last \n is not needed) */
1229 4 printbuffer_append(&buffer,
1230 "\n"
1231 "Boolean options accept both standalone flags and 'yes'/'no' parameters.\n"
1232 "These are equivalent flags:\n"
1233 " export DLB_ARGS=\"--lewi --no-drom\"\n"
1234 " export DLB_ARGS=\"--lewi=yes --drom=no\"");
1235
1236 /* This function must print always and ignore options --quiet and --silent */
1237 4 info0_force_print("%s", buffer.addr);
1238
1239 4 printbuffer_destroy(&buffer);
1240 4 }
1241
1242 /* Print which LeWI flags are enabled during DLB_Init */
1243 57 void options_print_lewi_flags(const options_t *options) {
1244 const opts_dict_t *entry;
1245
1246 // --lewi-mpi
1247 bool default_lewi_keep_one_cpu;
1248 57 entry = get_entry_by_name("--lewi-keep-one-cpu");
1249 57 parse_bool(entry->default_value, &default_lewi_keep_one_cpu);
1250
1251 // --lewi-mpi-calls
1252 mpi_set_t default_lewi_mpi_calls;
1253 57 entry = get_entry_by_name("--lewi-mpi-calls");
1254 57 parse_mpiset(entry->default_value, &default_lewi_mpi_calls);
1255
1256 // --lewi-affinity
1257 lewi_affinity_t default_lewi_affinity;
1258 57 entry = get_entry_by_name("--lewi-affinity");
1259 57 parse_lewi_affinity(entry->default_value, &default_lewi_affinity);
1260
1261 // --lewi-ompt
1262 omptool_opts_t default_lewi_ompt;
1263 57 entry = get_entry_by_name("--lewi-ompt");
1264 57 parse_omptool_opts(entry->default_value, &default_lewi_ompt);
1265
1266
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
1267
1/2
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
57 || options->lewi_mpi_calls != default_lewi_mpi_calls
1268
1/2
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
57 || options->lewi_affinity != default_lewi_affinity
1269
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 || options->lewi_ompt != default_lewi_ompt) {
1270 info0("LeWI options:");
1271 if (options->lewi_keep_cpu_on_blocking_call != default_lewi_keep_one_cpu) {
1272 info0(" --lewi-keep-one-cpu");
1273 }
1274 if (options->lewi_mpi_calls != default_lewi_mpi_calls) {
1275 info0(" --lewi-mpi-calls=%s", mpiset_tostr(options->lewi_mpi_calls));
1276 }
1277 if (options->lewi_affinity != default_lewi_affinity) {
1278 info0(" --lewi-affinity=%s", lewi_affinity_tostr(options->lewi_affinity));
1279 }
1280 if (options->lewi_ompt != default_lewi_ompt) {
1281 info0(" --lewi-ompt=%s", omptool_opts_tostr(options->lewi_ompt));
1282 }
1283 }
1284 57 }
1285