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

STEllAR-GROUP / hpx / #848

07 Dec 2022 11:00PM CUT coverage: 86.456% (+0.6%) from 85.835%
#848

push

StellarBot
Merge #6096

6096: Forking Boost.Tokenizer r=hkaiser a=hkaiser

- flyby: remove more Boost headers that are not needed anymore

Working towards #3440 

Co-authored-by: Hartmut Kaiser <hartmut.kaiser@gmail.com>

525 of 525 new or added lines in 20 files covered. (100.0%)

173087 of 200202 relevant lines covered (86.46%)

1845223.38 hits per line

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

65.64
/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 { namespace local { namespace detail {
39
    std::string runtime_configuration_string(command_line_handling const& cfg)
×
40
    {
41
        std::ostringstream strm;
×
42

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

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

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

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

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

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

69
        return 1;
×
70
    }
×
71

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

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

90
    inline std::string encode_and_enquote(std::string str)
6,006✔
91
    {
92
        encode(str, '\"', "\\\"", 2);
6,006✔
93
        return util::detail::enquote(str);
6,006✔
94
    }
95

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

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

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

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

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

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

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

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

151
            return affinity_desc;
×
152
        }
×
153

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

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

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

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

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

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

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

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

214
    std::size_t get_number_of_default_cores(bool use_process_mask)
7,264✔
215
    {
216
        threads::topology& top = threads::create_topology();
7,264✔
217

218
        std::size_t num_cores = top.get_number_of_cores();
7,264✔
219

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

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

235
            return num_cores_proc_mask;
×
236
        }
×
237

238
        return num_cores;
7,264✔
239
    }
7,264✔
240

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

253
        std::string threads_str = cfgmap.get_value<std::string>(
4,872✔
254
            "hpx.os_threads",
2,436✔
255
            rtcfg.get_entry("hpx.os_threads", std::to_string(init_threads)));
2,436✔
256

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

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

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

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

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

311
        if (min_os_threads == 0)
2,436✔
312
        {
313
            throw hpx::detail::command_line_error(
×
314
                "Number of hpx.force_min_os_threads must be greater "
315
                "than "
316
                "0");
317
        }
318

319
#if defined(HPX_HAVE_MAX_CPU_COUNT)
320
        if (min_os_threads > HPX_HAVE_MAX_CPU_COUNT)
321
        {
322
            throw hpx::detail::command_line_error(
323
                "Requested more than " HPX_PP_STRINGIZE(
324
                    HPX_HAVE_MAX_CPU_COUNT) " hpx.force_min_os_threads "
325
                                            "to use for this "
326
                                            "application, "
327
                                            "use the option "
328
                                            "-DHPX_WITH_MAX_CPU_COUNT=<"
329
                                            "N> "
330
                                            "when configuring HPX.");
331
        }
332
#endif
333

334
        threads = (std::max)(threads, min_os_threads);
2,436✔
335

336
        return threads;
2,436✔
337
    }
2,436✔
338

339
    std::size_t handle_num_cores(util::manage_config& cfgmap,
3,632✔
340
        hpx::program_options::variables_map& vm, std::size_t num_threads,
341
        std::size_t num_default_cores)
342
    {
343
        std::string cores_str = cfgmap.get_value<std::string>("hpx.cores", "");
3,632✔
344
        if ("all" == cores_str)
3,632✔
345
        {
346
            cfgmap.config_["hpx.cores"] = std::to_string(num_default_cores);
×
347
        }
×
348

349
        std::size_t num_cores =
3,632✔
350
            cfgmap.get_value<std::size_t>("hpx.cores", num_threads);
3,632✔
351
        if (vm.count("hpx:cores"))
3,632✔
352
        {
353
            cores_str = vm["hpx:cores"].as<std::string>();
2✔
354
            if ("all" == cores_str)
2✔
355
            {
356
                num_cores = num_default_cores;
×
357
            }
×
358
            else
359
            {
360
                num_cores = hpx::util::from_string<std::size_t>(cores_str);
2✔
361
            }
362
        }
2✔
363

364
        return num_cores;
3,632✔
365
    }
3,632✔
366

367
    std::size_t handle_num_cores(util::manage_config& cfgmap,
2,436✔
368
        hpx::program_options::variables_map& vm, std::size_t num_threads,
369
        bool use_process_mask)
370
    {
371
        return handle_num_cores(cfgmap, vm, num_threads,
4,872✔
372
            get_number_of_default_cores(use_process_mask));
2,436✔
373
    }
374

375
    void print_config(std::vector<std::string> const& ini_config)
×
376
    {
377
        std::cerr << "Configuration before runtime start:\n";
×
378
        std::cerr << "-----------------------------------\n";
×
379
        for (std::string const& s : ini_config)
×
380
        {
381
            std::cerr << s << std::endl;
×
382
        }
383
        std::cerr << "-----------------------------------\n";
×
384
    }
×
385

386
    ///////////////////////////////////////////////////////////////////////
387
    void command_line_handling::check_affinity_domain() const
2,436✔
388
    {
389
        if (affinity_domain_ != "pu")
2,436✔
390
        {
391
            if (0 != std::string("pu").find(affinity_domain_) &&
×
392
                0 != std::string("core").find(affinity_domain_) &&
×
393
                0 != std::string("numa").find(affinity_domain_) &&
×
394
                0 != std::string("machine").find(affinity_domain_))
×
395
            {
396
                throw hpx::detail::command_line_error(
×
397
                    "Invalid command line option --hpx:affinity, value must be "
398
                    "one of: pu, core, numa, or machine.");
399
            }
400
        }
×
401
    }
2,436✔
402

403
    void command_line_handling::check_affinity_description() const
2,436✔
404
    {
405
        if (affinity_bind_.empty())
2,436✔
406
        {
407
            return;
×
408
        }
409

410
        if (!(pu_offset_ == std::size_t(-1) || pu_offset_ == std::size_t(0)) ||
4,872✔
411
            pu_step_ != 1 || affinity_domain_ != "pu")
2,436✔
412
        {
413
            throw hpx::detail::command_line_error(
×
414
                "Command line option --hpx:bind should not be used with "
415
                "--hpx:pu-step, --hpx:pu-offset, or --hpx:affinity.");
416
        }
417
    }
2,436✔
418

419
    void command_line_handling::check_pu_offset() const
2,436✔
420
    {
421
        if (pu_offset_ != std::size_t(-1) &&
2,436✔
422
            pu_offset_ >= hpx::threads::hardware_concurrency())
×
423
        {
424
            throw hpx::detail::command_line_error(
×
425
                "Invalid command line option --hpx:pu-offset, value must be "
426
                "smaller than number of available processing units.");
427
        }
428
    }
2,436✔
429

430
    void command_line_handling::check_pu_step() const
2,436✔
431
    {
432
        if (hpx::threads::hardware_concurrency() > 1 &&
4,872✔
433
            (pu_step_ == 0 || pu_step_ >= hpx::threads::hardware_concurrency()))
2,436✔
434
        {
435
            throw hpx::detail::command_line_error(
×
436
                "Invalid command line option --hpx:pu-step, value must be "
437
                "non-zero and smaller than number of available processing "
438
                "units.");
439
        }
440
    }
2,436✔
441

442
    void command_line_handling::handle_high_priority_threads(
3,632✔
443
        hpx::program_options::variables_map& vm,
444
        std::vector<std::string>& ini_config)
445
    {
446
        if (vm_.count("hpx:high-priority-threads"))
3,632✔
447
        {
448
            std::size_t num_high_priority_queues =
×
449
                vm["hpx:high-priority-threads"].as<std::size_t>();
×
450
            if (num_high_priority_queues != std::size_t(-1) &&
×
451
                num_high_priority_queues > num_threads_)
×
452
            {
453
                throw hpx::detail::command_line_error(
×
454
                    "Invalid command line option: number of high priority "
455
                    "threads (--hpx:high-priority-threads), should not be "
456
                    "larger than number of threads (--hpx:threads)");
457
            }
458

459
            if (!(queuing_ == "local-priority" || queuing_ == "abp-priority"))
×
460
            {
461
                throw hpx::detail::command_line_error(
×
462
                    "Invalid command line option --hpx:high-priority-threads, "
463
                    "valid for --hpx:queuing=local-priority and "
464
                    "--hpx:queuing=abp-priority only");
465
            }
466

467
            ini_config.emplace_back("hpx.thread_queue.high_priority_queues!=" +
×
468
                std::to_string(num_high_priority_queues));
×
469
        }
×
470
    }
