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

STEllAR-GROUP / hpx / #882

31 Aug 2023 07:44PM UTC coverage: 41.798% (-44.7%) from 86.546%
#882

push

19442 of 46514 relevant lines covered (41.8%)

126375.38 hits per line

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

64.13
/libs/full/command_line_handling/src/command_line_handling.cpp
1
//  Copyright (c) 2007-2025 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/command_line_handling.hpp>
10
#include <hpx/command_line_handling/parse_command_line.hpp>
11
#include <hpx/modules/asio.hpp>
12
#include <hpx/modules/batch_environments.hpp>
13
#include <hpx/modules/debugging.hpp>
14
#include <hpx/modules/format.hpp>
15
#include <hpx/modules/functional.hpp>
16
#include <hpx/modules/logging.hpp>
17
#if defined(HPX_HAVE_MODULE_MPI_BASE)
18
#include <hpx/modules/mpi_base.hpp>
19
#endif
20
#if defined(HPX_HAVE_MODULE_LCI_BASE)
21
#include <hpx/modules/lci_base.hpp>
22
#endif
23
#if defined(HPX_HAVE_MODULE_GASNET_BASE)
24
#include <hpx/modules/gasnet_base.hpp>
25
#endif
26
#include <hpx/modules/program_options.hpp>
27
#include <hpx/modules/runtime_configuration.hpp>
28
#include <hpx/modules/topology.hpp>
29
#include <hpx/modules/util.hpp>
30
#if defined(HPX_HAVE_MAX_CPU_COUNT)
31
#include <hpx/modules/preprocessor.hpp>
32
#endif
33
#include <hpx/version.hpp>
34

35
#include <algorithm>
36
#include <cstddef>
37
#include <cstdint>
38
#include <fstream>
39
#include <iostream>
40
#include <memory>
41
#include <sstream>
42
#include <string>
43
#include <utility>
44
#include <vector>
45

46
#include <hpx/config/warnings_prefix.hpp>
47

48
namespace hpx::util {
49

50
    namespace detail {
×
51

52
        ///////////////////////////////////////////////////////////////////////
53
        std::string runtime_configuration_string(
×
54
            util::command_line_handling const& cfg)
55
        {
56
            std::ostringstream strm;
×
57

×
58
            // runtime mode
59
            strm << "  {mode}: " << get_runtime_mode_name(cfg.rtcfg_.mode_)
×
60
                 << "\n";
×
61

62
            if (cfg.num_localities_ != 1)
×
63
                strm << "  {localities}: " << cfg.num_localities_ << "\n";
64

×
65
            strm << hpx::local::detail::runtime_configuration_string(cfg);
×
66

67
            return strm.str();
68
        }
×
69

70
        ///////////////////////////////////////////////////////////////////////
71
        void report_thread_warning(std::string const& batch_name,
72
            std::size_t threads, std::size_t batch_threads)
73
        {
74
            std::cerr << "hpx::init: command line warning: --hpx:threads "
75
                         "used when running with "
76
                      << batch_name
77
                      << ", requesting a larger number of threads (" << threads
78
                      << ") than cores have been assigned by " << batch_name
79
                      << " (" << batch_threads
×
80
                      << "), the application might not run properly."
81
                      << std::endl;
×
82
        }
83

84
        void report_locality_warning_batch(std::string const& batch_name,
85
            std::size_t batch_localities, std::size_t num_localities)
86
        {
87
            std::cerr << "hpx::init: command line warning: "
88
                         "--hpx:localities used when running with "
89
                      << batch_name
90
                      << ", requesting a different number of localities ("
91
                      << num_localities << ") than have been assigned by "
92
                      << batch_name << " (" << batch_localities
×
93
                      << "), the application might not run properly."
94
                      << std::endl;
×
95
        }
96

97
        void report_locality_warning(std::string const& batch_name,
98
            std::size_t cmdline_localities, std::size_t num_localities)
99
        {
100
            std::cerr << "hpx::init: command line warning: "
101
                         "--hpx:localities used when running with "
102
                      << batch_name
103
                      << ", requesting a different number of localities ("
104
                      << num_localities
105
                      << ") than have been assigned on the command line "
106
                      << " (" << cmdline_localities
×
107
                      << "), the application might not run properly."
108
                      << std::endl;
109
        }
64✔
110

111
        ///////////////////////////////////////////////////////////////////////
112
        std::size_t handle_num_localities(util::manage_config const& cfgmap,
113
            hpx::program_options::variables_map const& vm,
114
            util::batch_environment const& env, bool using_nodelist,
115
            std::size_t num_localities, bool initial)
64✔
116
        {
64✔
117
            std::size_t const batch_localities =
64✔
118
                env.retrieve_number_of_localities();
119
            if (num_localities == 1 &&
58✔
120
                batch_localities != static_cast<std::size_t>(-1))
116✔
121
            {
122
                if (auto const cfg_num_localities =
123
                        cfgmap.get_value<std::size_t>(
124
                            "hpx.localities", batch_localities);
125
                    cfg_num_localities > 1)
126
                {
127
                    num_localities = cfg_num_localities;
128
                }
32✔
129
            }
96✔
130

131
            if (!initial && env.found_batch_environment() && using_nodelist &&
×
132
                (batch_localities != num_localities) && (num_localities != 1))
×
133
            {
134
                detail::report_locality_warning_batch(
135
                    env.get_batch_name(), batch_localities, num_localities);
128✔
136
            }
137

138
            if (vm.count("hpx:localities"))
24✔
139
            {
140
                std::size_t const localities =
12✔
141
                    vm["hpx:localities"].as<std::size_t>();
142

143
                if (localities == 0)
×
144
                {
145
                    throw hpx::detail::command_line_error(
146
                        "Number of --hpx:localities must be greater than 0");
6✔
147
                }
18✔
148

149
                if (!initial && env.found_batch_environment() &&
150
                    using_nodelist && (localities != num_localities) &&
×
151
                    (num_localities != 1))
×
152
                {
153
                    detail::report_locality_warning(
154
                        env.get_batch_name(), localities, num_localities);
155
                }
156
                num_localities = localities;
157
            }
158

159
#if !defined(HPX_HAVE_NETWORKING)
160
            if (num_localities != 1)
161
            {
162
                throw hpx::detail::command_line_error(
163
                    "Number of --hpx:localities must be equal to 1, please "
164
                    "enable networking to run distributed HPX applications "
165
                    "(use -DHPX_WITH_NETWORKING=On during configuration)");
64✔
166
            }
167
#endif
168
            return num_localities;
169
        }
128✔
170

171
        ///////////////////////////////////////////////////////////////////////
172
        std::size_t get_number_of_default_cores(
173
            util::batch_environment const& env, bool use_process_mask)
128✔
174
        {
175
            std::size_t const num_cores =
128✔
176
                hpx::local::detail::get_number_of_default_cores(
177
                    use_process_mask);
178
            if (use_process_mask)
179
            {
180
                return num_cores;
128✔
181
            }
128✔
182

183
            std::size_t batch_threads = env.retrieve_number_of_threads();
184
            if (batch_threads == static_cast<std::size_t>(-1))
185
            {
186
                return num_cores;
187
            }
128✔
188

189
            // assuming we assign the first N cores ...
1,984✔
190
            threads::topology const& top = threads::create_topology();
191
            std::size_t core = 0;
1,984✔
192
            for (/**/; core < num_cores; ++core)
1,984✔
193
            {
194
                batch_threads -= top.get_number_of_core_pus(core);
195
                if (batch_threads == 0)
128✔
196
                    break;
197
            }
198
            return core + 1;
199
        }
64✔
200

201
        ///////////////////////////////////////////////////////////////////////
202
        std::size_t handle_num_threads(util::manage_config const& cfgmap,
203
            util::runtime_configuration const& rtcfg,
204
            hpx::program_options::variables_map const& vm,
205
            util::batch_environment const& env, bool using_nodelist,
206
            bool initial, bool use_process_mask)
207
        {
208
            // If using the process mask we override "cores" and "all" options
64✔
209
            // but keep explicit numeric values.
210
            std::size_t const init_threads =
211
                hpx::local::detail::get_number_of_default_threads(
64✔
212
                    use_process_mask);
64✔
213
            std::size_t const init_cores =
214
                detail::get_number_of_default_cores(env, use_process_mask);
64✔
215
            std::size_t const batch_threads = env.retrieve_number_of_threads();
128✔
216

256✔
217
            auto threads_str = cfgmap.get_value<std::string>("hpx.os_threads",
218
                rtcfg.get_entry(
219
                    "hpx.os_threads", std::to_string(init_threads)));
64✔
220

221
            std::size_t threads;
64✔
222
            if ("cores" == threads_str)
64✔
223
            {
224
                threads = init_cores;
64✔
225
                if (batch_threads != static_cast<std::size_t>(-1))
226
                {
227
                    threads = batch_threads;
×
228
                }
229
            }
×
230
            else if ("all" == threads_str)
×
231
            {
232
                threads = init_threads;
×
233
                if (batch_threads != static_cast<std::size_t>(-1))
234
                {
235
                    threads = batch_threads;
×
236
                }
237
            }
×
238
            else if (batch_threads != static_cast<std::size_t>(-1))
239
            {
240
                threads = batch_threads;
241
            }
×
242
            else
243
            {
244
                threads = cfgmap.get_value<std::size_t>("hpx.os_threads",
245
                    hpx::util::from_string<std::size_t>(threads_str));
128✔
246
            }
247

128✔
248
            if (vm.count("hpx:threads"))
64✔
249
            {
250
                threads_str = vm["hpx:threads"].as<std::string>();
×
251
                if ("all" == threads_str)
×
252
                {
253
                    threads = init_threads;
×
254
                    if (batch_threads != static_cast<std::size_t>(-1))
255
                    {
256
                        threads = batch_threads;
64✔
257
                    }
258
                }
×
259
                else if ("cores" == threads_str)
×
260
                {
261
                    threads = init_cores;
×
262
                    if (batch_threads != static_cast<std::size_t>(-1))
263
                    {
264
                        threads = batch_threads;
265
                    }
266
                }
64✔
267
                else
268
                {
269
                    threads = hpx::util::from_string<std::size_t>(threads_str);
64✔
270
                }
271

272
                if (threads == 0)
×
273
                {
274
                    throw hpx::detail::command_line_error(
275
                        "Number of --hpx:threads must be greater than 0");
276
                }
277

278
#if defined(HPX_HAVE_MAX_CPU_COUNT)
279
                if (threads > HPX_HAVE_MAX_CPU_COUNT)
280
                {
281
                    // clang-format off
282
                    throw hpx::detail::command_line_error("Requested more than "
283
                        HPX_PP_STRINGIZE(HPX_HAVE_MAX_CPU_COUNT)" --hpx:threads "
284
                        "to use for this application, use the option "
285
                        "-DHPX_WITH_MAX_CPU_COUNT=<N> when configuring HPX.");
286
                    // clang-format on
287
                }
288
#endif
289
            }
64✔
290

64✔
291
            // make sure minimal requested number of threads is observed
292
            auto min_os_threads = cfgmap.get_value<std::size_t>(
64✔
293
                "hpx.force_min_os_threads", threads);
294

295
            if (min_os_threads == 0)
296
            {
×
297
                throw hpx::detail::command_line_error(
298
                    "Number of hpx.force_min_os_threads must be greater than "
299
                    "0");
300
            }
301

302
#if defined(HPX_HAVE_MAX_CPU_COUNT)
303
            if (min_os_threads > HPX_HAVE_MAX_CPU_COUNT)
304
            {
305
                // clang-format off
306
                throw hpx::detail::command_line_error("Requested more than "
307
                    HPX_PP_STRINGIZE(HPX_HAVE_MAX_CPU_COUNT)
308
                    " hpx.force_min_os_threads to use for this application, "
309
                    "use the option -DHPX_WITH_MAX_CPU_COUNT=<N> when "
310
                    "configuring HPX.");
311
                // clang-format on
312
            }
64✔
313
#endif
314

64✔
315
            threads = (std::max) (threads, min_os_threads);
316

317
            if (!initial && env.found_batch_environment() && using_nodelist &&
×
318
                (threads > batch_threads))
×
319
            {
320
                detail::report_thread_warning(
64✔
321
                    env.get_batch_name(), threads, batch_threads);
322
            }
323
            return threads;
324
        }
325

326
        ///////////////////////////////////////////////////////////////////////
327
#if !defined(HPX_HAVE_NETWORKING)
328
        void check_networking_option(
329
            hpx::program_options::variables_map const& vm, char const* option)
330
        {
331
            if (vm.count(option) != 0)
332
            {
333
                throw hpx::detail::command_line_error(
334
                    std::string("Invalid command line option: '--") + option +
335
                    "', networking was disabled at configuration time. "
336
                    "Reconfigure HPX using -DHPX_WITH_NETWORKING=On.");
337
            }
338
        }
×
339
#endif
340

341
        void check_networking_options(
342
            [[maybe_unused]] hpx::program_options::variables_map const& vm)
343
        {
344
#if !defined(HPX_HAVE_NETWORKING)
345
            check_networking_option(vm, "hpx:agas");
346
            check_networking_option(vm, "hpx:run-agas-server-only");
347
            check_networking_option(vm, "hpx:hpx");
348
            check_networking_option(vm, "hpx:nodefile");
349
            check_networking_option(vm, "hpx:nodes");
350
            check_networking_option(vm, "hpx:endnodes");
351
            check_networking_option(vm, "hpx:ifsuffix");
352
            check_networking_option(vm, "hpx:ifprefix");
353
            check_networking_option(vm, "hpx:iftransform");
354
            check_networking_option(vm, "hpx:localities");
355
            check_networking_option(vm, "hpx:node");
×
356
            check_networking_option(vm, "hpx:expect-connecting-localities");
357
#endif
358
        }
359
    }    // namespace detail
32✔
360

361
    ///////////////////////////////////////////////////////////////////////////
32✔
362
    command_line_handling::command_line_handling(runtime_configuration rtcfg,
363
        std::vector<std::string> ini_config,
32✔
364
        hpx::function<int(hpx::program_options::variables_map& vm)> hpx_main_f)
32✔
365
      : base_type(HPX_MOVE(rtcfg), HPX_MOVE(ini_config), HPX_MOVE(hpx_main_f))
366
      , node_(static_cast<std::size_t>(-1))
32✔
367
      , num_localities_(1)
368
    {
64✔
369
    }
370

371
    bool command_line_handling::handle_arguments(util::manage_config& cfgmap,
372
        hpx::program_options::variables_map& vm,
373
        std::vector<std::string>& ini_config, std::size_t& node, bool initial)
64✔
374
    {
375
        // handle local options
376
        base_type::handle_arguments(cfgmap, vm, ini_config);
377

378
        // verify that no networking options were used if networking was
379
        // disabled
380
        detail::check_networking_options(vm);
96✔
381

382
        bool debug_clp =
383
            node != static_cast<std::size_t>(-1) && vm.count("hpx:debug-clp");
64✔
384

385
        // create host name mapping
128✔
386
        [[maybe_unused]] bool have_tcp =
×
387
            rtcfg_.get_entry("hpx.parcel.tcp.enable", "1") != "0";
128✔
388
        util::map_hostnames mapnames(debug_clp);
×
389

128✔
390
        if (vm.count("hpx:ifsuffix"))
391
            mapnames.use_suffix(vm["hpx:ifsuffix"].as<std::string>());
392
        if (vm.count("hpx:ifprefix"))
393
            mapnames.use_prefix(vm["hpx:ifprefix"].as<std::string>());
64✔
394
        mapnames.force_ipv4(vm.count("hpx:force_ipv4") != 0);
192✔
395

128✔
396
        // The AGAS host name and port number are pre-initialized from
64✔
397
        //the command line
128✔
398
        auto agas_host = cfgmap.get_value<std::string>(
399
            "hpx.agas.address", rtcfg_.get_entry("hpx.agas.address", ""));
128✔
400
        auto agas_port = cfgmap.get_value<std::uint16_t>("hpx.agas.port",
401
            hpx::util::from_string<std::uint16_t>(
×
402
                rtcfg_.get_entry("hpx.agas.port", HPX_INITIAL_IP_PORT)));
×
403

404
        if (vm.count("hpx:agas"))
405
        {
406
            if (!util::split_ip_address(
407
                    vm["hpx:agas"].as<std::string>(), agas_host, agas_port))
408
            {
409
                std::cerr << "hpx::init: command line warning: illegal port "
410
                             "number given, using default value instead."
411
                          << std::endl;
128✔
412
            }
413
        }
414

×
415
        // Check command line arguments.
416
        if (vm.count("hpx:iftransform"))
417
        {
×
418
            util::sed_transform iftransform(
419
                vm["hpx:iftransform"].as<std::string>());
×
420

421
            // Check for parsing failures
×
422
            if (!iftransform)
423
            {
424
                throw hpx::detail::command_line_error(hpx::util::format(
425
                    "Could not parse --hpx:iftransform argument '{1}'",
426
                    vm["hpx:iftransform"].as<std::string>()));
×
427
            }
428

429
            using transform_function_type =
430
                util::map_hostnames::transform_function_type;
431
            mapnames.use_transform(transform_function_type(iftransform));
64✔
432
        }
433

434
        bool using_nodelist = false;
128✔
435

436
        std::vector<std::string> nodelist;
×
437

438
#if defined(HPX_HAVE_NETWORKING)
439
        if (vm.count("hpx:nodefile"))
440
        {
441
            if (vm.count("hpx:nodes"))
×
442
            {
443
                throw hpx::detail::command_line_error(
444
                    "Ambiguous command line options. Do not specify more than "
×
445
                    "one of the --hpx:nodefile and --hpx:nodes options at the "
×
446
                    "same time.");
×
447
            }
×
448

449
            std::string node_file = vm["hpx:nodefile"].as<std::string>();
×
450
            ini_config.emplace_back("hpx.nodefile!=" + node_file);
451
            std::ifstream ifs(node_file.c_str());
452
            if (ifs.is_open())
×
453
            {
454
                if (debug_clp)
×
455
                    std::cerr << "opened: " << node_file << std::endl;
456
                std::string line;
×
457
                while (std::getline(ifs, line))
458
                {
459
                    if (!line.empty())
460
                    {
461
                        nodelist.push_back(line);
462
                    }
×
463
                }
464
            }
465
            else
466
            {
×
467
                if (debug_clp)
×
468
                    std::cerr << "failed opening: " << node_file << std::endl;
469

×
470
                // raise hard error if node file could not be opened
128✔
471
                throw hpx::detail::command_line_error(hpx::util::format(
472
                    "Could not open nodefile: '{}'", node_file));
×
473
            }
474
        }
475
        else if (vm.count("hpx:nodes"))
476
        {
64✔
477
            nodelist = vm["hpx:nodes"].as<std::vector<std::string>>();
192✔
478
        }
64✔
479
#endif
480
        bool enable_batch_env =
481
            ((cfgmap.get_value<std::size_t>("hpx.ignore_batch_env", 0) +
64✔
482
                 vm.count("hpx:ignore-batch-env")) == 0) &&
483
            !use_process_mask_;
484

485
#if defined(HPX_HAVE_MODULE_MPI_BASE)
486
        bool have_mpi = util::mpi_environment::check_mpi_environment(rtcfg_);
487
#else
64✔
488
        bool have_mpi = false;
489
#endif
490

64✔
491
        util::batch_environment env(
492
            nodelist, have_mpi, debug_clp, enable_batch_env);
493

56✔
494
#if defined(HPX_HAVE_NETWORKING)
112✔
495
        if (!nodelist.empty())
496
        {
497
            using_nodelist = true;
498
            ini_config.emplace_back("hpx.nodes!=" +
64✔
499
                env.init_from_nodelist(nodelist, agas_host, have_tcp));
192✔
500
        }
501

502
        // let the batch environment decide about the AGAS host
503
        agas_host = env.agas_host_name(
504
            agas_host.empty() ? HPX_INITIAL_IP_ADDRESS : agas_host);
64✔
505
#endif
506

507
        [[maybe_unused]] bool run_agas_server = false;
508
        [[maybe_unused]] std::string hpx_host;
509
        [[maybe_unused]] std::uint16_t hpx_port = 0;
510

511
#if defined(HPX_HAVE_NETWORKING)
512
        bool expect_connections = false;
64✔
513
        std::uint16_t initial_hpx_port = 0;
514

515
        // handling number of localities, those might have already been
516
        // initialized from MPI environment
517
        num_localities_ = detail::handle_num_localities(
128✔
518
            cfgmap, vm, env, using_nodelist, num_localities_, initial);
64✔
519

64✔
520
        // Determine our network port, use arbitrary port if running on one
521
        // locality.
522
        hpx_host = cfgmap.get_value<std::string>("hpx.parcel.address",
523
            env.host_name(rtcfg_.get_entry(
524
                "hpx.parcel.address", HPX_INITIAL_IP_ADDRESS)));
525

64✔
526
        // we expect dynamic connections if:
64✔
527
        //  - --hpx:expect-connecting-localities or
64✔
528
        //  - hpx.expect_connecting_localities=1 is given, or
529
        //  - num_localities > 1
128✔
530
        expect_connections =
531
            cfgmap.get_value<int>("hpx.expect_connecting_localities",
532
                num_localities_ > 1 ? 1 : 0) != 0;
64✔
533

64✔
534
        if (vm.count("hpx:expect-connecting-localities"))
64✔
535
            expect_connections = true;
536

64✔
537
        ini_config.emplace_back(
538
            std::string("hpx.expect_connecting_localities=") +
12✔
539
            (expect_connections ? "1" : "0"));
24✔
540

541
        if (num_localities_ != 1 || expect_connections)
542
        {
64✔
543
            initial_hpx_port = hpx::util::from_string<std::uint16_t>(
544
                rtcfg_.get_entry("hpx.parcel.port", HPX_INITIAL_IP_PORT));
545
        }
128✔
546

64✔
547
        hpx_port = cfgmap.get_value<std::uint16_t>(
32✔
548
            "hpx.parcel.port", initial_hpx_port);
549

550
        run_agas_server = vm.count("hpx:run-agas-server") != 0;
551
        if (node == static_cast<std::size_t>(-1))
552
            node = env.retrieve_node_number();
553

554
        // make sure that TCP parcelport will only be enabled if necessary
555
        if (num_localities_ == 1 && !expect_connections)
64✔
556
            have_tcp = false;
557
#else
558
        num_localities_ = 1;
559
        node = 0;
560
        have_tcp = false;
32✔
561
#endif
96✔
562

96✔
563
        // If the user has not specified an explicit runtime mode we retrieve it
564
        // from the command line.
565
        if (hpx::runtime_mode::default_ == rtcfg_.mode_)
566
        {
567
#if defined(HPX_HAVE_NETWORKING)
568
            // The default mode is console, i.e. all workers need to be started
×
569
            // with --worker/-w.
570
            rtcfg_.mode_ = hpx::runtime_mode::console;
571
            if (vm.count("hpx:local") + vm.count("hpx:console") +
572
                    vm.count("hpx:worker") + vm.count("hpx:connect") >
573
                1)
64✔
574
            {
575
                throw hpx::detail::command_line_error(
×
576
                    "Ambiguous command line options. Do not specify more than "
577
                    "one of --hpx:local, --hpx:console, --hpx:worker, or "
578
                    "--hpx:connect");
579
            }
580

×
581
            // In these cases we default to executing with an empty hpx_main,
×
582
            // except if specified otherwise.
583
            if (vm.count("hpx:worker"))
584
            {
585
                rtcfg_.mode_ = hpx::runtime_mode::worker;
586

587
                // do not execute any explicit hpx_main except if asked
64✔
588
                // otherwise
589
                if (!vm.count("hpx:run-hpx-main") &&
×
590
                    !cfgmap.get_value<int>("hpx.run_hpx_main", 0))
591
                {
64✔
592
                    util::detail::reset_function(hpx_main_f_);
593
                }
×
594
            }
595
            else if (vm.count("hpx:connect"))
596
            {
597
                rtcfg_.mode_ = hpx::runtime_mode::connect;
598
            }
599
            else if (vm.count("hpx:local"))
600
            {
601
                rtcfg_.mode_ = hpx::runtime_mode::local;
602
            }
603
#elif defined(HPX_HAVE_DISTRIBUTED_RUNTIME)
604
            if (vm.count("hpx:local"))
605
            {
606
                rtcfg_.mode_ = hpx::runtime_mode::local;
607
            }
608
            else
609
            {
610
                rtcfg_.mode_ = hpx::runtime_mode::console;
64✔
611
            }
612
#else
613
            rtcfg_.mode_ = hpx::runtime_mode::local;
614
#endif
64✔
615
        }
616

617
#if defined(HPX_HAVE_NETWORKING)
×
618
        if (rtcfg_.mode_ != hpx::runtime_mode::local)
×
619
        {
620
            // we initialize certain settings if --node is specified (or data
621
            // has been retrieved from the environment)
622
            if (rtcfg_.mode_ == hpx::runtime_mode::connect)
623
            {
624
                // when connecting we need to select a unique port
×
625
                hpx_port = cfgmap.get_value<std::uint16_t>("hpx.parcel.port",
×
626
                    hpx::util::from_string<std::uint16_t>(rtcfg_.get_entry(
627
                        "hpx.parcel.port", HPX_CONNECTING_IP_PORT)));
628

629
                // do not execute any explicit hpx_main except if asked
630
                // otherwise
631
                if (!vm.count("hpx:run-hpx-main") &&
64✔
632
                    !cfgmap.get_value<int>("hpx.run_hpx_main", 0))
64✔
633
                {
634
                    util::detail::reset_function(hpx_main_f_);
635
                }
128✔
636
            }
637
            else if (node != static_cast<std::size_t>(-1) ||
×
638
                vm.count("hpx:node"))
639
            {
640
                // command line overwrites the environment
641
                if (vm.count("hpx:node"))
×
642
                {
643
                    if (vm.count("hpx:agas"))
×
644
                    {
645
                        throw hpx::detail::command_line_error(
646
                            "Command line option --hpx:node is not compatible "
128✔
647
                            "with --hpx:agas");
648
                    }
64✔
649
                    node = vm["hpx:node"].as<std::size_t>();
650
                }
651

652
                if (!vm.count("hpx:worker"))
60✔
653
                {
654
                    if (env.agas_node() == node)
655
                    {
656
                        // console node, by default runs AGAS
657
                        run_agas_server = true;
4✔
658
                        rtcfg_.mode_ = hpx::runtime_mode::console;
×
659
                    }
660
                    else
661
                    {
4✔
662
                        // don't use port zero for non-console localities
4✔
663
                        if (hpx_port == 0 && node != 0)
664
                            hpx_port = HPX_INITIAL_IP_PORT;
665

666
                        // each node gets a unique port
667
                        hpx_port = static_cast<std::uint16_t>(hpx_port + node);
12✔
668
                        rtcfg_.mode_ = hpx::runtime_mode::worker;
12✔
669

670
                        // do not execute any explicit hpx_main except if asked
671
                        // otherwise
672
                        if (!vm.count("hpx:run-hpx-main") &&
673
                            !cfgmap.get_value<int>("hpx.run_hpx_main", 0))
674
                        {
675
                            util::detail::reset_function(hpx_main_f_);
676
                        }
677
                    }
678
                }
128✔
679

680
                // store node number in configuration, don't do that if we're on
64✔
681
                // a worker and the node number is zero
128✔
682
                if (!vm.count("hpx:worker") || node != 0)
683
                {
684
                    ini_config.emplace_back(
685
                        "hpx.locality!=" + std::to_string(node));
128✔
686
                }
687
            }
×
688

×
689
            if (vm.count("hpx:hpx"))
690
            {
691
                if (!util::split_ip_address(
692
                        vm["hpx:hpx"].as<std::string>(), hpx_host, hpx_port))
693
                {
694
                    std::cerr
695
                        << "hpx::init: command line warning: illegal port "
696
                           "number given, using default value instead."
697
                        << std::endl;
128✔
698
                }
64✔
699
            }
700

701
            if ((vm.count("hpx:connect") ||
×
702
                    rtcfg_.mode_ == hpx::runtime_mode::connect) &&
703
                hpx_host == "127.0.0.1")
704
            {
192✔
705
                hpx_host = hpx::util::resolve_public_ip_address();
706
            }
707

708
            ini_config.emplace_back("hpx.node!=" + std::to_string(node));
709
        }
128✔
710
#endif
64✔
711

712
        // handle number of cores and threads
64✔
713
        num_threads_ = detail::handle_num_threads(cfgmap, rtcfg_, vm, env,
714
            using_nodelist, initial, use_process_mask_);
64✔
715

716
        num_cores_ = hpx::local::detail::handle_num_cores_default(cfgmap, vm,
717
            num_threads_,
64✔
718
            detail::get_number_of_default_cores(env, use_process_mask_));
64✔
719

128✔
720
        // Set number of cores and OS threads in configuration.
721
        ini_config.emplace_back(
722
            "hpx.os_threads=" + std::to_string(num_threads_));
64✔
723
        ini_config.emplace_back("hpx.cores=" + std::to_string(num_cores_));
724

725
        // handle high-priority threads
128✔
726
        handle_high_priority_threads(vm, ini_config);
128✔
727

728
#if defined(HPX_HAVE_PARCELPORT_TCP)
729
        // map host names to ip addresses, if requested
64✔
730
        if (have_tcp)
336✔
731
        {
732
            hpx_host = mapnames.map(hpx_host, hpx_port);
733
            agas_host = mapnames.map(agas_host, agas_port);
734
        }
735
#endif
736

737
        // sanity checks
52✔
738
        if (rtcfg_.mode_ != hpx::runtime_mode::local && num_localities_ == 1 &&
739
            !vm.count("hpx:agas") && !vm.count("hpx:node"))
740
        {
64✔
741
            // We assume we have to run the AGAS server if the number of
742
            // localities to run on is not specified (or is '1') and no
743
            // additional option (--hpx:agas or --hpx:node) has been specified.
64✔
744
            // That simplifies running small standalone applications on one
745
            // locality.
746
            run_agas_server = rtcfg_.mode_ != runtime_mode::connect;
747
        }
8✔
748

749
        if (rtcfg_.mode_ != hpx::runtime_mode::local)
56✔
750
        {
751
#if defined(HPX_HAVE_NETWORKING)
752
            if (hpx_host == agas_host && hpx_port == agas_port)
753
            {
754
                // we assume that we need to run the agas server if the user
52✔
755
                // asked for the same network addresses for HPX and AGAS
756
                run_agas_server = rtcfg_.mode_ != runtime_mode::connect;
757
            }
×
758
            else if (run_agas_server)
759
            {
760
                // otherwise, if the user instructed us to run the AGAS server,
4✔
761
                // we set the AGAS network address to the same value as the HPX
762
                // network address
763
                if (agas_host == HPX_INITIAL_IP_ADDRESS)
764
                {
4✔
765
                    agas_host = hpx_host;
766
                    agas_port = hpx_port;
767
                }
768
            }
769
            else if (env.found_batch_environment())
12✔
770
            {
12✔
771
                // in batch mode, if the network addresses are different, and we
772
                // should not run the AGAS server we assume to be in worker mode
773
                rtcfg_.mode_ = hpx::runtime_mode::worker;
774

775
                // do not execute any explicit hpx_main except if asked
776
                // otherwise
777
                if (!vm.count("hpx:run-hpx-main") &&
778
                    !cfgmap.get_value<int>("hpx.run_hpx_main", 0))
779
                {
64✔
780
                    util::detail::reset_function(hpx_main_f_);
64✔
781
                }
64✔
782
            }
64✔
783

64✔
784
            // write HPX and AGAS network parameters to the proper ini-file
64✔
785
            // entries
786
            ini_config.emplace_back("hpx.parcel.address=" + hpx_host);
64✔
787
            ini_config.emplace_back(
788
                "hpx.parcel.port=" + std::to_string(hpx_port));
60✔
789
            ini_config.emplace_back("hpx.agas.address=" + agas_host);
790
            ini_config.emplace_back(
791
                "hpx.agas.port=" + std::to_string(agas_port));
792

60✔
793
            if (run_agas_server)
794
            {
795
                ini_config.emplace_back("hpx.agas.service_mode=bootstrap");
796
            }
×
797

798
            // we can't run the AGAS server while connecting
799
            if (run_agas_server && rtcfg_.mode_ == runtime_mode::connect)
800
            {
801
                throw hpx::detail::command_line_error(
802
                    "Command line option error: can't run AGAS server"
803
                    "while connecting to a running application.");
64✔
804
            }
805
#else
64✔
806
            ini_config.emplace_back("hpx.agas.service_mode=bootstrap");
807
#endif
808
        }
809

64✔
810
        enable_logging_settings(vm, ini_config);
64✔
811

812
        // handle command line arguments after logging defaults
813
        if (vm.count("hpx:ini"))
814
        {
815
            std::vector<std::string> cfg =
128✔
816
                vm["hpx:ini"].as<std::vector<std::string>>();
64✔
817
            std::copy(cfg.begin(), cfg.end(), std::back_inserter(ini_config));
818
            cfgmap.add(cfg);
819
        }
128✔
820

821
        if (rtcfg_.mode_ != hpx::runtime_mode::local)
822
        {
×
823
            // Set number of localities in configuration (do it everywhere, even
824
            // if this information is only used by the AGAS server).
×
825
            ini_config.emplace_back(
826
                "hpx.localities!=" + std::to_string(num_localities_));
×
827

828
            // FIXME: AGAS V2: if a locality is supposed to run the AGAS
×
829
            //        service only and requests to use 'priority_local' as the
×
830
            //        scheduler, switch to the 'local' scheduler instead.
831
            ini_config.emplace_back(std::string("hpx.runtime_mode=") +
×
832
                get_runtime_mode_name(rtcfg_.mode_));
833

×
834
            bool noshutdown_evaluate = false;
835
            if (vm.count("hpx:print-counter-at"))
×
836
            {
837
                std::vector<std::string> print_counters_at =
×
838
                    vm["hpx:print-counter-at"].as<std::vector<std::string>>();
839

×
840
                for (std::string const& s : print_counters_at)
841
                {
842
                    if (0 == std::string("startup").find(s))
×
843
                    {
844
                        ini_config.emplace_back("hpx.print_counter.startup!=1");
845
                        continue;
×
846
                    }
847
                    if (0 == std::string("shutdown").find(s))
848
                    {
849
                        ini_config.emplace_back(
×
850
                            "hpx.print_counter.shutdown!=1");
851
                        continue;
×
852
                    }
853
                    if (0 == std::string("noshutdown").find(s))
854
                    {
128✔
855
                        ini_config.emplace_back(
192✔
856
                            "hpx.print_counter.shutdown!=0");
857
                        noshutdown_evaluate = true;
×
858
                        continue;
×
859
                    }
×
860

×
861
                    throw hpx::detail::command_line_error(hpx::util::format(
862
                        "Invalid argument for option --hpx:print-counter-at: "
863
                        "'{1}', allowed values: 'startup', 'shutdown' "
864
                        "(default), 'noshutdown'",
64✔
865
                        s));
866
                }
×
867
            }
868

869
            // if any counters have to be evaluated, always print at the end
64✔
870
            if (vm.count("hpx:print-counter") ||
128✔
871
                vm.count("hpx:print-counter-reset"))
872
            {
873
                if (!noshutdown_evaluate)
64✔
874
                    ini_config.emplace_back("hpx.print_counter.shutdown!=1");
875
                if (vm.count("hpx:reset-counters"))
876
                    ini_config.emplace_back("hpx.print_counter.reset!=1");
877
            }
64✔
878
        }
879

880
        if (debug_clp)
128✔
881
        {
882
            hpx::local::detail::print_config(ini_config);
×
883
        }
×
884

×
885
        return true;
×
886
    }
×
887

×
888
    ///////////////////////////////////////////////////////////////////////////
×
889
    void command_line_handling::enable_logging_settings(
×
890
        hpx::program_options::variables_map& vm,
891
        std::vector<std::string>& ini_config)
892
    {
128✔
893
        base_type::enable_logging_settings(vm, ini_config);
894

×
895
#if defined(HPX_HAVE_LOGGING) && defined(HPX_LOGGING_HAVE_SEPARATE_DESTINATIONS)
×
896
        if (vm.count("hpx:debug-agas-log"))
×
897
        {
×
898
            ini_config.emplace_back("hpx.logging.console.agas.destination=" +
×
899
                hpx::local::detail::convert_to_log_file(
×
900
                    vm["hpx:debug-agas-log"].as<std::string>()));
×
901
            ini_config.emplace_back("hpx.logging.agas.destination=" +
×
902
                hpx::local::detail::convert_to_log_file(
903
                    vm["hpx:debug-agas-log"].as<std::string>()));
904
            ini_config.emplace_back("hpx.logging.console.agas.level=5");
905
            ini_config.emplace_back("hpx.logging.agas.level=5");
906
        }
907

908
        if (vm.count("hpx:debug-parcel-log"))
909
        {
910
            ini_config.emplace_back("hpx.logging.console.parcel.destination=" +
911
                hpx::local::detail::convert_to_log_file(
912
                    vm["hpx:debug-parcel-log"].as<std::string>()));
913
            ini_config.emplace_back("hpx.logging.parcel.destination=" +
64✔
914
                hpx::local::detail::convert_to_log_file(
915
                    vm["hpx:debug-parcel-log"].as<std::string>()));
916
            ini_config.emplace_back("hpx.logging.console.parcel.level=5");
32✔
917
            ini_config.emplace_back("hpx.logging.parcel.level=5");
918
        }
919
#else
920
        if (vm.count("hpx:debug-agas-log") || vm.count("hpx:debug-parcel-log"))
921
        {
922
            throw hpx::detail::command_line_error(
923
                "Command line option error: can't enable logging while it was "
32✔
924
                "disabled at configuration time. Please re-configure HPX using "
925
                "the options -DHPX_WITH_LOGGING=On and "
926
                "-DHPX_LOGGING_WITH_SEPARATE_DESTINATIONS=On.");
32✔
927
        }
928
#endif
32✔
929
    }
930

931
    ///////////////////////////////////////////////////////////////////////////
73✔
932
    int command_line_handling::call(
82✔
933
        hpx::program_options::options_description const& desc_cmdline, int argc,
934
        char** argv,
935
        std::vector<std::shared_ptr<components::component_registry_base>>&
936
            component_registries)
937
    {
64✔
938
        // set the flag signaling that command line parsing has been done
939
        cmd_line_parsed_ = true;
940

941
        // separate command line arguments from configuration settings
942
        std::vector<std::string> args = preprocess_config_settings(argc, argv);
943

944
        util::manage_config cfgmap(ini_config_);
945

32✔
946
        // insert the pre-configured ini settings before loading modules
947
        for (std::string const& e : ini_config_)
64✔
948
            rtcfg_.parse("<user supplied config>", e, true, false);
32✔
949

950
        // support re-throwing command line exceptions for testing purposes
951
        util::commandline_error_mode error_mode =
952
            util::commandline_error_mode::allow_unregistered;
953
        if (cfgmap.get_value("hpx.commandline.rethrow_errors", 0) != 0)
954
        {
955
            error_mode |= util::commandline_error_mode::rethrow_on_error;
956
        }
957

958
        // The cfg registry may hold command line options to prepend to the
32✔
959
        // real command line.
64✔
960
        std::string prepend_command_line =
961
            rtcfg_.get_entry("hpx.commandline.prepend_options");
962

963
        args = hpx::local::detail::prepend_options(
964
            HPX_MOVE(args), HPX_MOVE(prepend_command_line));
965

966
        // Initial analysis of the command line options. This is preliminary as
967
        // it will not take into account any aliases as defined in any of the
32✔
968
        // runtime configuration files.
32✔
969
        {
970
            // Boost V1.47 and before do not properly reset a variables_map when
971
            // calling vm.clear(). We work around that problems by creating a
972
            // separate instance just for the preliminary command line handling.
973
            error_mode |= util::commandline_error_mode::ignore_aliases;
32✔
974
            hpx::program_options::variables_map prevm;
32✔
975
            if (!util::parse_commandline(rtcfg_, desc_cmdline, argv[0], args,
976
                    prevm, static_cast<std::size_t>(-1), error_mode,
977
                    rtcfg_.mode_))
978
            {
979
                return -1;
32✔
980
            }
981

28✔
982
            // handle all --hpx:foo options, determine node
28✔
983
            std::vector<std::string> ini_config;    // discard
28✔
984
            if (!handle_arguments(cfgmap, prevm, ini_config, node_, true))
28✔
985
            {
986
                return -2;
987
            }
988

989
            reconfigure(cfgmap, prevm);
990
        }
991

32✔
992
#if (defined(HPX_HAVE_NETWORKING) && defined(HPX_HAVE_PARCELPORT_MPI)) ||      \
993
    defined(HPX_HAVE_MODULE_MPI_BASE)
2✔
994
        // getting localities from MPI environment (support mpirun)
2✔
995
        if (util::mpi_environment::check_mpi_environment(rtcfg_))
2✔
996
        {
2✔
997
            util::mpi_environment::init(&argc, &argv, rtcfg_);
998
            num_localities_ =
999
                static_cast<std::size_t>(util::mpi_environment::size());
1000
            node_ = static_cast<std::size_t>(util::mpi_environment::rank());
1001
        }
1002
#endif
1003
#if (defined(HPX_HAVE_NETWORKING) && defined(HPX_HAVE_PARCELPORT_LCI)) ||      \
32✔
1004
    defined(HPX_HAVE_MODULE_LCI_BASE)
1005
        // better to put LCI init after MPI init, since LCI will also
1006
        // initialize MPI if MPI is not already initialized.
1007
        if (util::lci_environment::check_lci_environment(rtcfg_))
1008
        {
1009
            util::lci_environment::init(&argc, &argv, rtcfg_);
32✔
1010
            num_localities_ =
×
1011
                static_cast<std::size_t>(util::lci_environment::size());
1012
            node_ = static_cast<std::size_t>(util::lci_environment::rank());
32✔
1013
        }
64✔
1014
#endif
1015
#if (defined(HPX_HAVE_NETWORKING) && defined(HPX_HAVE_PARCELPORT_GASNET)) ||   \
32✔
1016
    defined(HPX_HAVE_MODULE_GASNET_BASE)
1017
        // better to put GASNET init after MPI init, since GASNET will also
1018
        // initialize MPI if MPI is not already initialized.
1019
        if (util::gasnet_environment::check_gasnet_environment(rtcfg_))
1020
        {
32✔
1021
            util::gasnet_environment::init(&argc, &argv, rtcfg_);
32✔
1022
            num_localities_ =
1023
                static_cast<std::size_t>(util::gasnet_environment::size());
1024
            node_ = static_cast<std::size_t>(util::gasnet_environment::rank());
64✔
1025
        }
1026
#endif
1027

1028
        // load plugin modules (after first pass of command line handling, so
1029
        // that settings given on command line could propagate to modules)
1030
        std::vector<std::shared_ptr<plugins::plugin_registry_base>>
1031
            plugin_registries = rtcfg_.load_modules(component_registries);
32✔
1032

1033
        // Re-run program option analysis, ini settings (such as aliases) will
1034
        // be considered now.
32✔
1035

1036
        // minimally assume one locality and this is the console
1037
        if (node_ == static_cast<std::size_t>(-1))
1038
            node_ = 0;
1039

32✔
1040
        for (std::shared_ptr<plugins::plugin_registry_base>& reg :
1041
            plugin_registries)
64✔
1042
        {
1043
            reg->init(&argc, &argv, rtcfg_);
1044
        }
1045

1046
        // Now reparse the command line using the node number (if given). This
1047
        // will additionally detect any --hpx:N:foo options.
1048
        hpx::program_options::options_description help;
1049
        std::vector<std::string> unregistered_options;
1050

1051
        error_mode |= util::commandline_error_mode::report_missing_config_file;
1052
        if (!util::parse_commandline(rtcfg_, desc_cmdline, argv[0], args, vm_,
1053
                node_, error_mode, rtcfg_.mode_, &help, &unregistered_options))
1054
        {
1055
            return -1;
1056
        }
1057

1058
        // break into debugger, if requested
1059
        handle_attach_debugger();
1060

1061
        // handle all --hpx:foo and --hpx:*:foo options
1062
        if (!handle_arguments(cfgmap, vm_, ini_config_, node_))
1063
        {
1064
            return -2;
1065
        }
1066

1067
        return finalize_commandline_handling(
1068
            argc, argv, help, unregistered_options);
1069
    }
1070
}    // namespace hpx::util
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