• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

STEllAR-GROUP / hpx / #856

28 Dec 2022 02:00AM UTC coverage: 86.602% (+0.05%) from 86.55%
#856

push

StellarBot
Merge #6119

6119: Update CMakeLists.txt r=hkaiser a=khuck

updating the default APEX version


Co-authored-by: Kevin Huck <khuck@cs.uoregon.edu>

174566 of 201573 relevant lines covered (86.6%)

1876093.78 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.6
/libs/core/command_line_handling_local/src/command_line_handling_local.cpp
1
//  Copyright (c) 2007-2022 Hartmut Kaiser
2
//
3
//  SPDX-License-Identifier: BSL-1.0
4
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
5
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6

7
#include <hpx/config.hpp>
8
#include <hpx/assert.hpp>
9
#include <hpx/command_line_handling_local/command_line_handling_local.hpp>
10
#include <hpx/command_line_handling_local/parse_command_line_local.hpp>
11
#include <hpx/functional/detail/reset_function.hpp>
12
#include <hpx/modules/asio.hpp>
13
#include <hpx/modules/debugging.hpp>
14
#include <hpx/modules/format.hpp>
15
#include <hpx/modules/program_options.hpp>
16
#include <hpx/modules/runtime_configuration.hpp>
17
#include <hpx/modules/string_util.hpp>
18
#include <hpx/modules/topology.hpp>
19
#include <hpx/modules/util.hpp>
20
#include <hpx/preprocessor/stringize.hpp>
21
#include <hpx/type_support/unused.hpp>
22
#include <hpx/util/from_string.hpp>
23
#include <hpx/version.hpp>
24

25
#include <algorithm>
26
#include <cstddef>
27
#include <cstdint>
28
#include <fstream>
29
#include <iomanip>
30
#include <iostream>
31
#include <iterator>
32
#include <memory>
33
#include <sstream>
34
#include <string>
35
#include <utility>
36
#include <vector>
37

