GCC Code Coverage Report


Directory: src/
File: src/support/options.c
Date: 2025-11-28 11:16:41
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 506 static const opts_dict_t* get_entry_by_name(const char *name) {
571 int i;
572
2/2
✓ Branch 0 taken 8886 times.
✓ Branch 1 taken 2 times.
8888 for (i=0; i<NUM_OPTIONS; ++i) {
573 8886 const opts_dict_t *entry = &options_dictionary[i];
574
1/2
✓ Branch 0 taken 8886 times.
✗ Branch 1 not taken.
8886 if (strcasecmp(entry->var_name, name) == 0
575
2/2
✓ Branch 0 taken 504 times.
✓ Branch 1 taken 8382 times.
8886 || strcasecmp(entry->arg_name, name) == 0) {
576 504 return entry;
577 }
578 }
579 2 return NULL;
580 }
581
582 173 static int set_ptr_path_value(void *option, const char *str_value) {
583 173 int path_len = snprintf(NULL, 0, "%s", str_value) + 1;
584
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 172 times.
173 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 172 *(char**)option = NULL;
589 }
590 173 return DLB_SUCCESS;
591 }
592
593 6821 static int set_value(option_type_t type, void *option, const char *str_value) {
594
16/18
✓ Branch 0 taken 2866 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1087 times.
✓ Branch 3 taken 717 times.
✓ Branch 4 taken 173 times.
✓ Branch 5 taken 233 times.
✓ Branch 6 taken 174 times.
✓ Branch 7 taken 174 times.
✓ Branch 8 taken 175 times.
✓ Branch 9 taken 174 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 174 times.
✓ Branch 12 taken 175 times.
✓ Branch 13 taken 174 times.
✓ Branch 14 taken 174 times.
✓ Branch 15 taken 174 times.
✓ Branch 16 taken 173 times.
✗ Branch 17 not taken.
6821 switch(type) {
595 2866 case OPT_BOOL_T:
596 2866 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 1087 case OPT_INT_T:
600 1087 return parse_int(str_value, (int*)option);
601 717 case OPT_STR_T:
602 717 snprintf(option, MAX_OPTION_LENGTH, "%s", str_value);
603 717 return DLB_SUCCESS;
604 173 case OPT_PTR_PATH_T:
605 173 return set_ptr_path_value(option, str_value);
606 233 case OPT_VB_T:
607 233 return parse_verbose_opts(str_value, (verbose_opts_t*)option);
608 174 case OPT_VBFMT_T:
609 174 return parse_verbose_fmt(str_value, (verbose_fmt_t*)option);
610 174 case OPT_INST_T:
611 174 return parse_instrument_items(str_value, (instrument_items_t*)option);
612 175 case OPT_DBG_T:
613 175 return parse_debug_opts(str_value, (debug_opts_t*)option);
614 174 case OPT_LEWI_AFF_T:
615 174 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 174 case OPT_MODE_T:
620 174 return parse_mode(str_value, (interaction_mode_t*)option);
621 175 case OPT_MPISET_T:
622 175 return parse_mpiset(str_value, (mpi_set_t*)option);
623 174 case OPT_OMPTOPTS_T:
624 174 return parse_omptool_opts(str_value, (omptool_opts_t*)option);
625 174 case OPT_TLPSUM_T:
626 174 return parse_talp_summary(str_value, (talp_summary_t*)option);
627 174 case OPT_TLPMOD_T:
628 174 return parse_talp_model(str_value, (talp_model_t*)option);
629 173 case OPT_OMPTM_T:
630 173 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 11962 static void parse_dlb_args(char *dlb_args, const char *arg_name, char* arg_value, size_t arg_max_len) {
776 11962 *arg_value = 0;
777 /* Tokenize a copy of dlb_args with " "(blank) delimiter */
778 11962 char *progress = dlb_args;
779 11962 char *end_space = NULL;
780 11962 size_t len = strlen(dlb_args) + 1;
781 11962 char *dlb_args_copy = malloc(sizeof(char)*len);
782 11962 strcpy(dlb_args_copy, dlb_args);
783 11962 char *token = strtok_r(dlb_args_copy, " ", &end_space);
784
2/2
✓ Branch 0 taken 7829 times.
✓ Branch 1 taken 11962 times.
19791 while (token) {
785 /* Each token is a complete string representing an option */
786
787 7829 bool remove_token = false;
788 /* token length must be computed before tokenizing into arg=val */
789 7829 size_t token_len = strlen(token);
790 /* progress pointer must be updated each iteration to skip spaces */
791
2/2
✓ Branch 0 taken 10082 times.
✓ Branch 1 taken 7829 times.
17911 while(isspace((unsigned char)*progress)) progress++;
792
793
2/2
✓ Branch 0 taken 6899 times.
✓ Branch 1 taken 930 times.
7829 if (strchr(token, '=')) {
794 /* Option is of the form --argument=value */
795 6899 char *end_equal = NULL;
796 6899 char *argument = strtok_r(token, "=", &end_equal);
797
2/2
✓ Branch 0 taken 293 times.
✓ Branch 1 taken 6606 times.
6899 if (strcmp(argument, arg_name) == 0) {
798 /* Obtain value */
799 293 char *value = strtok_r(NULL, "=", &end_equal);
800
2/2
✓ Branch 0 taken 292 times.
✓ Branch 1 taken 1 times.
293 if (value) {
801 292 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 293 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 461 times.
✓ Branch 1 taken 7368 times.
7829 if (remove_token) {
823 /* Remove token from dlb_args */
824 461 char *dest = progress;
825 461 char *src = progress + token_len;
826 461 size_t n = strlen(src) + 1;
827 461 memmove(dest, src, n);
828 } else {
829 /* Token is not removed, update parsed progress pointer */
830 7368 progress += token_len;
831 }
832
833 /* next token */
834 7829 token = strtok_r(NULL, " ", &end_space);
835 }
836 11962 free(dlb_args_copy);
837 11962 }
838
839 /* Initialize options struct from either argument, or env. variable */
840 173 void options_init(options_t *options, const char *dlb_args) {
841 /* Copy dlb_args into a local buffer */
842 173 char *dlb_args_from_api = NULL;
843
2/2
✓ Branch 0 taken 142 times.
✓ Branch 1 taken 31 times.
173 if (dlb_args) {
844 142 size_t len = strlen(dlb_args) + 1;
845 142 dlb_args_from_api = malloc(sizeof(char)*len);
846 142 strcpy(dlb_args_from_api, dlb_args);
847 }
848
849 /* Copy either DLB_ARGS or LB_ARGS into a local buffer */
850 173 char *dlb_args_from_env = NULL;
851 173 const char *env = getenv("DLB_ARGS");
852
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 144 times.
173 if (!env) {
853 29 env = getenv("LB_ARGS");
854
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 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 29 times.
173 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 173 char *arg_value_from_api = malloc(sizeof(char)*PATH_MAX);
866 173 char *arg_value_from_env = malloc(sizeof(char)*PATH_MAX);
867
868 int i;
869
2/2
✓ Branch 0 taken 7093 times.
✓ Branch 1 taken 173 times.
7266 for (i=0; i<NUM_OPTIONS; ++i) {
870 7093 const opts_dict_t *entry = &options_dictionary[i];
871 7093 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 173 times.
✓ Branch 1 taken 6920 times.
7093 switch (entry->type) {
876 173 case OPT_PTR_PATH_T:
877 173 arg_max_len = PATH_MAX-1;
878 173 break;
879 6920 default:
880 6920 arg_max_len = MAX_OPTION_LENGTH-1;
881 6920 break;
882 }
883
884 /* Reset intermediate buffers */
885 7093 arg_value_from_api[0] = '\0';
886 7093 arg_value_from_env[0] = '\0';
887
888 /* Parse dlb_args from API */
889
2/2
✓ Branch 0 taken 5822 times.
✓ Branch 1 taken 1271 times.
7093 if (dlb_args_from_api) {
890 5822 parse_dlb_args(dlb_args_from_api, entry->arg_name, arg_value_from_api, arg_max_len);
891
2/2
✓ Branch 0 taken 338 times.
✓ Branch 1 taken 5484 times.
5822 if (strlen(arg_value_from_api) > 0) {
892 338 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 1189 times.
7093 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 7093 const char *arg_value = getenv(entry->var_name);
910
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7093 times.
7093 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 519 times.
✓ Branch 1 taken 6574 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 516 times.
7093 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 7093 times.
7093 if (entry->flags & OPT_UNUSED) {
928 continue;
929 }
930
931 /* Assign option = rhs, and nullify rhs if error */
932
2/2
✓ Branch 0 taken 423 times.
✓ Branch 1 taken 6670 times.
7093 if (rhs) {
933 423 int error = set_value(entry->type, (char*)options+entry->offset, rhs);
934
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 423 times.
423 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 6670 times.
✓ Branch 1 taken 423 times.
✓ Branch 2 taken 6154 times.
✓ Branch 3 taken 516 times.
7093 if (!rhs && !(entry->flags & OPT_DEPRECATED)) {
943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6154 times.
6154 fatal_cond(!(entry->flags & OPT_OPTIONAL),
944 "Variable %s must be defined", entry->arg_name);
945 6154 int error = set_value(entry->type, (char*)options+entry->offset, entry->default_value);
946
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6154 times.
6154 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 173 free(arg_value_from_api);
953 173 free(arg_value_from_env);
954
955 /* Safety checks and free local buffers */
956
2/2
✓ Branch 0 taken 142 times.
✓ Branch 1 taken 31 times.
173 if (dlb_args_from_api) {
957 142 char *str = dlb_args_from_api;
958
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 142 times.
362 while(isspace((unsigned char)*str)) str++;
959
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 139 times.
142 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 142 free(dlb_args_from_api);
967 }
968
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 29 times.
173 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 173 }
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 256 void options_parse_entry(const char *var_name, void *option) {
991 256 const opts_dict_t *entry = get_entry_by_name(var_name);
992
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 256 times.
256 ensure(entry, "%s: bad variable name '%s'", __func__, var_name);
993
994
4/4
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 194 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 46 times.
256 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 240 char *dlb_args_from_env = NULL;
1001 240 const char *env = getenv("DLB_ARGS");
1002
2/2
✓ Branch 0 taken 236 times.
✓ Branch 1 taken 4 times.
240 if (env) {
1003 236 size_t len = strlen(env) + 1;
1004 236 dlb_args_from_env = malloc(sizeof(char)*len);
1005 236 strcpy(dlb_args_from_env, env);
1006 }
1007
1008 /* Pointer to rhs to be parsed */
1009 240 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 240 times.
240 switch (entry->type) {
1014 case OPT_PTR_PATH_T:
1015 arg_max_len = PATH_MAX-1;
1016 break;
1017 240 default:
1018 240 arg_max_len = MAX_OPTION_LENGTH-1;
1019 240 break;
1020 }
1021
1022 /* Preallocate a buffer large enough to save the option value */
1023 240 char *arg_value_from_env = malloc(sizeof(char)*(arg_max_len+1));
1024 240 arg_value_from_env[0] = '\0';
1025
1026 /* Parse DLB_ARGS from env */
1027
2/2
✓ Branch 0 taken 236 times.
✓ Branch 1 taken 4 times.
240 if (dlb_args_from_env) {
1028 236 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 206 times.
236 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 210 times.
240 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 210 times.
✓ Branch 1 taken 30 times.
240 if (!rhs) {
1044 210 set_value(entry->type, option, entry->default_value);
1045 }
1046
1047 /* Free buffers */
1048 240 free(arg_value_from_env);
1049
2/2
✓ Branch 0 taken 236 times.
✓ Branch 1 taken 4 times.
240 if (dlb_args_from_env) {
1050 236 free(dlb_args_from_env);
1051 }
1052 }
1053 256 }
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