3,632✔
471

472
    ///////////////////////////////////////////////////////////////////////////
473
    bool command_line_handling::handle_arguments(util::manage_config& cfgmap,
2,436✔
474
        hpx::program_options::variables_map& vm,
475
        std::vector<std::string>& ini_config)
476
    {
477
        bool debug_clp = vm.count("hpx:debug-clp");
2,436✔
478

479
        if (vm.count("hpx:ini"))
2,436✔
480
        {
481
            std::vector<std::string> cfg =
482
                vm["hpx:ini"].as<std::vector<std::string>>();
571✔
483
            std::copy(cfg.begin(), cfg.end(), std::back_inserter(ini_config));
571✔
484
            cfgmap.add(cfg);
571✔
485
        }
571✔
486

487
        use_process_mask_ =
2,436✔
488
            (cfgmap.get_value<int>("hpx.use_process_mask", 0) > 0) ||
4,872✔
489
            (vm.count("hpx:use-process-mask") > 0);
2,436✔
490

491
#if defined(__APPLE__)
492
        if (use_process_mask_)
493
        {
494
            std::cerr
495
                << "Warning: enabled process mask for thread binding, but "
496
                   "thread binding is not supported on macOS. Ignoring option."
497
                << std::endl;
498
            use_process_mask_ = false;
499
        }
500
#endif
501

502
        ini_config.emplace_back(
2,436✔
503
            "hpx.use_process_mask!=" + std::to_string(use_process_mask_));
2,436✔
504

505
        // handle setting related to schedulers
506
        queuing_ = detail::handle_queuing(cfgmap, vm, "local-priority-fifo");
2,436✔
507
        ini_config.emplace_back("hpx.scheduler=" + queuing_);
2,436✔
508

509
        affinity_domain_ = detail::handle_affinity(cfgmap, vm, "pu");
2,436✔
510
        ini_config.emplace_back("hpx.affinity=" + affinity_domain_);
2,436✔
511

512
        check_affinity_domain();
2,436✔
513

514
        affinity_bind_ = detail::handle_affinity_bind(cfgmap, vm, "");
2,436✔
515
        if (!affinity_bind_.empty())
2,436✔
516
        {
517
#if defined(__APPLE__)
518
            std::cerr << "Warning: thread binding set to \"" << affinity_bind_
519
                      << "\" but thread binding is not supported on macOS. "
520
                         "Ignoring option."
521
                      << std::endl;
522
            affinity_bind_ = "";
523
#else
524
            ini_config.emplace_back("hpx.bind!=" + affinity_bind_);
×
525
#endif
526
        }
×
527

528
        pu_step_ = detail::handle_pu_step(cfgmap, vm, 1);
2,436✔
529
#if defined(__APPLE__)
530
        if (pu_step_ != 1)
531
        {
532
            std::cerr << "Warning: PU step set to \"" << pu_step_
533
                      << "\" but thread binding is not supported on macOS. "
534
                         "Ignoring option."
535
                      << std::endl;
536
            pu_step_ = 1;
537
        }
538
#endif
539
        ini_config.emplace_back("hpx.pu_step=" + std::to_string(pu_step_));
2,436✔
540

541
        check_pu_step();
2,436✔
542

543
        pu_offset_ = detail::handle_pu_offset(cfgmap, vm, std::size_t(-1));
2,436✔
544

545
        // NOLINTNEXTLINE(bugprone-branch-clone)
546
        if (pu_offset_ != std::size_t(-1))
2,436✔
547
        {
548
#if defined(__APPLE__)
549
            std::cerr << "Warning: PU offset set to \"" << pu_offset_
550
                      << "\" but thread binding is not supported on macOS. "
551
                         "Ignoring option."
552
                      << std::endl;
553
            pu_offset_ = std::size_t(-1);
554
            ini_config.emplace_back("hpx.pu_offset=0");
555
#else
556
            ini_config.emplace_back(
×
557
                "hpx.pu_offset=" + std::to_string(pu_offset_));
×
558
#endif
559
        }
×
560
        else
561
        {
562
            ini_config.emplace_back("hpx.pu_offset=0");
2,436✔
563
        }
564

565
        check_pu_offset();
2,436✔
566

567
        numa_sensitive_ = detail::handle_numa_sensitive(
2,436✔
568
            cfgmap, vm, affinity_bind_.empty() ? 0 : 1);
2,436✔
569
        ini_config.emplace_back(
2,436✔
570
            "hpx.numa_sensitive=" + std::to_string(numa_sensitive_));
2,436✔
571

572
        // default affinity mode is now 'balanced' (only if no pu-step or
573
        // pu-offset is given)
574
        if (pu_step_ == 1 && pu_offset_ == std::size_t(-1) &&
2,436✔
575
            affinity_bind_.empty())
2,436✔
576
        {
577
#if defined(__APPLE__)
578
            affinity_bind_ = "none";
579
#else
580
            affinity_bind_ = "balanced";
2,436✔
581
#endif
582
            ini_config.emplace_back("hpx.bind!=" + affinity_bind_);
2,436✔
583
        }
2,436✔
584

585
        check_affinity_description();
2,436✔
586

587
        // handle number of cores and threads
588
        num_threads_ =
2,436✔
589
            detail::handle_num_threads(cfgmap, rtcfg_, vm, use_process_mask_);
2,436✔
590
        num_cores_ = detail::handle_num_cores(
2,436✔
591
            cfgmap, vm, num_threads_, use_process_mask_);
2,436✔
592

593
        // Set number of cores and OS threads in configuration.
594
        ini_config.emplace_back(
2,436✔
595
            "hpx.os_threads=" + std::to_string(num_threads_));
2,436✔
596
        ini_config.emplace_back("hpx.cores=" + std::to_string(num_cores_));
2,436✔
597

598
        // handle high-priority threads
599
        handle_high_priority_threads(vm, ini_config);
2,436✔
600

601
        enable_logging_settings(vm, ini_config);
2,436✔
602

603
        if (debug_clp)
2,436✔
604
        {
605
            print_config(ini_config);
×
606
        }
×
607

608
        return true;
2,436✔
609
    }