38
namespace hpx::local::detail {
39

40
    std::string runtime_configuration_string(command_line_handling const& cfg)
×
41
    {
42
        std::ostringstream strm;
×
43

44
        // default scheduler used for this run
45
        strm << "  {scheduler}: " << cfg.queuing_ << "\n";
×
46

47
        // amount of threads and cores configured for this run
48
        strm << "  {os-threads}: " << cfg.num_threads_ << "\n";
×
49
        strm << "  {cores}: " << cfg.num_cores_ << "\n";
×
50

51
        return strm.str();
×
52
    }
×
53

54
    ///////////////////////////////////////////////////////////////////////
55
    int print_version(std::ostream& out)
×
56
    {
57
        out << std::endl << hpx::copyright() << std::endl;
×
58
        out << hpx::complete_version() << std::endl;
×
59
        return 1;
×
60
    }
×
61

62
    int print_info(std::ostream& out, command_line_handling const& cfg)
×
63
    {
64
        out << "Static configuration:\n---------------------\n";
×
65
        out << hpx::configuration_string() << std::endl;
×
66

67
        out << "Runtime configuration:\n----------------------\n";
×
68
        out << runtime_configuration_string(cfg) << std::endl;
×
69

70
        return 1;
×
71
    }
×
72

73
    ///////////////////////////////////////////////////////////////////////
74
    inline void encode(
6,020✔
75
        std::string& str, char s, char const* r, std::size_t inc = 1ull)
76
    {
77
        std::string::size_type pos = 0;
6,020✔
78
        while ((pos = str.find_first_of(s, pos)) != std::string::npos)
6,020✔
79
        {
80
            str.replace(pos, 1, r);
×
81
            pos += inc;
×
82
        }
83
    }
6,020✔
84

85
    inline std::string encode_string(std::string str)
×
86
    {
87
        encode(str, '\n', "\\n");
×
88
        return str;
×
89
    }
90

91
    inline std::string encode_and_enquote(std::string str)
6,020✔
92
    {
93
        encode(str, '\"', "\\\"", 2);
6,020✔
94
        return enquote(HPX_MOVE(str));
6,020✔
95
    }
×
96

97
    ///////////////////////////////////////////////////////////////////////
98
    std::string convert_to_log_file(std::string const& dest)
9,556✔
99
    {
100
        if (dest.empty())
9,556✔
101
            return "cout";
×
102

103
        if (dest == "cout" || dest == "cerr" || dest == "console")
9,556✔
104
            return dest;
×
105
#if defined(ANDROID) || defined(__ANDROID__)
106
        if (dest == "android_log")
107
            return dest;
108
#endif
109
        // everything else is assumed to be a file name
110
        return "file(" + dest + ")";
9,556✔
111
    }
9,556✔
112

113
    std::string handle_queuing(util::manage_config& cfgmap,
2,442✔
114
        hpx::program_options::variables_map& vm, std::string const& default_)
115
    {
116
        // command line options is used preferred
117
        if (vm.count("hpx:queuing"))
2,442✔
118
            return vm["hpx:queuing"].as<std::string>();
16✔
119

120
        // use either cfgmap value or default
121
        return cfgmap.get_value<std::string>("hpx.scheduler", default_);
2,426✔
122
    }
2,442✔
123

124
    std::string handle_affinity(util::manage_config& cfgmap,
2,442✔
125
        hpx::program_options::variables_map& vm, std::string const& default_)
126
    {
127
        // command line options is used preferred
128
        if (vm.count("hpx:affinity"))
2,442✔
129
            return vm["hpx:affinity"].as<std::string>();
×
130

131
        // use either cfgmap value or default
132
        return cfgmap.get_value<std::string>("hpx.affinity", default_);
2,442✔
133
    }
2,442✔
134

135
    std::string handle_affinity_bind(util::manage_config& cfgmap,
2,442✔
136
        hpx::program_options::variables_map& vm, std::string const& default_)
137
    {
138
        // command line options is used preferred
139
        if (vm.count("hpx:bind"))
2,442✔
140
        {
141
            std::string affinity_desc;
×
142

143
            std::vector<std::string> bind_affinity =
144
                vm["hpx:bind"].as<std::vector<std::string>>();
×
145
            for (std::string const& s : bind_affinity)
×
146
            {
147
                if (!affinity_desc.empty())
×
148
                    affinity_desc += ";";
×
149
                affinity_desc += s;
×
150
            }
151

152
            return affinity_desc;
×
153
        }
×
154

155
        // use either cfgmap value or default
156
        return cfgmap.get_value<std::string>("hpx.bind", default_);
2,442✔
157
    }
2,442✔
158

159
    std::size_t handle_pu_step(util::manage_config& cfgmap,
2,442✔
160
        hpx::program_options::variables_map& vm, std::size_t default_)
161
    {
162
        // command line options is used preferred
163
        if (vm.count("hpx:pu-step"))
2,442✔
164
            return vm["hpx:pu-step"].as<std::size_t>();
×
165

166
        // use either cfgmap value or default
167
        return cfgmap.get_value<std::size_t>("hpx.pu_step", default_);
2,442✔
168
    }
2,442✔
169

170
    std::size_t handle_pu_offset(util::manage_config& cfgmap,
2,442✔
171
        hpx::program_options::variables_map& vm, std::size_t default_)
172
    {
173
        // command line options is used preferred
174
        if (vm.count("hpx:pu-offset"))
2,442✔
175
            return vm["hpx:pu-offset"].as<std::size_t>();
×
176

177
        // use either cfgmap value or default
178
        return cfgmap.get_value<std::size_t>("hpx.pu_offset", default_);
2,442✔
179
    }
2,442✔
180

181
    std::size_t handle_numa_sensitive(util::manage_config& cfgmap,
2,442✔
182
        hpx::program_options::variables_map& vm, std::size_t default_)
183
    {
184
        if (vm.count("hpx:numa-sensitive") != 0)
2,442✔
185
        {
186
            std::size_t numa_sensitive =
×
187
                vm["hpx:numa-sensitive"].as<std::size_t>();
×
188
            if (numa_sensitive > 2)
×
189
            {
190
                throw hpx::detail::command_line_error(
×
191
                    "Invalid argument value for --hpx:numa-sensitive. Allowed "
192
                    "values are 0, 1, or 2");
193
            }
194
            return numa_sensitive;
×
195
        }
196

197
        // use either cfgmap value or default
198
        return cfgmap.get_value<std::size_t>("hpx.numa_sensitive", default_);
2,442✔
199
    }
2,442✔
200

201
    ///////////////////////////////////////////////////////////////////////
202
    std::size_t get_number_of_default_threads(bool use_process_mask)
3,638✔
203
    {
204
        if (use_process_mask)
3,638✔
205
        {
206
            threads::topology& top = threads::create_topology();
×
207
            return threads::count(top.get_cpubind_mask());
×
208
        }
209
        return threads::hardware_concurrency();
3,638✔
210
    }
3,638✔
211

212
    std::size_t get_number_of_default_cores(bool use_process_mask)
7,276✔
213
    {
214
        threads::topology& top = threads::create_topology();
7,276✔
215

216
        std::size_t num_cores = top.get_number_of_cores();
7,276✔
217

218
        if (use_process_mask)
7,276✔
219
        {
220
            threads::mask_type proc_mask = top.get_cpubind_mask();
×
221
            std::size_t num_cores_proc_mask = 0;
×
222

223
            for (std::size_t num_core = 0; num_core < num_cores; ++num_core)
×
224
            {
225
                threads::mask_type core_mask =
226
                    top.init_core_affinity_mask_from_core(num_core);
×
227
                if (threads::bit_and(core_mask, proc_mask))
×
228
                {
229
                    ++num_cores_proc_mask;
×
230
                }
×
231
            }
×
232

233
            return num_cores_proc_mask;
×
234
        }
×
235

236
        return num_cores;
7,276✔
237
    }
7,276✔
238

239
    ///////////////////////////////////////////////////////////////////////
240
    std::size_t handle_num_threads(util::manage_config& cfgmap,
2,442✔
241
        hpx::util::runtime_configuration const& rtcfg,
242
        hpx::program_options::variables_map& vm, bool use_process_mask)
243
    {
244
        // If using the process mask we override "cores" and "all" options but
245
        // keep explicit numeric values.
246
        std::size_t const init_threads =
2,442✔
247
            get_number_of_default_threads(use_process_mask);
2,442✔
248
        std::size_t const init_cores =
2,442✔
249
            get_number_of_default_cores(use_process_mask);
2,442✔
250

251
        std::string threads_str = cfgmap.get_value<std::string>(
4,884✔
252
            "hpx.os_threads",
2,442✔
253
            rtcfg.get_entry("hpx.os_threads", std::to_string(init_threads)));
2,442✔
254

255
        std::size_t threads = 0;
2,442✔
256
        if ("cores" == threads_str)
2,442✔
257
        {
258
            threads = init_cores;
1,608✔
259
        }
1,608✔
260
        else if ("all" == threads_str)
834✔
261
        {
262
            threads = init_threads;
700✔
263
        }
700✔
264
        else
265
        {
266
            threads = cfgmap.get_value<std::size_t>("hpx.os_threads",
268✔
267
                hpx::util::from_string<std::size_t>(threads_str));
134✔
268
        }
269

270
        if (vm.count("hpx:threads"))
2,442✔
271
        {
272
            threads_str = vm["hpx:threads"].as<std::string>();
2,412✔
273
            if ("all" == threads_str)
2,412✔
274
            {
275
                threads = init_threads;
20✔
276
            }
20✔
277
            else if ("cores" == threads_str)
2,392✔
278
            {
279
                threads = init_cores;
2✔
280
            }
2✔
281
            else
282
            {
283
                threads = hpx::util::from_string<std::size_t>(threads_str);
2,390✔
284
            }
285

286
            if (threads == 0)
2,412✔
287
            {
288
                throw hpx::detail::command_line_error(
×
289
                    "Number of --hpx:threads must be greater than 0");
290
            }
291

292
#if defined(HPX_HAVE_MAX_CPU_COUNT)
293
            if (threads > HPX_HAVE_MAX_CPU_COUNT)
294
            {
295
                // clang-format off
296
                throw hpx::detail::command_line_error("Requested more than "
297
                    HPX_PP_STRINGIZE(HPX_HAVE_MAX_CPU_COUNT)" --hpx:threads "
298
                    "to use for this application, use the option "
299
                    "-DHPX_WITH_MAX_CPU_COUNT=<N> when configuring HPX.");
300
                // clang-format on
301
            }
302
#endif
303
        }
2,412✔
304

305
        // make sure minimal requested number of threads is observed
306
        std::size_t min_os_threads =
2,442✔
307
            cfgmap.get_value<std::size_t>("hpx.force_min_os_threads", threads);
2,442✔
308

309
        if (min_os_threads == 0)
2,442✔
310
        {
311
            throw hpx::detail::command_line_error(
×
312
                "Number of hpx.force_min_os_threads must be greater than 0");
313
        }
314

315
#if defined(HPX_HAVE_MAX_CPU_COUNT)
316
        if (min_os_threads > HPX_HAVE_MAX_CPU_COUNT)
317
        {
318
            // clang-format off
319
            throw hpx::detail::command_line_error(
320
                "Requested more than " HPX_PP_STRINGIZE(HPX_HAVE_MAX_CPU_COUNT)
321
                " hpx.force_min_os_threads to use for this application, use the "
322
                "option -DHPX_WITH_MAX_CPU_COUNT=<N> when configuring HPX.");
323
            // clang-format on
324
        }
325
#endif
326
        threads = (std::max)(threads, min_os_threads);
2,442✔
327

328
        return threads;
2,442✔
329
    }
2,442✔
330

331
    std::size_t handle_num_cores(util::manage_config& cfgmap,
3,638✔
332
        hpx::program_options::variables_map& vm, std::size_t num_threads,
333
        std::size_t num_default_cores)
334
    {
335
        std::string cores_str = cfgmap.get_value<std::string>("hpx.cores", "");
3,638✔
336
        if ("all" == cores_str)
3,638✔
337
        {
338
            cfgmap.config_["hpx.cores"] = std::to_string(num_default_cores);
×
339
        }
×
340

341
        std::size_t num_cores =
3,638✔
342
            cfgmap.get_value<std::size_t>("hpx.cores", num_threads);
3,638✔
343
        if (vm.count("hpx:cores"))
3,638✔
344
        {
345
            cores_str = vm["hpx:cores"].as<std::string>();
2✔
346
            if ("all" == cores_str)
2✔
347
            {
348
                num_cores = num_default_cores;
×
349
            }
×
350
            else
351
            {
352
                num_cores = hpx::util::from_string<std::size_t>(cores_str);
2✔
353
            }
354
        }
2✔
355

356
        return num_cores;
3,638✔
357
    }
3,638✔
358

359
    std::size_t handle_num_cores(util::manage_config& cfgmap,
2,442✔
360
        hpx::program_options::variables_map& vm, std::size_t num_threads,
361
        bool use_process_mask)
362
    {
363
        return handle_num_cores(cfgmap, vm, num_threads,
4,884✔
364
            get_number_of_default_cores(use_process_mask));
2,442✔
365
    }
366

367
    void print_config(std::vector<std::string> const& ini_config)
×
368
    {
369
        std::cerr << "Configuration before runtime start:\n";
×
370
        std::cerr << "-----------------------------------\n";
×
371
        for (std::string const& s : ini_config)
×
372
        {
373
            std::cerr << s << std::endl;
×
374
        }
375
        std::cerr << "-----------------------------------\n";
×
376
    }
×
377

378
    ///////////////////////////////////////////////////////////////////////
379
    command_line_handling::command_line_handling(
1,221✔
380
        hpx::util::runtime_configuration rtcfg,
381
        std::vector<std::string> ini_config,
382
        hpx::function<int(hpx::program_options::variables_map& vm)> hpx_main_f)
383
      : rtcfg_(HPX_MOVE(rtcfg))
1,221✔
384
      , ini_config_(HPX_MOVE(ini_config))
1,221✔
385
      , hpx_main_f_(HPX_MOVE(hpx_main_f))
1,221✔
386
      , num_threads_(1)
1,221✔
387
      , num_cores_(1)
1,221✔
388
      , pu_step_(1)
1,221✔
389
      , pu_offset_(std::size_t(-1))
1,221✔
390
      , numa_sensitive_(0)
1,221✔
391
      , use_process_mask_(false)
1,221✔
392
      , cmd_line_parsed_(false)
1,221✔
393
      , info_printed_(false)
1,221✔
394
      , version_printed_(false)
1,221✔
395
    {
396
    }
1,221✔
397

398
    void command_line_handling::check_affinity_domain() const
2,442✔
399
    {
400
        if (affinity_domain_ != "pu")
2,442✔
401
        {
402
            if (0 != std::string("pu").find(affinity_domain_) &&
×
403
                0 != std::string("core").find(affinity_domain_) &&
×
404
                0 != std::string("numa").find(affinity_domain_) &&
×
405
                0 != std::string("machine").find(affinity_domain_))
×
406
            {
407
                throw hpx::detail::command_line_error(
×
408
                    "Invalid command line option --hpx:affinity, value must be "
409
                    "one of: pu, core, numa, or machine.");
410
            }
411
        }
×
412
    }
2,442✔
413

414
    void command_line_handling::check_affinity_description() const
2,442✔
415
    {
416
        if (affinity_bind_.empty())
2,442✔
417
        {
418
            return;
×
419
        }
420

421
        if (!(pu_offset_ == std::size_t(-1) || pu_offset_ == std::size_t(0)) ||
4,884✔
422
            pu_step_ != 1 || affinity_domain_ != "pu")
2,442✔
423
        {
424
            throw hpx::detail::command_line_error(
×
425
                "Command line option --hpx:bind should not be used with "
426
                "--hpx:pu-step, --hpx:pu-offset, or --hpx:affinity.");
427
        }
428
    }
2,442✔
429

430
    void command_line_handling::check_pu_offset() const
2,442✔
431
    {
432
        if (pu_offset_ != std::size_t(-1) &&
2,442✔
433
            pu_offset_ >= hpx::threads::hardware_concurrency())
×
434
        {
435
            throw hpx::detail::command_line_error(
×
436
                "Invalid command line option --hpx:pu-offset, value must be "
437
                "smaller than number of available processing units.");
438
        }
439
    }
2,442✔
440

441
    void command_line_handling::check_pu_step() const
2,442✔
442
    {
443
        if (hpx::threads::hardware_concurrency() > 1 &&
4,884✔
444
            (pu_step_ == 0 || pu_step_ >= hpx::threads::hardware_concurrency()))
2,442✔
445
        {
446
            throw hpx::detail::command_line_error(
×
447
                "Invalid command line option --hpx:pu-step, value must be "
448
                "non-zero and smaller than number of available processing "
449
                "units.");
450
        }
451
    }
2,442✔
452

453
    void command_line_handling::handle_high_priority_threads(
3,638✔
454
        hpx::program_options::variables_map& vm,
455
        std::vector<std::string>& ini_config)
456
    {
457
        if (vm_.count("hpx:high-priority-threads"))
3,638✔
458
        {
459
            std::size_t num_high_priority_queues =
×
460
                vm["hpx:high-priority-threads"].as<std::size_t>();
×
461
            if (num_high_priority_queues != std::size_t(-1) &&
×
462
                num_high_priority_queues > num_threads_)
×
463
            {
464
                throw hpx::detail::command_line_error(
×
465
                    "Invalid command line option: number of high priority "
466
                    "threads (--hpx:high-priority-threads), should not be "
467
                    "larger than number of threads (--hpx:threads)");
468
            }
469

470
            if (!(queuing_ == "local-priority" || queuing_ == "abp-priority"))
×
471
            {
472
                throw hpx::detail::command_line_error(
×
473
                    "Invalid command line option --hpx:high-priority-threads, "
474
                    "valid for --hpx:queuing=local-priority and "
475
                    "--hpx:queuing=abp-priority only");
476
            }
477

478
            ini_config.emplace_back("hpx.thread_queue.high_priority_queues!=" +
×
479
                std::to_string(num_high_priority_queues));
×
480
        }
×
481
    }
3,638✔
482

483
    ///////////////////////////////////////////////////////////////////////////
484
    bool command_line_handling::handle_arguments(util::manage_config& cfgmap,
2,442✔
485
        hpx::program_options::variables_map& vm,
486
        std::vector<std::string>& ini_config)
487
    {
488
        bool debug_clp = vm.count("hpx:debug-clp");
2,442✔
489

490
        if (vm.count("hpx:ini"))
2,442✔
491
        {
492
            std::vector<std::string> cfg =
493
                vm["hpx:ini"].as<std::vector<std::string>>();
570✔
494
            std::copy(cfg.begin(), cfg.end(), std::back_inserter(ini_config));
570✔
495
            cfgmap.add(cfg);
570✔
496
        }
570✔
497

498
        use_process_mask_ =
2,442✔
499
            (cfgmap.get_value<int>("hpx.use_process_mask", 0) > 0) ||
4,884✔
500
            (vm.count("hpx:use-process-mask") > 0);
2,442✔
501

502
#if defined(__APPLE__)
503
        if (use_process_mask_)
504
        {
505
            std::cerr
506
                << "Warning: enabled process mask for thread binding, but "
507
                   "thread binding is not supported on macOS. Ignoring option."
508
                << std::endl;
509
            use_process_mask_ = false;
510
        }
511
#endif
512

513
        ini_config.emplace_back(
2,442✔
514
            "hpx.use_process_mask!=" + std::to_string(use_process_mask_));
2,442✔
515

516
        // handle setting related to schedulers
517
        queuing_ = detail::handle_queuing(cfgmap, vm, "local-priority-fifo");
2,442✔
518
        ini_config.emplace_back("hpx.scheduler=" + queuing_);
2,442✔
519

520
        affinity_domain_ = detail::handle_affinity(cfgmap, vm, "pu");
2,442✔
521
        ini_config.emplace_back("hpx.affinity=" + affinity_domain_);
2,442✔
522

523
        check_affinity_domain();
2,442✔
524

525
        affinity_bind_ = detail::handle_affinity_bind(cfgmap, vm, "");
2,442✔
526
        if (!affinity_bind_.empty())
2,442✔
527
        {
528
#if defined(__APPLE__)
529
            std::cerr << "Warning: thread binding set to \"" << affinity_bind_
530
                      << "\" but thread binding is not supported on macOS. "
531
                         "Ignoring option."
532
                      << std::endl;
533
            affinity_bind_ = "";
534
#else
535
            ini_config.emplace_back("hpx.bind!=" + affinity_bind_);
×
536
#endif
537
        }
×
538

539
        pu_step_ = detail::handle_pu_step(cfgmap, vm, 1);
2,442✔
540
#if defined(__APPLE__)
541
        if (pu_step_ != 1)
542
        {
543
            std::cerr << "Warning: PU step set to \"" << pu_step_
544
                      << "\" but thread binding is not supported on macOS. "
545
                         "Ignoring option."
546
                      << std::endl;
547
            pu_step_ = 1;
548
        }
549
#endif
550
        ini_config.emplace_back("hpx.pu_step=" + std::to_string(pu_step_));
2,442✔
551

552
        check_pu_step();
2,442✔
553

554
        pu_offset_ = detail::handle_pu_offset(cfgmap, vm, std::size_t(-1));
2,442✔
555

556
        // NOLINTNEXTLINE(bugprone-branch-clone)
557
        if (pu_offset_ != std::size_t(-1))
2,442✔
558
        {
559
#if defined(__APPLE__)
560
            std::cerr << "Warning: PU offset set to \"" << pu_offset_
561
                      << "\" but thread binding is not supported on macOS. "
562
                         "Ignoring option."
563
                      << std::endl;
564
            pu_offset_ = std::size_t(-1);
565
            ini_config.emplace_back("hpx.pu_offset=0");
566
#else
567
            ini_config.emplace_back(
×
568
                "hpx.pu_offset=" + std::to_string(pu_offset_));
×
569
#endif
570
        }
×
571
        else
572
        {
573
            ini_config.emplace_back("hpx.pu_offset=0");
2,442✔
574
        }
575

576
        check_pu_offset();
2,442✔
577

578
        numa_sensitive_ = detail::handle_numa_sensitive(
2,442✔
579
            cfgmap, vm, affinity_bind_.empty() ? 0 : 1);
2,442✔
580
        ini_config.emplace_back(
2,442✔
581
            "hpx.numa_sensitive=" + std::to_string(numa_sensitive_));
2,442✔
582

583
        // default affinity mode is now 'balanced' (only if no pu-step or
584
        // pu-offset is given)
585
        if (pu_step_ == 1 && pu_offset_ == std::size_t(-1) &&
2,442✔
586
            affinity_bind_.empty())
2,442✔
587
        {
588
#if defined(__APPLE__)
589
            affinity_bind_ = "none";
590
#else
591
            affinity_bind_ = "balanced";
2,442✔
592
#endif
593
            ini_config.emplace_back("hpx.bind!=" + affinity_bind_);
2,442✔
594
        }
2,442✔
595

596
        check_affinity_description();
2,442✔
597

598
        // handle number of cores and threads
599
        num_threads_ =
2,442✔
600
            detail::handle_num_threads(cfgmap, rtcfg_, vm, use_process_mask_);
2,442✔
601
        num_cores_ = detail::handle_num_cores(
2,442✔
602
            cfgmap, vm, num_threads_, use_process_mask_);
2,442✔
603

604
        // Set number of cores and OS threads in configuration.
605
        ini_config.emplace_back(
2,442✔
606
            "hpx.os_threads=" + std::to_string(num_threads_));
2,442✔
607
        ini_config.emplace_back("hpx.cores=" + std::to_string(num_cores_));
2,442✔
608

609
        // handle high-priority threads
610
        handle_high_priority_threads(vm, ini_config);
2,442✔
611

612
        enable_logging_settings(vm, ini_config);
2,442✔
613

614
        if (debug_clp)
2,442✔
615
        {
616
            print_config(ini_config);
×
617
        }
×
618

619
        return true;
2,442✔
620
    }
×
621

622
    ///////////////////////////////////////////////////////////////////////////
623
    void command_line_handling::enable_logging_settings(
4,859✔
624
        hpx::program_options::variables_map& vm,
625
        [[maybe_unused]] std::vector<std::string>& ini_config)
626
    {
627
#if defined(HPX_HAVE_LOGGING)
628
        if (vm.count("hpx:debug-hpx-log"))
4,859✔
629
        {
630
            ini_config.emplace_back("hpx.logging.console.destination=" +
9,556✔
631
                detail::convert_to_log_file(
4,778✔
632
                    vm["hpx:debug-hpx-log"].as<std::string>()));
4,778✔
633
            ini_config.emplace_back("hpx.logging.destination=" +
9,556✔
634
                detail::convert_to_log_file(
4,778✔
635
                    vm["hpx:debug-hpx-log"].as<std::string>()));
4,778✔
636
            ini_config.emplace_back("hpx.logging.console.level=5");
4,778✔
637
            ini_config.emplace_back("hpx.logging.level=5");
4,778✔
638
        }
4,778✔
639

640
        if (vm.count("hpx:debug-timing-log"))
4,859✔
641
        {
642
            ini_config.emplace_back("hpx.logging.console.timing.destination=" +
×
643
                detail::convert_to_log_file(
×
644
                    vm["hpx:debug-timing-log"].as<std::string>()));
×
645
            ini_config.emplace_back("hpx.logging.timing.destination=" +
×
646
                detail::convert_to_log_file(
×
647
                    vm["hpx:debug-timing-log"].as<std::string>()));
×
648
            ini_config.emplace_back("hpx.logging.console.timing.level=1");
×
649
            ini_config.emplace_back("hpx.logging.timing.level=1");
×
650
        }
×
651

652
        if (vm.count("hpx:debug-app-log"))
4,859✔
653
        {
654
            ini_config.emplace_back(
×
655
                "hpx.logging.console.application.destination=" +
×
656
                detail::convert_to_log_file(
×
657
                    vm["hpx:debug-app-log"].as<std::string>()));
×
658
            ini_config.emplace_back("hpx.logging.application.destination=" +
×
659
                detail::convert_to_log_file(
×
660
                    vm["hpx:debug-app-log"].as<std::string>()));
×
661
            ini_config.emplace_back("hpx.logging.console.application.level=5");
×
662
            ini_config.emplace_back("hpx.logging.application.level=5");
×
663
        }
×
664
#else
665
        if (vm.count("hpx:debug-hpx-log") || vm.count("hpx:debug-timing-log") ||
666
            vm.count("hpx:debug-app-log"))
667
        {
668
            // clang-format off
669
            throw hpx::detail::command_line_error(
670
                "Command line option error: can't enable logging while it "
671
                "was disabled at configuration time. Please re-configure "
672
                "HPX using the option -DHPX_WITH_LOGGING=On.");
673
            // clang-format on
674
        }
675
#endif
676
    }
4,859✔
677

678
    ///////////////////////////////////////////////////////////////////////////
679
    void command_line_handling::store_command_line(int argc, char** argv)
1,221✔
680
    {
681
        // Collect the command line for diagnostic purposes.
682
        std::string command;
1,221✔
683
        std::string cmd_line;
1,221✔
684
        std::string options;
1,221✔
685
        for (int i = 0; i < argc; ++i)
6,014✔
686
        {
687
            // quote only if it contains whitespace
688
            std::string arg = detail::encode_and_enquote(argv[i]);    //-V108
4,793✔
689

690
            cmd_line += arg;
4,793✔
691
            if (i == 0)
4,793✔
692
            {
693
                command = arg;
1,221✔
694
            }
1,221✔
695
            else
696
            {
697
                options += " " + arg;
3,572✔
698
            }
699

700
            if ((i + 1) != argc)
4,793✔
701
            {
702
                cmd_line += " ";
3,572✔
703
            }
3,572✔
704
        }
4,793✔
705

706
        // Store the program name and the command line.
707
        ini_config_.emplace_back("hpx.cmd_line!=" + cmd_line);
1,221✔
708
        ini_config_.emplace_back("hpx.commandline.command!=" + command);
1,221✔
709
        ini_config_.emplace_back("hpx.commandline.options!=" + options);
1,221✔
710
    }
1,221✔
711

712
    ///////////////////////////////////////////////////////////////////////////
713
    void command_line_handling::store_unregistered_options(
1,221✔
714
        std::string const& cmd_name,
715
        std::vector<std::string> const& unregistered_options)
716
    {
717
        std::string unregistered_options_cmd_line;
1,221✔
718

719
        if (!unregistered_options.empty())
1,221✔
720
        {
721
            typedef std::vector<std::string>::const_iterator iterator_type;
722

723
            iterator_type end = unregistered_options.end();
3✔
724
            for (iterator_type it = unregistered_options.begin(); it != end;
6✔
725
                 ++it)
3✔
726
                unregistered_options_cmd_line +=
3✔
727
                    " " + detail::encode_and_enquote(*it);
3✔
728

729
            ini_config_.emplace_back("hpx.unknown_cmd_line!=" +
9✔
730
                detail::encode_and_enquote(cmd_name) +
6✔
731
                unregistered_options_cmd_line);
732
        }
3✔
733

734
        ini_config_.emplace_back("hpx.program_name!=" + cmd_name);
1,221✔
735
        ini_config_.emplace_back("hpx.reconstructed_cmd_line!=" +
3,663✔
736
            encode_and_enquote(cmd_name) + " " + reconstruct_command_line(vm_) +
2,442✔
737
            " " + unregistered_options_cmd_line);
1,221✔
738
    }
1,221✔
739

740
    ///////////////////////////////////////////////////////////////////////////
741
    bool command_line_handling::handle_help_options(
1,221✔
742
        hpx::program_options::options_description const& help)
743
    {
744
        if (vm_.count("hpx:help"))
1,221✔
745
        {
746
            std::string help_option(vm_["hpx:help"].as<std::string>());
3✔
747
            if (0 == std::string("minimal").find(help_option))
3✔
748
            {
749
                // print static help only
750
                std::cout << help << std::endl;
3✔
751
                return true;
3✔
752
            }
753
            else if (0 == std::string("full").find(help_option))
×
754
            {
755
                // defer printing help until after dynamic part has been
756
                // acquired
757
                std::ostringstream strm;
×
758
                strm << help << std::endl;
×
759
                ini_config_.emplace_back(
×
760
                    "hpx.cmd_line_help!=" + detail::encode_string(strm.str()));
×
761
                ini_config_.emplace_back(
×
762
                    "hpx.cmd_line_help_option!=" + help_option);
×
763
            }
×
764
            else
765
            {
766
                throw hpx::detail::command_line_error(hpx::util::format(
×
767
                    "Invalid argument for option --hpx:help: '{1}', allowed "
×
768
                    "values: 'minimal' (default) and 'full'",
769
                    help_option));
770
            }
771
        }
3✔
772
        return false;
1,218✔
773
    }
1,221✔
774

775
    void command_line_handling::handle_attach_debugger()
1,221✔
776
    {
777
#if defined(_POSIX_VERSION) || defined(HPX_WINDOWS)
778
        if (vm_.count("hpx:attach-debugger"))
1,221✔
779
        {
780
            std::string option = vm_["hpx:attach-debugger"].as<std::string>();
×
781
            if (option != "off" && option != "startup" &&
×
782
                option != "exception" && option != "test-failure")
×
783
            {
784
                // clang-format off
785
                std::cerr <<
×
786
                    "hpx::init: command line warning: --hpx:attach-debugger: "
787
                    "invalid option: " << option << ". Allowed values are "
×
788
                    "'off', 'startup', 'exception' or 'test-failure'" << std::endl;
×
789
                // clang-format on
790
            }
×
791
            else
792
            {
793
                if (option == "startup")
×
794
                    util::attach_debugger();
×
795

796
                ini_config_.emplace_back("hpx.attach_debugger!=" + option);
×
797
            }
798
        }
×
799
#endif
800
    }
1,221✔
801

802
    ///////////////////////////////////////////////////////////////////////////
803
    // separate command line arguments from configuration settings
804
    std::vector<std::string> command_line_handling::preprocess_config_settings(
1,221✔
805
        int argc, char** argv)
806
    {
807
        std::vector<std::string> options;
1,221✔
808
        options.reserve(static_cast<std::size_t>(argc) + ini_config_.size());
1,221✔
809

810
        // extract all command line arguments from configuration settings and
811
        // remove them from this list
812
        auto it = std::stable_partition(ini_config_.begin(), ini_config_.end(),
1,221✔
813
            [](std::string const& e) { return e.find("--hpx:") != 0; });
953✔
814

815
        std::move(it, ini_config_.end(), std::back_inserter(options));
1,221✔
816
        ini_config_.erase(it, ini_config_.end());
1,221✔
817

818
        // store the command line options that came from the configuration
819
        // settings in the registry
820
        if (!options.empty())
1,221✔
821
        {
822
            std::string config_options;
16✔
823
            for (auto const& option : options)
34✔
824
            {
825
                config_options += " " + option;
18✔
826
            }
827

828
            rtcfg_.add_entry("hpx.commandline.config_options", config_options);
16✔
829
        }
16✔
830

831
        // now append all original command line options
832
        for (int i = 1; i != argc; ++i)
4,793✔
833
        {
834
            options.emplace_back(argv[i]);
3,572✔
835
        }
3,572✔
836

837
        return options;
1,221✔
838
    }
1,221✔
839

840
    ///////////////////////////////////////////////////////////////////////////
841
    std::vector<std::string> prepend_options(
1,221✔
842
        std::vector<std::string>&& args, std::string&& options)
843
    {
844
        if (options.empty())
1,221✔
845
        {
846
            return HPX_MOVE(args);
1,221✔
847
        }
848

849
        hpx::string_util::escaped_list_separator sep('\\', ' ', '\"');
×
850
        hpx::string_util::tokenizer tok(options, sep);
×
851

852
        std::vector<std::string> result(tok.begin(), tok.end());
×
853
        std::move(args.begin(), args.end(), std::back_inserter(result));
×
854
        return result;
×
855
    }
1,221✔
856

857
    ///////////////////////////////////////////////////////////////////////////
858
    void command_line_handling::reconfigure(
1,221✔
859
        util::manage_config& cfgmap, hpx::program_options::variables_map& prevm)
860
    {
861
        // re-initialize runtime configuration object
862
        if (prevm.count("hpx:config"))
1,221✔
863
            rtcfg_.reconfigure(prevm["hpx:config"].as<std::string>());
1,221✔
864
        else
865
            rtcfg_.reconfigure("");
×
866

867
        // Make sure any aliases defined on the command line get used for the
868
        // option analysis below.
869
        std::vector<std::string> cfg;
1,221✔
870
        if (prevm.count("hpx:ini"))
1,221✔
871
        {
872
            cfg = prevm["hpx:ini"].as<std::vector<std::string>>();
285✔
873
            cfgmap.add(cfg);
285✔
874
        }
285✔
875

876
        // append ini options from command line
877
        std::copy(
1,221✔
878
            ini_config_.begin(), ini_config_.end(), std::back_inserter(cfg));
1,221✔
879

880
        // enable logging if invoked requested from command line
881
        std::vector<std::string> ini_config_logging;
1,221✔
882
        enable_logging_settings(prevm, ini_config_logging);
1,221✔
883

884
        std::copy(ini_config_logging.begin(), ini_config_logging.end(),
1,221✔
885
            std::back_inserter(cfg));
1,221✔
886

887
        rtcfg_.reconfigure(cfg);
1,221✔
888
    }
1,221✔
889

890
    int command_line_handling::call(
623✔
891
        hpx::program_options::options_description const& desc_cmdline, int argc,
892
        char** argv)
893
    {
894
        // set the flag signaling that command line parsing has been done
895
        cmd_line_parsed_ = true;
623✔
896

897
        // separate command line arguments from configuration settings
898
        std::vector<std::string> args = preprocess_config_settings(argc, argv);
623✔
899

900
        util::manage_config cfgmap(ini_config_);
623✔
901

902
        // insert the pre-configured ini settings before loading modules
903
        for (std::string const& e : ini_config_)
1,021✔
904
            rtcfg_.parse("<user supplied config>", e, true, false);
398✔
905

906
        // support re-throwing command line exceptions for testing purposes
907
        util::commandline_error_mode error_mode =
623✔
908
            util::commandline_error_mode::allow_unregistered;
909
        if (cfgmap.get_value("hpx.commandline.rethrow_errors", 0) != 0)
623✔
910
        {
911
            error_mode |= util::commandline_error_mode::rethrow_on_error;
1✔
912
        }
1✔
913

914
        // The cfg registry may hold command line options to prepend to the
915
        // real command line.
916
        std::string prepend_command_line =
917
            rtcfg_.get_entry("hpx.commandline.prepend_options");
623✔
918

919
        args = prepend_options(HPX_MOVE(args), HPX_MOVE(prepend_command_line));
623✔
920

921
        // Initial analysis of the command line options. This is preliminary as
922
        // it will not take into account any aliases as defined in any of the
923
        // runtime configuration files.
924
        {
925
            // Boost V1.47 and before do not properly reset a variables_map when
926
            // calling vm.clear(). We work around that problems by creating a
927
            // separate instance just for the preliminary command line handling.
928
            hpx::program_options::variables_map prevm;
623✔
929
            if (!parse_commandline(
623✔
930
                    rtcfg_, desc_cmdline, argv[0], args, prevm, error_mode))
623✔
931
            {
932
                return -1;
×
933
            }
934

935
            // handle all --hpx:foo options
936
            std::vector<std::string> ini_config;    // discard
623✔
937
            if (!handle_arguments(cfgmap, prevm, ini_config))
623✔
938
            {
939
                return -2;
×
940
            }
941

942
            reconfigure(cfgmap, prevm);
623✔
943
        }
623✔
944

945
        // Re-run program option analysis, ini settings (such as aliases) will
946
        // be considered now.
947
        hpx::program_options::options_description help;
623✔
948
        std::vector<std::string> unregistered_options;
623✔
949

950
        error_mode |= util::commandline_error_mode::report_missing_config_file;
623✔
951
        if (!parse_commandline(rtcfg_, desc_cmdline, argv[0], args, vm_,
623✔
952
                error_mode, &help, &unregistered_options))
623✔
953
        {
954
            return -1;
×
955
        }
956

957
        // break into debugger, if requested
958
        handle_attach_debugger();
623✔
959

960
        // handle all --hpx:foo options
961
        if (!handle_arguments(cfgmap, vm_, ini_config_))
623✔
962
        {
963
            return -2;
×
964
        }
965

966
        return finalize_commandline_handling(
623✔
967
            argc, argv, help, unregistered_options);
623✔
968
    }
623✔
969

970
    int command_line_handling::finalize_commandline_handling(int argc,
1,221✔
971
        char** argv, hpx::program_options::options_description const& help,
972
        std::vector<std::string> const& unregistered_options)
973
    {
974
        // store unregistered command line and arguments
975
        store_command_line(argc, argv);
1,221✔
976
        store_unregistered_options(argv[0], unregistered_options);
1,221✔
977

978
        // add all remaining ini settings to the global configuration
979
        rtcfg_.reconfigure(ini_config_);
1,221✔
980

981
        // help can be printed only after the runtime mode has been set
982
        if (handle_help_options(help))
1,221✔
983
        {
984
            return 1;    // exit application gracefully
3✔
985
        }
986

987
        // print version/copyright information
988
        if (vm_.count("hpx:version"))
1,218✔
989
        {
990
            if (!version_printed_)
×
991
            {
992
                detail::print_version(std::cout);
×
993
                version_printed_ = true;
×
994
            }
×
995

996
            return 1;
×
997
        }
998

999
        // print configuration information (static and dynamic)
1000
        if (vm_.count("hpx:info"))
1,218✔
1001
        {
1002
            if (!info_printed_)
×
1003
            {
1004
                detail::print_info(std::cout, *this);
×
1005
                info_printed_ = true;
×
1006
            }
×
1007

1008
            return 1;
×
1009
        }
1010

1011
        // all is good
1012
        return 0;
1,218✔
1013
    }
1,221✔
1014
}    // namespace hpx::local::detail
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc