• 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

56.89
/libs/full/command_line_handling/src/command_line_handling.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/command_line_handling.hpp>
10
#include <hpx/command_line_handling/parse_command_line.hpp>
11
#include <hpx/functional/detail/reset_function.hpp>
12
#include <hpx/modules/asio.hpp>
13
#include <hpx/modules/batch_environments.hpp>
14
#include <hpx/modules/debugging.hpp>
15
#include <hpx/modules/format.hpp>
16
#if defined(HPX_HAVE_MODULE_MPI_BASE)
17
#include <hpx/modules/mpi_base.hpp>
18
#endif
19
#if defined(HPX_HAVE_MODULE_LCI_BASE)
20
#include <hpx/modules/lci_base.hpp>
21
#endif
22
#include <hpx/modules/program_options.hpp>
23
#include <hpx/modules/runtime_configuration.hpp>
24
#include <hpx/modules/topology.hpp>
25
#include <hpx/modules/util.hpp>
26
#include <hpx/preprocessor/stringize.hpp>
27
#include <hpx/util/from_string.hpp>
28
#include <hpx/version.hpp>
29

30
#include <algorithm>
31
#include <cstddef>
32
#include <cstdint>
33
#include <fstream>
34
#include <iomanip>
35
#include <iostream>
36
#include <iterator>
37
#include <memory>
38
#include <sstream>
39
#include <string>
40
#include <utility>
41
#include <vector>
42