×
610

611
    ///////////////////////////////////////////////////////////////////////////
612
    void command_line_handling::enable_logging_settings(
4,850✔
613
        hpx::program_options::variables_map& vm,
614
        [[maybe_unused]] std::vector<std::string>& ini_config)
615
    {
616
#if defined(HPX_HAVE_LOGGING)
617
        if (vm.count("hpx:debug-hpx-log"))
4,850✔
618
        {
619
            ini_config.emplace_back("hpx.logging.console.destination=" +
9,538✔
620
                detail::convert_to_log_file(
4,769✔
621
                    vm["hpx:debug-hpx-log"].as<std::string>()));
4,769✔
622
            ini_config.emplace_back("hpx.logging.destination=" +
9,538✔
623
                detail::convert_to_log_file(
4,769✔
624
                    vm["hpx:debug-hpx-log"].as<std::string>()));
4,769✔
625
            ini_config.emplace_back("hpx.logging.console.level=5");
4,769✔
626
            ini_config.emplace_back("hpx.logging.level=5");
4,769✔
627
        }
4,769✔
628

629
        if (vm.count("hpx:debug-timing-log"))
4,850✔
630
        {
631
            ini_config.emplace_back("hpx.logging.console.timing.destination=" +
×
632
                detail::convert_to_log_file(
×
633
                    vm["hpx:debug-timing-log"].as<std::string>()));
×
634
            ini_config.emplace_back("hpx.logging.timing.destination=" +
×
635
                detail::convert_to_log_file(
×
636
                    vm["hpx:debug-timing-log"].as<std::string>()));
×
637
            ini_config.emplace_back("hpx.logging.console.timing.level=1");
×
638
            ini_config.emplace_back("hpx.logging.timing.level=1");
×
639
        }
×
640

641
        if (vm.count("hpx:debug-app-log"))
4,850✔
642
        {
643
            ini_config.emplace_back(
×
644
                "hpx.logging.console.application.destination=" +
×
645
                detail::convert_to_log_file(
×
646
                    vm["hpx:debug-app-log"].as<std::string>()));
×
647
            ini_config.emplace_back("hpx.logging.application.destination=" +
×
648
                detail::convert_to_log_file(
×
649
                    vm["hpx:debug-app-log"].as<std::string>()));
×
650
            ini_config.emplace_back("hpx.logging.console.application.level=5");
×
651
            ini_config.emplace_back("hpx.logging.application.level=5");
×
652
        }
×
653
#else
654
        if (vm.count("hpx:debug-hpx-log") || vm.count("hpx:debug-timing-log") ||
655
            vm.count("hpx:debug-app-log"))
656
        {
657
            // clang-format off
658
            throw hpx::detail::command_line_error(
659
                "Command line option error: can't enable logging while it "
660
                "was disabled at configuration time. Please re-configure "
661
                "HPX using the option -DHPX_WITH_LOGGING=On.");
662
            // clang-format on
663
        }
664
#endif
665
    }
4,850✔
666

667
    ///////////////////////////////////////////////////////////////////////////
668
    void command_line_handling::store_command_line(int argc, char** argv)
1,218✔
669
    {
670
        // Collect the command line for diagnostic purposes.
671
        std::string command;
1,218✔
672
        std::string cmd_line;
1,218✔
673
        std::string options;
1,218✔
674
        for (int i = 0; i < argc; ++i)
6,002✔
675
        {
676
            // quote only if it contains whitespace
677
            std::string arg = detail::encode_and_enquote(argv[i]);    //-V108
4,784✔
678

679
            cmd_line += arg;
4,784✔
680
            if (i == 0)
4,784✔
681
            {
682
                command = arg;
1,218✔
683
            }
1,218✔
684
            else
685
            {
686
                options += " " + arg;
3,566✔
687
            }
688

689
            if ((i + 1) != argc)
4,784✔
690
            {
691
                cmd_line += " ";
3,566✔
692
            }
3,566✔
693
        }
4,784✔
694

695
        // Store the program name and the command line.
696
        ini_config_.emplace_back("hpx.cmd_line!=" + cmd_line);
1,218✔
697
        ini_config_.emplace_back("hpx.commandline.command!=" + command);
1,218✔
698
        ini_config_.emplace_back("hpx.commandline.options!=" + options);
1,218✔
699
    }
1,218✔
700

701
    ///////////////////////////////////////////////////////////////////////////
702
    void command_line_handling::store_unregistered_options(
1,218✔
703
        std::string const& cmd_name,
704
        std::vector<std::string> const& unregistered_options)
705
    {
706
        std::string unregistered_options_cmd_line;
1,218✔
707

708
        if (!unregistered_options.empty())
1,218✔
709
        {
710
            typedef std::vector<std::string>::const_iterator iterator_type;
711

712
            iterator_type end = unregistered_options.end();
2✔
713
            for (iterator_type it = unregistered_options.begin(); it != end;
4✔
714
                 ++it)
2✔
715
                unregistered_options_cmd_line +=
2✔
716
                    " " + detail::encode_and_enquote(*it);
2✔
717

718
            ini_config_.emplace_back("hpx.unknown_cmd_line!=" +
6✔
719
                detail::encode_and_enquote(cmd_name) +
4✔
720
                unregistered_options_cmd_line);
721
        }
2✔
722

723
        ini_config_.emplace_back("hpx.program_name!=" + cmd_name);
1,218✔
724
        ini_config_.emplace_back("hpx.reconstructed_cmd_line!=" +
3,654✔
725
            encode_and_enquote(cmd_name) + " " + reconstruct_command_line(vm_) +
2,436✔
726
            " " + unregistered_options_cmd_line);
1,218✔
727
    }
1,218✔
728

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

765
    void command_line_handling::handle_attach_debugger()
1,218✔
766
    {
767
#if defined(_POSIX_VERSION) || defined(HPX_WINDOWS)
768
        if (vm_.count("hpx:attach-debugger"))
1,218✔
769
        {
770
            std::string option = vm_["hpx:attach-debugger"].as<std::string>();
×
771
            if (option != "off" && option != "startup" &&
×
772
                option != "exception" && option != "test-failure")
×
773
            {
774
                // clang-format off
775
                std::cerr <<
×
776
                    "hpx::init: command line warning: --hpx:attach-debugger: "
777
                    "invalid option: " << option << ". Allowed values are "
×
778
                    "'off', 'startup', 'exception' or 'test-failure'" << std::endl;
×
779
                // clang-format on
780
            }
×
781
            else
782
            {
783
                if (option == "startup")
×
784
                    util::attach_debugger();
×
785

786
                ini_config_.emplace_back("hpx.attach_debugger!=" + option);
×
787
            }
788
        }
×
789
#endif
790
    }