43
namespace hpx { namespace util {
44

45
    namespace detail {
46

47
        ///////////////////////////////////////////////////////////////////////
48
        std::string runtime_configuration_string(
×
49
            util::command_line_handling const& cfg)
50
        {
51
            std::ostringstream strm;
×
52

53
            // runtime mode
54
            strm << "  {mode}: " << get_runtime_mode_name(cfg.rtcfg_.mode_)
×
55
                 << "\n";
×
56

57
            if (cfg.num_localities_ != 1)
×
58
                strm << "  {localities}: " << cfg.num_localities_ << "\n";
×
59

60
            strm << hpx::local::detail::runtime_configuration_string(cfg);
×
61

62
            return strm.str();
×
63
        }
×
64

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

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

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

106
        ///////////////////////////////////////////////////////////////////////
107
        std::size_t handle_num_localities(util::manage_config& cfgmap,
1,196✔
108
            hpx::program_options::variables_map& vm,
109
            util::batch_environment& env, bool using_nodelist,
110
            std::size_t num_localities, bool initial)
111
        {
112
            std::size_t batch_localities = env.retrieve_number_of_localities();
1,196✔
113
            if (num_localities == 1 && batch_localities != std::size_t(-1))
1,196✔
114
            {
115
                std::size_t cfg_num_localities = cfgmap.get_value<std::size_t>(
×
116
                    "hpx.localities", batch_localities);
×
117
                if (cfg_num_localities > 1)
×
118
                    num_localities = cfg_num_localities;
×
119
            }
×
120

121
            if (!initial && env.found_batch_environment() && using_nodelist &&
1,196✔
122
                (batch_localities != num_localities) && (num_localities != 1))
×
123
            {
124
                detail::report_locality_warning_batch(
×
125
                    env.get_batch_name(), batch_localities, num_localities);
×
126
            }
×
127

128
            if (vm.count("hpx:localities"))
1,196✔
129
            {
130
                std::size_t localities = vm["hpx:localities"].as<std::size_t>();
562✔
131

132
                if (localities == 0)
562✔
133
                {
134
                    throw hpx::detail::command_line_error(
×
135
                        "Number of --hpx:localities must be greater than 0");
136
                }
137

138
                if (!initial && env.found_batch_environment() &&
562✔
139
                    using_nodelist && (localities != num_localities) &&
×
140
                    (num_localities != 1))
×
141
                {
142
                    detail::report_locality_warning(
×
143
                        env.get_batch_name(), localities, num_localities);
×
144
                }
×
145
                num_localities = localities;
562✔
146
            }
562✔
147

148
#if !defined(HPX_HAVE_NETWORKING)
149
            if (num_localities != 1)
150
            {
151
                throw hpx::detail::command_line_error(
152
                    "Number of --hpx:localities must be equal to 1, please "
153
                    "enable networking to run distributed HPX applications "
154
                    "(use -DHPX_WITH_NETWORKING=On during configuration)");
155
            }
156
#endif
157
            return num_localities;
1,196✔
158
        }
×
159

160
        ///////////////////////////////////////////////////////////////////////
161
        std::size_t get_number_of_default_cores(
2,392✔
162
            util::batch_environment& env, bool use_process_mask)
163
        {
164
            std::size_t num_cores =
2,392✔
165
                hpx::local::detail::get_number_of_default_cores(
2,392✔
166
                    use_process_mask);
2,392✔
167
            if (use_process_mask)
2,392✔
168
            {
169
                return num_cores;
×
170
            }
171

172
            std::size_t batch_threads = env.retrieve_number_of_threads();
2,392✔
173
            if (batch_threads == std::size_t(-1))
2,392✔
174
            {
175
                return num_cores;
2,392✔
176
            }
177

178
            // assuming we assign the first N cores ...
179
            threads::topology& top = threads::create_topology();
×
180
            std::size_t core = 0;
×
181
            for (/**/; core < num_cores; ++core)
×
182
            {
183
                batch_threads -= top.get_number_of_core_pus(core);
×
184
                if (batch_threads == 0)
×
185
                    break;
×
186
            }
×
187
            return core + 1;
×
188
        }
2,392✔
189

190
        ///////////////////////////////////////////////////////////////////////
191
        std::size_t handle_num_threads(util::manage_config& cfgmap,
1,196✔
192
            util::runtime_configuration const& rtcfg,
193
            hpx::program_options::variables_map& vm,
194
            util::batch_environment& env, bool using_nodelist, bool initial,
195
            bool use_process_mask)
196
        {
197
            // If using the process mask we override "cores" and "all" options
198
            // but keep explicit numeric values.
199
            std::size_t const init_threads =
1,196✔
200
                hpx::local::detail::get_number_of_default_threads(
1,196✔
201
                    use_process_mask);
1,196✔
202
            std::size_t const init_cores =
1,196✔
203
                detail::get_number_of_default_cores(env, use_process_mask);
1,196✔
204
            std::size_t const batch_threads = env.retrieve_number_of_threads();
1,196✔
205

206
            std::string threads_str =
207
                cfgmap.get_value<std::string>("hpx.os_threads",
2,392✔
208
                    rtcfg.get_entry(
2,392✔
209
                        "hpx.os_threads", std::to_string(init_threads)));
1,196✔
210

211
            std::size_t threads = 0;
1,196✔
212
            if ("cores" == threads_str)
1,196✔
213
            {
214
                threads = init_cores;
1,154✔
215
                if (batch_threads != std::size_t(-1))
1,154✔
216
                {
217
                    threads = batch_threads;
×
218
                }
×
219
            }
1,154✔
220
            else if ("all" == threads_str)
42✔
221
            {
222
                threads = init_threads;
34✔
223
                if (batch_threads != std::size_t(-1))
34✔
224
                {
225
                    threads = batch_threads;
×
226
                }
×
227
            }
34✔
228
            else if (batch_threads != std::size_t(-1))
8✔
229
            {
230
                threads = batch_threads;
×
231
            }
×
232
            else
233
            {
234
                threads = cfgmap.get_value<std::size_t>("hpx.os_threads",
16✔
235
                    hpx::util::from_string<std::size_t>(threads_str));
8✔
236
            }
237

238
            if (vm.count("hpx:threads"))
1,196✔
239
            {
240
                threads_str = vm["hpx:threads"].as<std::string>();
1,168✔
241
                if ("all" == threads_str)
1,168✔
242
                {
243
                    threads = init_threads;
2✔
244
                    if (batch_threads != std::size_t(-1))
2✔
245
                    {
246
                        threads = batch_threads;
×
247
                    }
×
248
                }
2✔
249
                else if ("cores" == threads_str)
1,166✔
250
                {
251
                    threads = init_cores;
×
252
                    if (batch_threads != std::size_t(-1))
×
253
                    {
254
                        threads = batch_threads;
×
255
                    }
×
256
                }
×
257
                else
258
                {
259
                    threads = hpx::util::from_string<std::size_t>(threads_str);
1,166✔
260
                }
261

262
                if (threads == 0)
1,168✔
263
                {
264
                    throw hpx::detail::command_line_error(
×
265
                        "Number of --hpx:threads must be greater than 0");
266
                }
267

268
#if defined(HPX_HAVE_MAX_CPU_COUNT)
269
                if (threads > HPX_HAVE_MAX_CPU_COUNT)
270
                {
271
                    // clang-format off
272
                    throw hpx::detail::command_line_error("Requested more than "
273
                        HPX_PP_STRINGIZE(HPX_HAVE_MAX_CPU_COUNT)" --hpx:threads "
274
                        "to use for this application, use the option "
275
                        "-DHPX_WITH_MAX_CPU_COUNT=<N> when configuring HPX.");
276
                    // clang-format on
277
                }
278
#endif
279
            }
1,168✔
280

281
            // make sure minimal requested number of threads is observed
282
            std::size_t min_os_threads = cfgmap.get_value<std::size_t>(
1,196✔
283
                "hpx.force_min_os_threads", threads);
1,196✔
284

285
            if (min_os_threads == 0)
1,196✔
286
            {
287
                throw hpx::detail::command_line_error(
×
288
                    "Number of hpx.force_min_os_threads must be greater than "
289
                    "0");
290
            }
291

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

305
            threads = (std::max)(threads, min_os_threads);
1,196✔
306

307
            if (!initial && env.found_batch_environment() && using_nodelist &&
1,196✔
308
                (threads > batch_threads))
×
309
            {
310
                detail::report_thread_warning(
×
311
                    env.get_batch_name(), threads, batch_threads);
×
312
            }
×
313
            return threads;
1,196✔
314
        }
1,196✔
315

316
        ///////////////////////////////////////////////////////////////////////
317
#if !defined(HPX_HAVE_NETWORKING)
318
        void check_networking_option(
319
            hpx::program_options::variables_map& vm, char const* option)
320
        {
321
            if (vm.count(option) != 0)
322
            {
323
                throw hpx::detail::command_line_error(
324
                    std::string("Invalid command line option: '--") + option +
325
                    "', networking was disabled at configuration time. "
326
                    "Reconfigure HPX using -DHPX_WITH_NETWORKING=On.");
327
            }
328
        }
329
#endif
330

331
        void check_networking_options(
1,196✔
332
            [[maybe_unused]] hpx::program_options::variables_map& vm)
333
        {
334
#if !defined(HPX_HAVE_NETWORKING)
335
            check_networking_option(vm, "hpx:agas");
336
            check_networking_option(vm, "hpx:run-agas-server-only");
337
            check_networking_option(vm, "hpx:hpx");
338
            check_networking_option(vm, "hpx:nodefile");
339
            check_networking_option(vm, "hpx:nodes");
340
            check_networking_option(vm, "hpx:endnodes");
341
            check_networking_option(vm, "hpx:ifsuffix");
342
            check_networking_option(vm, "hpx:ifprefix");
343
            check_networking_option(vm, "hpx:iftransform");
344
            check_networking_option(vm, "hpx:localities");
345
            check_networking_option(vm, "hpx:node");
346
            check_networking_option(vm, "hpx:expect-connecting-localities");
347
#endif
348
        }
1,196✔
349
    }    // namespace detail
350

351
    ///////////////////////////////////////////////////////////////////////////
352
    command_line_handling::command_line_handling(runtime_configuration rtcfg,
598✔
353
        std::vector<std::string> ini_config,
354
        hpx::function<int(hpx::program_options::variables_map& vm)> hpx_main_f)
355
      : base_type(HPX_MOVE(rtcfg), HPX_MOVE(ini_config), HPX_MOVE(hpx_main_f))
598✔
356
      , node_(std::size_t(-1))
598✔
357
      , num_localities_(1)
598✔
358
    {
598✔
359
    }
598✔
360

361
    bool command_line_handling::handle_arguments(util::manage_config& cfgmap,
1,196✔
362
        hpx::program_options::variables_map& vm,
363
        std::vector<std::string>& ini_config, std::size_t& node, bool initial)
364
    {
365
        // handle local options
366
        base_type::handle_arguments(cfgmap, vm, ini_config);
1,196✔
367

368
        // verify that no networking options were used if networking was
369
        // disabled
370
        detail::check_networking_options(vm);
1,196✔
371

372
        bool debug_clp = node != std::size_t(-1) && vm.count("hpx:debug-clp");
1,196✔
373

374
        // create host name mapping
375
        util::map_hostnames mapnames(debug_clp);
1,196✔
376

377
        if (vm.count("hpx:ifsuffix"))
1,196✔
378
            mapnames.use_suffix(vm["hpx:ifsuffix"].as<std::string>());
×
379
        if (vm.count("hpx:ifprefix"))
1,196✔
380
            mapnames.use_prefix(vm["hpx:ifprefix"].as<std::string>());
×
381
        mapnames.force_ipv4(vm.count("hpx:force_ipv4") != 0);
1,196✔
382

383
        // The AGAS host name and port number are pre-initialized from
384
        //the command line
385
        std::string agas_host = cfgmap.get_value<std::string>(
2,392✔
386
            "hpx.agas.address", rtcfg_.get_entry("hpx.agas.address", ""));
1,196✔
387
        std::uint16_t agas_port =
1,196✔
388
            cfgmap.get_value<std::uint16_t>("hpx.agas.port",
2,392✔
389
                hpx::util::from_string<std::uint16_t>(
1,196✔
390
                    rtcfg_.get_entry("hpx.agas.port", HPX_INITIAL_IP_PORT)));
1,196✔
391

392
        if (vm.count("hpx:agas"))
1,196✔
393
        {
394
            if (!util::split_ip_address(
×
395
                    vm["hpx:agas"].as<std::string>(), agas_host, agas_port))
×
396
            {
397
                std::cerr << "hpx::init: command line warning: illegal port "
×
398
                             "number given, using default value instead."
399
                          << std::endl;
×
400
            }
×
401
        }
×
402

403
        // Check command line arguments.
404
        if (vm.count("hpx:iftransform"))
1,196✔
405
        {
406
            util::sed_transform iftransform(
×
407
                vm["hpx:iftransform"].as<std::string>());
×
408

409
            // Check for parsing failures
410
            if (!iftransform)
×
411
            {
412
                throw hpx::detail::command_line_error(hpx::util::format(
×
413
                    "Could not parse --hpx:iftransform argument '{1}'",
×
414
                    vm["hpx:iftransform"].as<std::string>()));
×
415
            }
416

417
            typedef util::map_hostnames::transform_function_type
418
                transform_function_type;
419
            mapnames.use_transform(transform_function_type(iftransform));
×
420
        }
×
421

422
        bool using_nodelist = false;
1,196✔
423

424
        std::vector<std::string> nodelist;
1,196✔
425

426
#if defined(HPX_HAVE_NETWORKING)
427
        if (vm.count("hpx:nodefile"))
1,196✔
428
        {
429
            if (vm.count("hpx:nodes"))
×
430
            {
431
                throw hpx::detail::command_line_error(
×
432
                    "Ambiguous command line options. Do not specify more than "
433
                    "one of the --hpx:nodefile and --hpx:nodes options at the "
434
                    "same time.");
435
            }
436
            std::string node_file = vm["hpx:nodefile"].as<std::string>();
×
437
            ini_config.emplace_back("hpx.nodefile!=" + node_file);
×
438
            std::ifstream ifs(node_file.c_str());
×
439
            if (ifs.is_open())
×
440
            {
441
                if (debug_clp)
×
442
                    std::cerr << "opened: " << node_file << std::endl;
×
443
                std::string line;
×
444
                while (std::getline(ifs, line))
×
445
                {
446
                    if (!line.empty())
×
447
                    {
448
                        nodelist.push_back(line);
×
449
                    }
×
450
                }
451
            }
×
452
            else
453
            {
454
                if (debug_clp)
×
455
                    std::cerr << "failed opening: " << node_file << std::endl;
×
456

457
                // raise hard error if node file could not be opened
458
                throw hpx::detail::command_line_error(hpx::util::format(
×
459
                    "Could not open nodefile: '{}'", node_file));
×
460
            }
461
        }
×
462
        else if (vm.count("hpx:nodes"))
1,196✔
463
        {
464
            nodelist = vm["hpx:nodes"].as<std::vector<std::string>>();
×
465
        }
×
466
#endif
467
        bool enable_batch_env =
1,196✔
468
            ((cfgmap.get_value<std::size_t>("hpx.ignore_batch_env", 0) +
3,586✔
469
                 vm.count("hpx:ignore-batch-env")) == 0) &&
1,196✔
470
            !use_process_mask_;
1,194✔
471

472
#if defined(HPX_HAVE_MODULE_MPI_BASE)
473
        bool have_mpi = util::mpi_environment::check_mpi_environment(rtcfg_);
474
#else
475
        bool have_mpi = false;
1,196✔
476
#endif
477

478
        util::batch_environment env(
1,196✔
479
            nodelist, have_mpi, debug_clp, enable_batch_env);
1,196✔
480

481
#if defined(HPX_HAVE_NETWORKING)
482
        if (!nodelist.empty())
1,196✔
483
        {
484
            using_nodelist = true;
×
485
            ini_config.emplace_back(
×
486
                "hpx.nodes!=" + env.init_from_nodelist(nodelist, agas_host));
×
487
        }
×
488

489
        // let the batch environment decide about the AGAS host
490
        agas_host = env.agas_host_name(
1,196✔
491
            agas_host.empty() ? HPX_INITIAL_IP_ADDRESS : agas_host);
1,196✔
492
#endif
493

494
        bool run_agas_server = false;
1,196✔
495
        std::string hpx_host;
1,196✔
496
        std::uint16_t hpx_port = 0;
1,196✔
497

498
#if defined(HPX_HAVE_NETWORKING)
499
        bool expect_connections = false;
1,196✔
500
        std::uint16_t initial_hpx_port = 0;
1,196✔
501

502
        // handling number of localities, those might have already been
503
        // initialized from MPI environment
504
        num_localities_ = detail::handle_num_localities(
1,196✔
505
            cfgmap, vm, env, using_nodelist, num_localities_, initial);
1,196✔
506

507
        // Determine our network port, use arbitrary port if running on one
508
        // locality.
509
        hpx_host = cfgmap.get_value<std::string>("hpx.parcel.address",
2,392✔
510
            env.host_name(rtcfg_.get_entry(
1,196✔
511
                "hpx.parcel.address", HPX_INITIAL_IP_ADDRESS)));
1,196✔
512

513
        // we expect dynamic connections if:
514
        //  - --hpx:expect-connecting-localities or
515
        //  - hpx.expect_connecting_localities=1 is given, or
516
        //  - num_localities > 1
517
        expect_connections =
1,196✔
518
            cfgmap.get_value<int>("hpx.expect_connecting_localities",
1,196✔
519
                num_localities_ > 1 ? 1 : 0) != 0;
1,196✔
520

521
        if (vm.count("hpx:expect-connecting-localities"))
1,196✔
522
            expect_connections = true;
2✔
523

524
        ini_config.emplace_back(
2,392✔
525
            std::string("hpx.expect_connecting_localities=") +
2,392✔
526
            (expect_connections ? "1" : "0"));
1,196✔
527

528
        if (num_localities_ != 1 || expect_connections)
1,196✔
529
        {
530
            initial_hpx_port = hpx::util::from_string<std::uint16_t>(
568✔
531
                rtcfg_.get_entry("hpx.parcel.port", HPX_INITIAL_IP_PORT));
568✔
532
        }
568✔
533

534
        hpx_port = cfgmap.get_value<std::uint16_t>(
1,196✔
535
            "hpx.parcel.port", initial_hpx_port);
1,196✔
536

537
        run_agas_server = vm.count("hpx:run-agas-server") != 0;
1,196✔
538
        if (node == std::size_t(-1))
1,196✔
539
            node = env.retrieve_node_number();
598✔
540
#else
541
        num_localities_ = 1;
542
        node = 0;
543
#endif
544

545
        // If the user has not specified an explicit runtime mode we retrieve it
546
        // from the command line.
547
        if (hpx::runtime_mode::default_ == rtcfg_.mode_)
1,196✔
548
        {
549
#if defined(HPX_HAVE_NETWORKING)
550
            // The default mode is console, i.e. all workers need to be started
551
            // with --worker/-w.
552
            rtcfg_.mode_ = hpx::runtime_mode::console;
592✔
553
            if (vm.count("hpx:local") + vm.count("hpx:console") +
1,776✔
554
                    vm.count("hpx:worker") + vm.count("hpx:connect") >
592✔
555
                1)
556
            {
557
                throw hpx::detail::command_line_error(
×
558
                    "Ambiguous command line options. "
559
                    "Do not specify more than one of --hpx:local, "
560
                    "--hpx:console, --hpx:worker, or --hpx:connect");
561
            }
562

563
            // In these cases we default to executing with an empty
564
            // hpx_main, except if specified otherwise.
565
            if (vm.count("hpx:worker"))
592✔
566
            {
567
                rtcfg_.mode_ = hpx::runtime_mode::worker;
×
568

569
#if !defined(HPX_HAVE_RUN_MAIN_EVERYWHERE)
570
                // do not execute any explicit hpx_main except if asked
571
                // otherwise
572
                if (!vm.count("hpx:run-hpx-main") &&
×
573
                    !cfgmap.get_value<int>("hpx.run_hpx_main", 0))
×
574
                {
575
                    util::detail::reset_function(hpx_main_f_);
×
576
                }
×
577
#endif
578
            }
×
579
            else if (vm.count("hpx:connect"))
592✔
580
            {
581
                rtcfg_.mode_ = hpx::runtime_mode::connect;
×
582
            }
×
583
            else if (vm.count("hpx:local"))
592✔
584
            {
585
                rtcfg_.mode_ = hpx::runtime_mode::local;
×
586
            }
×
587
#elif defined(HPX_HAVE_DISTRIBUTED_RUNTIME)
588
            if (vm.count("hpx:local"))
589
            {
590
                rtcfg_.mode_ = hpx::runtime_mode::local;
591
            }
592
            else
593
            {
594
                rtcfg_.mode_ = hpx::runtime_mode::console;
595
            }
596
#else
597
            rtcfg_.mode_ = hpx::runtime_mode::local;
598
#endif
599
        }
592✔
600

601
#if defined(HPX_HAVE_NETWORKING)
602
        if (rtcfg_.mode_ != hpx::runtime_mode::local)
1,196✔
603
        {
604
            // we initialize certain settings if --node is specified (or data
605
            // has been retrieved from the environment)
606
            if (rtcfg_.mode_ == hpx::runtime_mode::connect)
1,188✔
607
            {
608
                // when connecting we need to select a unique port
609
                hpx_port = cfgmap.get_value<std::uint16_t>("hpx.parcel.port",
4✔
610
                    hpx::util::from_string<std::uint16_t>(rtcfg_.get_entry(
2✔
611
                        "hpx.parcel.port", HPX_CONNECTING_IP_PORT)));
2✔
612

613
#if !defined(HPX_HAVE_RUN_MAIN_EVERYWHERE)
614
                // do not execute any explicit hpx_main except if asked
615
                // otherwise
616
                if (!vm.count("hpx:run-hpx-main") &&
4✔
617
                    !cfgmap.get_value<int>("hpx.run_hpx_main", 0))
2✔
618
                {
619
                    util::detail::reset_function(hpx_main_f_);
×
620
                }
×
621
#endif
622
            }
2✔
623
            else if (node != std::size_t(-1) || vm.count("hpx:node"))
1,186✔
624
            {
625
                // command line overwrites the environment
626
                if (vm.count("hpx:node"))
874✔
627
                {
628
                    if (vm.count("hpx:agas"))
562✔
629
                    {
630
                        throw hpx::detail::command_line_error(
×
631
                            "Command line option --hpx:node "
632
                            "is not compatible with --hpx:agas");
633
                    }
634
                    node = vm["hpx:node"].as<std::size_t>();
562✔
635
                }
562✔
636

637
                if (!vm.count("hpx:worker"))
874✔
638
                {
639
                    if (env.agas_node() == node)
874✔
640
                    {
641
                        // console node, by default runs AGAS
642
                        run_agas_server = true;
592✔
643
                        rtcfg_.mode_ = hpx::runtime_mode::console;
592✔
644
                    }
592✔
645
                    else
646
                    {
647
                        // don't use port zero for non-console localities
648
                        if (hpx_port == 0 && node != 0)
282✔
649
                            hpx_port = HPX_INITIAL_IP_PORT;
×
650

651
                        // each node gets an unique port
652
                        hpx_port = static_cast<std::uint16_t>(hpx_port + node);
282✔
653
                        rtcfg_.mode_ = hpx::runtime_mode::worker;
282✔
654

655
#if !defined(HPX_HAVE_RUN_MAIN_EVERYWHERE)
656
                        // do not execute any explicit hpx_main except if asked
657
                        // otherwise
658
                        if (!vm.count("hpx:run-hpx-main") &&
562✔
659
                            !cfgmap.get_value<int>("hpx.run_hpx_main", 0))
280✔
660
                        {
661
                            util::detail::reset_function(hpx_main_f_);
234✔
662
                        }
234✔
663
#endif
664
                    }
665
                }
874✔
666

667
                // store node number in configuration, don't do that if we're on
668
                // a worker and the node number is zero
669
                if (!vm.count("hpx:worker") || node != 0)
874✔
670
                {
671
                    ini_config.emplace_back(
1,748✔
672
                        "hpx.locality!=" + std::to_string(node));
874✔
673
                }
874✔
674
            }
874✔
675

676
            if (vm.count("hpx:hpx"))
1,188✔
677
            {
678
                if (!util::split_ip_address(
×
679
                        vm["hpx:hpx"].as<std::string>(), hpx_host, hpx_port))
×
680
                {
681
                    std::cerr
682
                        << "hpx::init: command line warning: illegal port "
×
683
                           "number given, using default value instead."
684
                        << std::endl;
×
685
                }
×
686
            }
×
687

688
            if ((vm.count("hpx:connect") ||
2,376✔
689
                    rtcfg_.mode_ == hpx::runtime_mode::connect) &&
1,188✔
690
                hpx_host == "127.0.0.1")
2✔
691
            {
692
                hpx_host = hpx::util::resolve_public_ip_address();
2✔
693
            }
2✔
694

695
            ini_config.emplace_back("hpx.node!=" + std::to_string(node));
1,188✔
696
        }
1,188✔
697
#endif
698

699
        // handle number of cores and threads
700
        num_threads_ = detail::handle_num_threads(cfgmap, rtcfg_, vm, env,
2,392✔
701
            using_nodelist, initial, use_process_mask_);
1,196✔
702

703
        num_cores_ =
1,196✔
704
            hpx::local::detail::handle_num_cores(cfgmap, vm, num_threads_,
1,196✔
705
                detail::get_number_of_default_cores(env, use_process_mask_));
1,196✔
706

707
        // Set number of cores and OS threads in configuration.
708
        ini_config.emplace_back(
2,392✔
709
            "hpx.os_threads=" + std::to_string(num_threads_));
1,196✔
710
        ini_config.emplace_back("hpx.cores=" + std::to_string(num_cores_));
1,196✔
711

712
        // handle high-priority threads
713
        handle_high_priority_threads(vm, ini_config);
1,196✔
714

715
        // map host names to ip addresses, if requested
716
        hpx_host = mapnames.map(hpx_host, hpx_port);
1,196✔
717
        agas_host = mapnames.map(agas_host, agas_port);
1,196✔
718

719
        // sanity checks
720
        if (rtcfg_.mode_ != hpx::runtime_mode::local && num_localities_ == 1 &&
1,822✔
721
            !vm.count("hpx:agas") && !vm.count("hpx:node"))
626✔
722
        {
723
            // We assume we have to run the AGAS server if the number of
724
            // localities to run on is not specified (or is '1') and no
725
            // additional option (--hpx:agas or --hpx:node) has been specified.
726
            // That simplifies running small standalone applications on one
727
            // locality.
728
            run_agas_server = rtcfg_.mode_ != runtime_mode::connect;
626✔
729
        }
626✔
730

731
        if (rtcfg_.mode_ != hpx::runtime_mode::local)
1,196✔
732
        {
733
#if defined(HPX_HAVE_NETWORKING)
734
            if (hpx_host == agas_host && hpx_port == agas_port)
1,188✔
735
            {
736
                // we assume that we need to run the agas server if the user
737
                // asked for the same network addresses for HPX and AGAS
738
                run_agas_server = rtcfg_.mode_ != runtime_mode::connect;
284✔
739
            }
284✔
740
            else if (run_agas_server)
904✔
741
            {
742
                // otherwise, if the user instructed us to run the AGAS server,
743
                // we set the AGAS network address to the same value as the HPX
744
                // network address
745
                if (agas_host == HPX_INITIAL_IP_ADDRESS)
620✔
746
                {
747
                    agas_host = hpx_host;
620✔
748
                    agas_port = hpx_port;
620✔
749
                }
620✔
750
            }
620✔
751
            else if (env.found_batch_environment())
284✔
752
            {
753
                // in batch mode, if the network addresses are different and we
754
                // should not run the AGAS server we assume to be in worker mode
755
                rtcfg_.mode_ = hpx::runtime_mode::worker;
×
756

757
#if !defined(HPX_HAVE_RUN_MAIN_EVERYWHERE)
758
                // do not execute any explicit hpx_main except if asked
759
                // otherwise
760
                if (!vm.count("hpx:run-hpx-main") &&
×
761
                    !cfgmap.get_value<int>("hpx.run_hpx_main", 0))
×
762
                {
763
                    util::detail::reset_function(hpx_main_f_);
×
764
                }
×
765
#endif
766
            }
×
767

768
            // write HPX and AGAS network parameters to the proper ini-file entries
769
            ini_config.emplace_back("hpx.parcel.address=" + hpx_host);
1,188✔
770
            ini_config.emplace_back(
2,376✔
771
                "hpx.parcel.port=" + std::to_string(hpx_port));
1,188✔
772
            ini_config.emplace_back("hpx.agas.address=" + agas_host);
1,188✔
773
            ini_config.emplace_back(
2,376✔
774
                "hpx.agas.port=" + std::to_string(agas_port));
1,188✔
775

776
            if (run_agas_server)
1,188✔
777
            {
778
                ini_config.emplace_back("hpx.agas.service_mode=bootstrap");
904✔
779
            }
904✔
780

781
            // we can't run the AGAS server while connecting
782
            if (run_agas_server && rtcfg_.mode_ == runtime_mode::connect)
1,188✔
783
            {
784
                throw hpx::detail::command_line_error(
×
785
                    "Command line option error: can't run AGAS server"
786
                    "while connecting to a running application.");
787
            }
788
#else
789
            ini_config.emplace_back("hpx.agas.service_mode=bootstrap");
790
#endif
791
        }
1,188✔
792

793
        enable_logging_settings(vm, ini_config);
1,196✔
794

795
        if (rtcfg_.mode_ != hpx::runtime_mode::local)
1,196✔
796
        {
797
            // Set number of localities in configuration (do it everywhere,
798
            // even if this information is only used by the AGAS server).
799
            ini_config.emplace_back(
2,376✔
800
                "hpx.localities!=" + std::to_string(num_localities_));
1,188✔
801

802
            // FIXME: AGAS V2: if a locality is supposed to run the AGAS
803
            //        service only and requests to use 'priority_local' as the
804
            //        scheduler, switch to the 'local' scheduler instead.
805
            ini_config.emplace_back(std::string("hpx.runtime_mode=") +
1,188✔
806
                get_runtime_mode_name(rtcfg_.mode_));
1,188✔
807

808
            bool noshutdown_evaluate = false;
1,188✔
809
            if (vm.count("hpx:print-counter-at"))
1,188✔
810
            {
811
                std::vector<std::string> print_counters_at =
812
                    vm["hpx:print-counter-at"].as<std::vector<std::string>>();
×
813

814
                for (std::string const& s : print_counters_at)
×
815
                {
816
                    if (0 == std::string("startup").find(s))
×
817
                    {
818
                        ini_config.emplace_back("hpx.print_counter.startup!=1");
×
819
                        continue;
×
820
                    }
821
                    if (0 == std::string("shutdown").find(s))
×
822
                    {
823
                        ini_config.emplace_back(
×
824
                            "hpx.print_counter.shutdown!=1");
825
                        continue;
×
826
                    }
827
                    if (0 == std::string("noshutdown").find(s))
×
828
                    {
829
                        ini_config.emplace_back(
×
830
                            "hpx.print_counter.shutdown!=0");
831
                        noshutdown_evaluate = true;
×
832
                        continue;
×
833
                    }
834

835
                    throw hpx::detail::command_line_error(hpx::util::format(
×
836
                        "Invalid argument for option --hpx:print-counter-at: "
×
837
                        "'{1}', allowed values: 'startup', 'shutdown' "
838
                        "(default), 'noshutdown'",
839
                        s));
×
840
                }
841
            }
×
842

843
            // if any counters have to be evaluated, always print at the end
844
            if (vm.count("hpx:print-counter") ||
2,376✔
845
                vm.count("hpx:print-counter-reset"))
1,188✔
846
            {
847
                if (!noshutdown_evaluate)
×
848
                    ini_config.emplace_back("hpx.print_counter.shutdown!=1");
×
849
                if (vm.count("hpx:reset-counters"))
×
850
                    ini_config.emplace_back("hpx.print_counter.reset!=1");
×
851
            }
×
852
        }
1,188✔
853

854
        if (debug_clp)
1,196✔
855
        {
856
            hpx::local::detail::print_config(ini_config);
×
857
        }
×
858

859
        return true;
860
    }
1,196✔
861

862
    ///////////////////////////////////////////////////////////////////////////
863
    void command_line_handling::enable_logging_settings(
1,196✔
864
        hpx::program_options::variables_map& vm,
865
        std::vector<std::string>& ini_config)
866
    {
867
        base_type::enable_logging_settings(vm, ini_config);
1,196✔
868

869
#if defined(HPX_HAVE_LOGGING)
870
        if (vm.count("hpx:debug-agas-log"))
1,196✔
871
        {
872
            ini_config.emplace_back("hpx.logging.console.agas.destination=" +
×
873
                hpx::local::detail::convert_to_log_file(
×
874
                    vm["hpx:debug-agas-log"].as<std::string>()));
×
875
            ini_config.emplace_back("hpx.logging.agas.destination=" +
×
876
                hpx::local::detail::convert_to_log_file(
×
877
                    vm["hpx:debug-agas-log"].as<std::string>()));
×
878
            ini_config.emplace_back("hpx.logging.console.agas.level=5");
×
879
            ini_config.emplace_back("hpx.logging.agas.level=5");
×
880
        }
×
881

882
        if (vm.count("hpx:debug-parcel-log"))
1,196✔
883
        {
884
            ini_config.emplace_back("hpx.logging.console.parcel.destination=" +
×
885
                hpx::local::detail::convert_to_log_file(
×
886
                    vm["hpx:debug-parcel-log"].as<std::string>()));
×
887
            ini_config.emplace_back("hpx.logging.parcel.destination=" +
×
888
                hpx::local::detail::convert_to_log_file(
×
889
                    vm["hpx:debug-parcel-log"].as<std::string>()));
×
890
            ini_config.emplace_back("hpx.logging.console.parcel.level=5");
×
891
            ini_config.emplace_back("hpx.logging.parcel.level=5");
×
892
        }
×
893
#else
894
        if (vm.count("hpx:debug-agas-log") || vm.count("hpx:debug-parcel-log"))
895
        {
896
            // clang-format off
897
            throw hpx::detail::command_line_error(
898
                "Command line option error: can't enable logging while it "
899
                "was disabled at configuration time. Please re-configure "
900
                "HPX using the option -DHPX_WITH_LOGGING=On.");
901
            // clang-format on
902
        }
903
#endif
904
    }
1,196✔
905

906
    ///////////////////////////////////////////////////////////////////////////
907
    int command_line_handling::call(
598✔
908
        hpx::program_options::options_description const& desc_cmdline, int argc,
909
        char** argv,
910
        std::vector<std::shared_ptr<components::component_registry_base>>&
911
            component_registries)
912
    {
913
        // set the flag signaling that command line parsing has been done
914
        cmd_line_parsed_ = true;
598✔
915

916
        // separate command line arguments from configuration settings
917
        std::vector<std::string> args = preprocess_config_settings(argc, argv);
598✔
918

919
        util::manage_config cfgmap(ini_config_);
598✔
920

921
        // insert the pre-configured ini settings before loading modules
922
        for (std::string const& e : ini_config_)
1,135✔
923
            rtcfg_.parse("<user supplied config>", e, true, false);
537✔
924

925
        // support re-throwing command line exceptions for testing purposes
926
        util::commandline_error_mode error_mode =
598✔
927
            util::commandline_error_mode::allow_unregistered;
928
        if (cfgmap.get_value("hpx.commandline.rethrow_errors", 0) != 0)
598✔
929
        {
930
            error_mode |= util::commandline_error_mode::rethrow_on_error;
×
931
        }
×
932

933
        // The cfg registry may hold command line options to prepend to the
934
        // real command line.
935
        std::string prepend_command_line =
936
            rtcfg_.get_entry("hpx.commandline.prepend_options");
598✔
937

938
        args = hpx::local::detail::prepend_options(
598✔
939
            HPX_MOVE(args), HPX_MOVE(prepend_command_line));
940

941
        // Initial analysis of the command line options. This is preliminary as
942
        // it will not take into account any aliases as defined in any of the
943
        // runtime configuration files.
944
        {
945
            // Boost V1.47 and before do not properly reset a variables_map when
946
            // calling vm.clear(). We work around that problems by creating a
947
            // separate instance just for the preliminary command line handling.
948
            error_mode |= util::commandline_error_mode::ignore_aliases;
598✔
949
            hpx::program_options::variables_map prevm;
598✔
950
            if (!util::parse_commandline(rtcfg_, desc_cmdline, argv[0], args,
598✔
951
                    prevm, std::size_t(-1), error_mode, rtcfg_.mode_))
598✔
952
            {
953
                return -1;
×
954
            }
955

956
            // handle all --hpx:foo options, determine node
957
            std::vector<std::string> ini_config;    // discard
598✔
958
            if (!handle_arguments(cfgmap, prevm, ini_config, node_, true))
598✔
959
            {
960
                return -2;
×
961
            }
962

963
            reconfigure(cfgmap, prevm);
598✔
964
        }
598✔
965

966
#if (defined(HPX_HAVE_NETWORKING) && defined(HPX_HAVE_PARCELPORT_MPI)) ||      \
967
    defined(HPX_HAVE_MODULE_MPI_BASE)
968
        // getting localities from MPI environment (support mpirun)
969
        if (util::mpi_environment::check_mpi_environment(rtcfg_))
970
        {
971
            util::mpi_environment::init(&argc, &argv, rtcfg_);
972
            num_localities_ =
973
                static_cast<std::size_t>(util::mpi_environment::size());
974
            node_ = static_cast<std::size_t>(util::mpi_environment::rank());
975
        }
976
#endif
977
#if (defined(HPX_HAVE_NETWORKING) && defined(HPX_HAVE_PARCELPORT_LCI)) ||      \
978
    defined(HPX_HAVE_MODULE_LCI_BASE)
979
        // better to put LCI init after MPI init, since LCI will also
980
        // initialize MPI if MPI is not already initialized.
981
        if (util::lci_environment::check_lci_environment(rtcfg_))
982
        {
983
            util::lci_environment::init(&argc, &argv, rtcfg_);
984
            num_localities_ =
985
                static_cast<std::size_t>(util::lci_environment::size());
986
            node_ = static_cast<std::size_t>(util::lci_environment::rank());
987
        }
988
#endif
989

990
        // load plugin modules (after first pass of command line handling, so
991
        // that settings given on command line could propagate to modules)
992
        std::vector<std::shared_ptr<plugins::plugin_registry_base>>
993
            plugin_registries = rtcfg_.load_modules(component_registries);
598✔
994

995
        // Re-run program option analysis, ini settings (such as aliases) will
996
        // be considered now.
997

998
        // minimally assume one locality and this is the console
999
        if (node_ == std::size_t(-1))
598✔
1000
            node_ = 0;
317✔
1001

1002
        for (std::shared_ptr<plugins::plugin_registry_base>& reg :
1,184✔
1003
            plugin_registries)
598✔
1004
        {
1005
            reg->init(&argc, &argv, rtcfg_);
586✔
1006
        }
1007

1008
        // Now re-parse the command line using the node number (if given). This
1009
        // will additionally detect any --hpx:N:foo options.
1010
        hpx::program_options::options_description help;
598✔
1011
        std::vector<std::string> unregistered_options;
598✔
1012

1013
        error_mode |= util::commandline_error_mode::report_missing_config_file;
598✔
1014
        if (!util::parse_commandline(rtcfg_, desc_cmdline, argv[0], args, vm_,
598✔
1015
                node_, error_mode, rtcfg_.mode_, &help, &unregistered_options))
598✔
1016
        {
1017
            return -1;
×
1018
        }
1019

1020
        // break into debugger, if requested
1021
        handle_attach_debugger();
598✔
1022

1023
        // handle all --hpx:foo and --hpx:*:foo options
1024
        if (!handle_arguments(cfgmap, vm_, ini_config_, node_))
598✔
1025
        {
1026
            return -2;
×
1027
        }
1028

1029
        return finalize_commandline_handling(
1,196✔
1030
            argc, argv, help, unregistered_options);
598✔
1031
    }
598✔
1032
}}    // 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