1,218✔
791

792
    ///////////////////////////////////////////////////////////////////////////
793
    // separate command line arguments from configuration settings
794
    std::vector<std::string> command_line_handling::preprocess_config_settings(
1,218✔
795
        int argc, char** argv)
796
    {
797
        std::vector<std::string> options;
1,218✔
798
        options.reserve(static_cast<std::size_t>(argc) + ini_config_.size());
1,218✔
799

800
        // extract all command line arguments from configuration settings and
801
        // remove them from this list
802
        auto it = std::stable_partition(ini_config_.begin(), ini_config_.end(),
1,218✔
803
            [](std::string const& e) { return e.find("--hpx:") != 0; });
953✔
804

805
        std::move(it, ini_config_.end(), std::back_inserter(options));
1,218✔
806
        ini_config_.erase(it, ini_config_.end());
1,218✔
807

808
        // store the command line options that came from the configuration
809
        // settings in the registry
810
        if (!options.empty())
1,218✔
811
        {
812
            std::string config_options;
16✔
813
            for (auto const& option : options)
34✔
814
            {
815
                config_options += " " + option;
18✔
816
            }
817

818
            rtcfg_.add_entry("hpx.commandline.config_options", config_options);
16✔
819
        }
16✔
820

821
        // now append all original command line options
822
        for (int i = 1; i != argc; ++i)
4,784✔
823
        {
824
            options.emplace_back(argv[i]);
3,566✔
825
        }
3,566✔
826

827
        return options;
1,218✔
828
    }
1,218✔
829

830
    ///////////////////////////////////////////////////////////////////////////
831
    std::vector<std::string> prepend_options(
1,218✔
832
        std::vector<std::string>&& args, std::string&& options)
833
    {
834
        if (options.empty())
1,218✔
835
        {
836
            return HPX_MOVE(args);
1,218✔
837
        }
838

839
        hpx::string_util::escaped_list_separator sep('\\', ' ', '\"');
×
840
        hpx::string_util::tokenizer tok(options, sep);
×
841

842
        std::vector<std::string> result(tok.begin(), tok.end());
×
843
        std::move(args.begin(), args.end(), std::back_inserter(result));
×
844
        return result;
×
845
    }
1,218✔
846

847
    ///////////////////////////////////////////////////////////////////////////
848
    void command_line_handling::reconfigure(
1,218✔
849
        util::manage_config& cfgmap, hpx::program_options::variables_map& prevm)
850
    {
851
        // re-initialize runtime configuration object
852
        if (prevm.count("hpx:config"))
1,218✔
853
            rtcfg_.reconfigure(prevm["hpx:config"].as<std::string>());
1,218✔
854
        else
855
            rtcfg_.reconfigure("");
×
856

857
        // Make sure any aliases defined on the command line get used for the
858
        // option analysis below.
859
        std::vector<std::string> cfg;
1,218✔
860
        if (prevm.count("hpx:ini"))
1,218✔
861
        {
862
            cfg = prevm["hpx:ini"].as<std::vector<std::string>>();
285✔
863
            cfgmap.add(cfg);
285✔
864
        }
285✔
865

866
        // append ini options from command line
867
        std::copy(
1,218✔
868
            ini_config_.begin(), ini_config_.end(), std::back_inserter(cfg));
1,218✔
869

870
        // enable logging if invoked requested from command line
871
        std::vector<std::string> ini_config_logging;
1,218✔
872
        enable_logging_settings(prevm, ini_config_logging);
1,218✔
873

874
        std::copy(ini_config_logging.begin(), ini_config_logging.end(),
1,218✔
875
            std::back_inserter(cfg));
1,218✔
876

877
        rtcfg_.reconfigure(cfg);
1,218✔
878
    }
1,218✔
879

880
    int command_line_handling::call(
620✔
881
        hpx::program_options::options_description const& desc_cmdline, int argc,
882
        char** argv)
883
    {
884
        // set the flag signaling that command line parsing has been done
885
        cmd_line_parsed_ = true;
620✔
886

887
        // separate command line arguments from configuration settings
888
        std::vector<std::string> args = preprocess_config_settings(argc, argv);
620✔
889

890
        util::manage_config cfgmap(ini_config_);
620✔
891

892
        // insert the pre-configured ini settings before loading modules
893
        for (std::string const& e : ini_config_)
1,018✔
894
            rtcfg_.parse("<user supplied config>", e, true, false);
398✔
895

896
        // support re-throwing command line exceptions for testing purposes
897
        int error_mode = util::allow_unregistered;
620✔
898
        if (cfgmap.get_value("hpx.commandline.rethrow_errors", 0) != 0)
620✔
899
        {
900
            error_mode |= util::rethrow_on_error;
1✔
901
        }
1✔
902

903
        // The cfg registry may hold command line options to prepend to the
904
        // real command line.
905
        std::string prepend_command_line =
906
            rtcfg_.get_entry("hpx.commandline.prepend_options");
620✔
907

908
        args = prepend_options(HPX_MOVE(args), HPX_MOVE(prepend_command_line));
620✔
909

910
        // Initial analysis of the command line options. This is preliminary as
911
        // it will not take into account any aliases as defined in any of the
912
        // runtime configuration files.
913
        {
914
            // Boost V1.47 and before do not properly reset a variables_map when
915
            // calling vm.clear(). We work around that problems by creating a
916
            // separate instance just for the preliminary command line handling.
917
            hpx::program_options::variables_map prevm;
620✔
918
            if (!parse_commandline(
620✔
919
                    rtcfg_, desc_cmdline, argv[0], args, prevm, error_mode))
620✔
920
            {
921
                return -1;
×
922
            }
923

924
            // handle all --hpx:foo options
925
            std::vector<std::string> ini_config;    // discard
620✔
926
            if (!handle_arguments(cfgmap, prevm, ini_config))
620✔
927
            {
928
                return -2;
×
929
            }
930

931
            reconfigure(cfgmap, prevm);
620✔
932
        }
620✔
933

934
        // Re-run program option analysis, ini settings (such as aliases) will
935
        // be considered now.
936
        hpx::program_options::options_description help;
620✔
937
        std::vector<std::string> unregistered_options;
620✔
938

939
        if (!parse_commandline(rtcfg_, desc_cmdline, argv[0], args, vm_,
620✔
940
                error_mode | util::report_missing_config_file, &help,
620✔
941
                &unregistered_options))
942
        {
943
            return -1;
×
944
        }
945

946
        // break into debugger, if requested
947
        handle_attach_debugger();
620✔
948

949
        // handle all --hpx:foo options
950
        if (!handle_arguments(cfgmap, vm_, ini_config_))
620✔
951
        {
952
            return -2;
×
953
        }
954

955
        return finalize_commandline_handling(
620✔
956
            argc, argv, help, unregistered_options);
620✔
957
    }
620✔
958

959
    int command_line_handling::finalize_commandline_handling(int argc,
1,218✔
960
        char** argv, hpx::program_options::options_description const& help,
961
        std::vector<std::string> const& unregistered_options)
962
    {
963
        // store unregistered command line and arguments
964
        store_command_line(argc, argv);
1,218✔
965
        store_unregistered_options(argv[0], unregistered_options);
1,218✔
966

967
        // add all remaining ini settings to the global configuration
968
        rtcfg_.reconfigure(ini_config_);
1,218✔
969

970
        // help can be printed only after the runtime mode has been set
971
        if (handle_help_options(help))
1,218✔
972
        {
973
            return 1;    // exit application gracefully
3✔
974
        }
975

976
        // print version/copyright information
977
        if (vm_.count("hpx:version"))
1,215✔
978
        {
979
            if (!version_printed_)
×
980
            {
981
                detail::print_version(std::cout);
×
982
                version_printed_ = true;
×
983
            }
×
984

985
            return 1;
×
986
        }
987

988
        // print configuration information (static and dynamic)
989
        if (vm_.count("hpx:info"))
1,215✔
990
        {
991
            if (!info_printed_)
×
992
            {
993
                detail::print_info(std::cout, *this);
×
994
                info_printed_ = true;
×
995
            }
×
996

997
            return 1;
×
998
        }
999

1000
        // all is good
1001
        return 0;
1,215✔
1002
    }
1,218✔
1003
}}}    // 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

© 2025 Coveralls, Inc