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

STEllAR-GROUP / hpx / #857

28 Dec 2022 11:12PM UTC coverage: 86.543% (-0.06%) from 86.602%
#857

push

StellarBot
Merge #6118

6118: Modernize modules from level 17, 18, 19, and 20 r=hkaiser a=hkaiser

working towards https://github.com/STEllAR-GROUP/hpx/issues/5497

Modules:
- core/threading_base
- full/command_line_handling
- core/io_service
- core/schedulers
- core/synchronization
- core/futures
- core/thread_pools
- core/lcos_local
- core/pack_traversal
- core/resource_partitioner
- core/threading
- full/naming_base


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

849 of 849 new or added lines in 98 files covered. (100.0%)

174389 of 201505 relevant lines covered (86.54%)

1916353.25 hits per line

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

56.97
/libs/full/command_line_handling/src/parse_command_line.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/command_line_handling/parse_command_line.hpp>
8
#include <hpx/command_line_handling_local/parse_command_line_local.hpp>
9
#include <hpx/datastructures/any.hpp>
10
#include <hpx/ini/ini.hpp>
11
#include <hpx/modules/errors.hpp>
12
#include <hpx/modules/filesystem.hpp>
13
#include <hpx/util/from_string.hpp>
14

15
#include <cctype>
16
#include <cstddef>
17
#include <fstream>
18
#include <iostream>
19
#include <stdexcept>
20
#include <string>
21
#include <utility>
22
#include <vector>
23

24
///////////////////////////////////////////////////////////////////////////////
25
namespace hpx::util {
26

27
    namespace detail {
28

29
        ///////////////////////////////////////////////////////////////////////
30
        // All command line options which are normally formatted as --hpx:foo
31
        // should be usable as --hpx:N:foo, where N is the node number this
32
        // option should be exclusively used for.
33
        bool handle_node_specific_option(std::string const& s, std::size_t node,
×
34
            std::pair<std::string, std::string>& opt)
35
        {
36
            // any option not starting with --hpx: will be handled elsewhere
37
            constexpr char const hpx_prefix[] = "--hpx:";
×
38
            constexpr std::string::size_type const hpx_prefix_len =
×
39
                sizeof(hpx_prefix) - 1;
40

41
            if (s.size() < hpx_prefix_len ||
×
42
                s.compare(0, hpx_prefix_len, hpx_prefix) != 0 ||
×
43
                !std::isdigit(s[hpx_prefix_len]))    // -V557
×
44
            {
45
                return false;
×
46
            }
47

48
            // any --hpx: option without a second ':' is handled elsewhere as
49
            // well
50
            std::string::size_type p = s.find_first_of(':', hpx_prefix_len);
×
51
            if (p == std::string::npos)
×
52
                return false;
×
53

54
            if (hpx::util::from_string<std::size_t>(
×
55
                    s.substr(hpx_prefix_len, p - hpx_prefix_len),
×
56
                    std::size_t(-1)) == node)
×
57
            {
58
                using hpx::local::detail::trim_whitespace;
59

60
                // this option is for the current locality only
61
                std::string::size_type p1 = s.find_first_of('=', p);
×
62
                if (p1 != std::string::npos)
×
63
                {
64
                    // the option has a value
65
                    std::string o(
66
                        "hpx:" + trim_whitespace(s.substr(p + 1, p1 - p - 1)));
×
67
                    std::string v(trim_whitespace(s.substr(p1 + 1)));
×
68
                    opt = std::make_pair(o, v);
×
69
                }
×
70
                else
71
                {
72
                    // no value
73
                    std::string o("hpx:" + trim_whitespace(s.substr(p + 1)));
×
74
                    opt = std::make_pair(o, std::string());
×
75
                }
×
76
                return true;
×
77
            }
78

79
            // This option is specifically not for us, so we return an option
80
            // which will be silently ignored.
81
            opt = std::make_pair(std::string("hpx:ignore"), std::string());
×
82
            return true;
×
83
        }
×
84

85
        ///////////////////////////////////////////////////////////////////////
86
        // Additional command line parser which interprets '@something' as an
87
        // option "options-file" with the value "something". Additionally we
88
        // resolve defined command line option aliases.
89
        struct option_parser : hpx::local::detail::option_parser
90
        {
91
            using base_type = hpx::local::detail::option_parser;
92

93
            option_parser(util::section const& ini, std::size_t node,
×
94
                bool ignore_aliases) noexcept
95
              : base_type(ini, ignore_aliases)
×
96
              , node_(node)
×
97
            {
×
98
            }
×
99

100
            std::pair<std::string, std::string> operator()(
×
101
                std::string const& s) const
102
            {
103
                // handle node specific options
104
                std::pair<std::string, std::string> opt;
×
105
                if (handle_node_specific_option(s, node_, opt))
×
106
                    return opt;
×
107

108
                // handle aliasing, if enabled
109
                return static_cast<base_type const&>(*this)(s);
×
110
            }
×
111

112
            std::size_t node_;
113
        };
114

115
        ///////////////////////////////////////////////////////////////////////
116
        // Handle all options from a given config file, parse and add them to
117
        // the given variables_map
118
        bool handle_config_file_options(std::vector<std::string> const& options,
11,305✔
119
            hpx::program_options::options_description const& desc,
120
            hpx::program_options::variables_map& vm, util::section const& rtcfg,
121
            std::size_t node, util::commandline_error_mode error_mode)
122
        {
123
            // add options to parsed settings
124
            if (!options.empty())
11,305✔
125
            {
126
                using hpx::program_options::command_line_parser;
127
                using hpx::program_options::store;
128
                using hpx::program_options::command_line_style::unix_style;
129

130
                util::commandline_error_mode mode =
×
131
                    error_mode & util::commandline_error_mode::ignore_aliases;
×
132
                util::commandline_error_mode notmode =
×
133
                    error_mode & ~util::commandline_error_mode::ignore_aliases;
×
134

135
                store(hpx::local::detail::get_commandline_parser(
×
136
                          command_line_parser(options)
×
137
                              .options(desc)
×
138
                              .style(unix_style)
×
139
                              .extra_parser(hpx::util::detail::option_parser(
×
140
                                  rtcfg, node, as_bool(mode))),
×
141
                          notmode)
×
142
                          .run(),
×
143
                    vm);
×
144
                notify(vm);
×
145
                return true;
×
146
            }
147
            return false;
11,305✔
148
        }
11,305✔
149

150
        // try to find a config file somewhere up the filesystem hierarchy
151
        // starting with the input file path. This allows to use a general
152
        // <app_name>.cfg file for all executables in a certain project.
153
        void handle_generic_config_options(std::string appname,
1,792✔
154
            hpx::program_options::variables_map& vm,
155
            hpx::program_options::options_description const& desc_cfgfile,
156
            util::section const& ini, std::size_t node,
157
            util::commandline_error_mode error_mode)
158
        {
159
            if (appname.empty())
1,792✔
160
                return;
×
161

162
            filesystem::path dir(filesystem::initial_path());
1,792✔
163
            filesystem::path app(appname);
1,792✔
164
            appname = filesystem::basename(app.filename());
1,792✔
165

166
            // walk up the hierarchy, trying to find a file <appname>.cfg
167
            while (!dir.empty())
11,305✔
168
            {
169
                filesystem::path filename = dir / (appname + ".cfg");
11,305✔
170
                util::commandline_error_mode mode = error_mode &
22,610✔
171
                    ~util::commandline_error_mode::report_missing_config_file;
11,305✔
172
                std::vector<std::string> options =
173
                    hpx::local::detail::read_config_file_options(
11,305✔
174
                        filename.string(), mode);
11,305✔
175

176
                bool result = handle_config_file_options(
11,305✔
177
                    options, desc_cfgfile, vm, ini, node, mode);
11,305✔
178
                if (result)
11,305✔
179
                {
180
                    break;    // break on the first options file found
×
181
                }
182

183
                // Boost filesystem and C++17 filesystem behave differently
184
                // here. Boost filesystem returns an empty path for
185
                // "/".parent_path() whereas C++17 filesystem will keep
186
                // returning "/".
187
#if !defined(HPX_FILESYSTEM_HAVE_BOOST_FILESYSTEM_COMPATIBILITY)
188
                auto dir_prev = dir;
11,305✔
189
                dir = dir.parent_path();    // chop off last directory part
11,305✔
190
                if (dir_prev == dir)
11,305✔
191
                    break;
1,792✔
192
#else
193
                dir = dir.parent_path();    // chop off last directory part
194
#endif
195
            }
11,305✔
196
        }
1,792✔
197

198
        // handle all --options-file found on the command line
199
        void handle_config_options(hpx::program_options::variables_map& vm,
1,792✔
200
            hpx::program_options::options_description const& desc_cfgfile,
201
            util::section const& ini, std::size_t node,
202
            util::commandline_error_mode error_mode)
203
        {
204
            using hpx::program_options::options_description;
205
            if (vm.count("hpx:options-file"))
1,792✔
206
            {
207
                std::vector<std::string> const& cfg_files =
×
208
                    vm["hpx:options-file"].as<std::vector<std::string>>();
×
209

210
                for (std::string const& cfg_file : cfg_files)
×
211
                {
212
                    // parse a single config file and store the results
213
                    std::vector<std::string> options =
214
                        hpx::local::detail::read_config_file_options(
×
215
                            cfg_file, error_mode);
×
216

217
                    handle_config_file_options(
×
218
                        options, desc_cfgfile, vm, ini, node, error_mode);
×
219
                }
×
220
            }
×
221
        }
1,792✔
222

223
        hpx::local::detail::options_map compose_all_options(
1,792✔
224
            hpx::runtime_mode mode)
225
        {
226
            using hpx::local::detail::options_type;
227
            using hpx::program_options::value;
228

229
            hpx::local::detail::options_map all_options =
1,792✔
230
                hpx::local::detail::compose_local_options();
1,792✔
231

232
            switch (mode)
1,792✔
233
            {
234
            case runtime_mode::default_:
235
#if defined(HPX_HAVE_NETWORKING)
236
                // clang-format off
237
                all_options[options_type::hpx_options].add_options()
592✔
238
                    ("hpx:worker", "run this instance in worker mode")
239
                    ("hpx:console", "run this instance in console mode")
240
                    ("hpx:connect", "run this instance in worker mode, "
241
                         "but connecting late")
242
                ;
243
#else
244
                all_options[options_type::hpx_options].add_options()
245
                    ("hpx:console", "run this instance in console mode")
246
                ;
247
                // clang-format on
248
#endif
249
                break;
1,781✔
250

251
#if defined(HPX_HAVE_NETWORKING)
252
            case runtime_mode::worker:
253
            case runtime_mode::console:
254
                [[fallthrough]];
255
            case runtime_mode::connect:
256
                // If the runtime for this application is always run in worker
257
                // mode, silently ignore the worker option for hpx_pbs
258
                // compatibility.
259

260
                // clang-format off
261
                all_options[options_type::hidden_options].add_options()
1,192✔
262
                    ("hpx:worker", "run this instance in worker mode")
263
                    ("hpx:console", "run this instance in console mode")
264
                    ("hpx:connect", "run this instance in worker mode, "
265
                        "but connecting late")
266
                ;
267
                // clang-format on
268
                break;
1,192✔
269
#else
270
            case runtime_mode::console:
271
                // clang-format off
272
                all_options[options_type::hidden_options].add_options()
273
                    ("hpx:console", "run this instance in console mode")
274
                ;
275
                // clang-format on
276
                break;
277
#endif
278
            case runtime_mode::local:
279
                break;
8✔
280

281
            case runtime_mode::invalid:
282
                [[fallthrough]];
283
            default:
284
                throw hpx::detail::command_line_error(
×
285
                    "Invalid runtime mode specified");
286
            }
287

288
            // Always add the option to start the local runtime
289
            // clang-format off
290
            all_options[options_type::hpx_options].add_options()
1,792✔
291
                ("hpx:local",
292
                  "run this instance in local mode (experimental; certain "
293
                  "functionalities are not available at runtime)")
294
            ;
295
            // clang-format on
296

297
            // general options definitions
298
            // clang-format off
299
            all_options[options_type::hpx_options].add_options()
17,920✔
300
                ("hpx:run-hpx-main",
301
                  "run the hpx_main function, regardless of locality mode")
302
#if defined(HPX_HAVE_NETWORKING)
303
                ("hpx:agas", value<std::string>(),
1,792✔
304
                  "the IP address the AGAS root server is running on, "
305
                  "expected format: `address:port' (default: "
306
                  "127.0.0.1:7910)")
307
                ("hpx:hpx", value<std::string>(),
1,792✔
308
                  "the IP address the HPX parcelport is listening on, "
309
                  "expected format: `address:port' (default: "
310
                  "127.0.0.1:7910)")
311
                ("hpx:nodefile", value<std::string>(),
1,792✔
312
                  "the file name of a node file to use (list of nodes, one "
313
                  "node name per line and core)")
314
                ("hpx:nodes", value<std::vector<std::string> >()->multitoken(),
1,792✔
315
                  "the (space separated) list of the nodes to use (usually "
316
                  "this is extracted from a node file)")
317
                ("hpx:endnodes", "this can be used to end the list of nodes "
318
                  "specified using the option --hpx:nodes")
319
                ("hpx:ifsuffix", value<std::string>(),
1,792✔
320
                  "suffix to append to host names in order to resolve them "
321
                  "to the proper network interconnect")
322
                ("hpx:ifprefix", value<std::string>(),
1,792✔
323
                  "prefix to prepend to host names in order to resolve them "
324
                  "to the proper network interconnect")
325
                ("hpx:iftransform", value<std::string>(),
1,792✔
326
                  "sed-style search and replace (s/search/replace/) used to "
327
                  "transform host names to the proper network interconnect")
328
                ("hpx:force_ipv4", "Force ipv4 for resolving network hostnames")
329
#endif
330
#if defined(HPX_HAVE_DISTRIBUTED_RUNTIME)
331
                ("hpx:localities", value<std::size_t>(),
1,792✔
332
                  "the number of localities to wait for at application "
333
                  "startup (default: 1)")
334
#endif
335
#if defined(HPX_HAVE_NETWORKING)
336
                ("hpx:node", value<std::size_t>(),
1,792✔
337
                  "number of the node this locality is run on "
338
                  "(must be unique, alternatively: -0, -1, ..., -9)")
339
                ("hpx:ignore-batch-env", "ignore batch environment variables "
340
                 "(implied by --hpx:use-process-mask)")
341
                ("hpx:expect-connecting-localities",
342
                  "this locality expects other localities to dynamically connect "
343
                  "(default: false if the number of localities is equal to one, "
344
                  "true if the number of initial localities is larger than 1)")
345
#endif
346
            ;
347

348
            all_options[options_type::debugging_options].add_options()
5,376✔
349
                ("hpx:debug-agas-log", value<std::string>()->implicit_value("cout"),
1,792✔
350
                  "enable all messages on the AGAS log channel and send all "
351
                  "AGAS logs to the target destination")
352
                ("hpx:debug-parcel-log", value<std::string>()->implicit_value("cout"),
1,792✔
353
                  "enable all messages on the parcel transport log channel and send all "
354
                  "parcel transport logs to the target destination")
355
#if defined(HPX_HAVE_DISTRIBUTED_RUNTIME)
356
                ("hpx:list-symbolic-names", "list all registered symbolic "
357
                  "names after startup")
358
                ("hpx:list-component-types", "list all dynamic component types "
359
                  "after startup")
360
#endif
361
#if defined(HPX_HAVE_NETWORKING)
362
                ("hpx:list-parcel-ports", "list all available parcel-ports")
363
#endif
364
            ;
365

366
#if defined(HPX_HAVE_DISTRIBUTED_RUNTIME)
367
            all_options[options_type::counter_options].add_options()
14,336✔
368
                ("hpx:print-counter", value<std::vector<std::string> >()->composing(),
1,792✔
369
                  "print the specified performance counter either repeatedly "
370
                  "and/or at the times specified by --hpx:print-counter-at "
371
                    "(see also option --hpx:print-counter-interval)")
372
                ("hpx:print-counter-reset",
373
                        value<std::vector<std::string> >()->composing(),
1,792✔
374
                  "print the specified performance counter either repeatedly "
375
                  "and/or at the times specified by --hpx:print-counter-at, "
376
                    "reset the counter after the "
377
                    "value is queried (see also option --hpx:print-counter-interval)")
378
                ("hpx:print-counter-interval", value<std::size_t>(),
1,792✔
379
                  "print the performance counter(s) specified with --hpx:print-counter "
380
                  "repeatedly after the time interval (specified in milliseconds) "
381
                  "(default: 0, which means print once at shutdown)")
382
                ("hpx:print-counter-destination", value<std::string>(),
1,792✔
383
                  "print the performance counter(s) specified with --hpx:print-counter "
384
                  "to the given file (default: console (cout), "
385
                  "possible values: 'cout' (console), 'none' (no output), or "
386
                  "any file name")
387
                ("hpx:list-counters", value<std::string>()->implicit_value("minimal"),
1,792✔
388
                  "list the names of all registered performance counters, "
389
                  "possible values:\n"
390
                  "   'minimal' (prints counter name skeletons)\n"
391
                  "   'full' (prints all available counter names)")
392
                ("hpx:list-counter-infos",
393
                    value<std::string>()->implicit_value("minimal"),
1,792✔
394
                  "list the description of all registered performance counters, "
395
                  "possible values:\n"
396
                  "   'minimal' (prints infos for counter name skeletons)\n"
397
                  "   'full' (prints all available counter infos)")
398
                ("hpx:print-counter-format", value<std::string>(),
1,792✔
399
                  "print the performance counter(s) specified with --hpx:print-counter "
400
                  "in a given format (default: normal)")
401
                ("hpx:csv-header",
402
                  "print the performance counter(s) specified with --hpx:print-counter "
403
                  "with header when format specified with --hpx:print-counter-format"
404
                  "is csv or csv-short")
405
                ("hpx:no-csv-header",
406
                  "print the performance counter(s) specified with --hpx:print-counter "
407
                  "without header when format specified with --hpx:print-counter-format"
408
                  "is csv or csv-short")
409
                ("hpx:print-counter-at",
410
                    value<std::vector<std::string> >()->composing(),
1,792✔
411
                  "print the performance counter(s) specified with "
412
                  "--hpx:print-counter (or --hpx:print-counter-reset) at the given "
413
                  "point in time, possible "
414
                  "argument values: 'startup', 'shutdown' (default), 'noshutdown'")
415
                ("hpx:reset-counters",
416
                  "reset all performance counter(s) specified with --hpx:print-counter "
417
                  "after they have been evaluated")
418
                ("hpx:print-counters-locally",
419
                  "each locality prints only its own local counters")
420
                ("hpx:print-counter-types",
421
                  "append counter type description to generated output")
422
            ;
423
#endif
424
            // clang-format on
425

426
            return all_options;
1,792✔
427
        }
1,792✔
428
    }    // namespace detail
429

430
    ///////////////////////////////////////////////////////////////////////////
431
    // parse the command line
432
    bool parse_commandline(util::section const& rtcfg,
1,792✔
433
        hpx::program_options::options_description const& app_options,
434
        std::string const& arg0, std::vector<std::string> const& args,
435
        hpx::program_options::variables_map& vm, std::size_t node,
436
        util::commandline_error_mode error_mode, hpx::runtime_mode mode,
437
        hpx::program_options::options_description* visible,
438
        std::vector<std::string>* unregistered_options)
439
    {
440
        using hpx::local::detail::options_type;
441

442
        try
443
        {
444
            // construct the overall options description and parse the command
445
            // line
446
            hpx::local::detail::options_map all_options =
447
                detail::compose_all_options(mode);
1,792✔
448

449
            hpx::local::detail::compose_all_options(app_options, all_options);
1,792✔
450

451
#if defined(HPX_HAVE_DISTRIBUTED_RUNTIME)
452
            all_options[options_type::desc_cmdline].add(
3,584✔
453
                all_options[options_type::counter_options]);
1,792✔
454
            all_options[options_type::desc_cfgfile].add(
3,584✔
455
                all_options[options_type::counter_options]);
1,792✔
456
#endif
457
            bool result = hpx::local::detail::parse_commandline(rtcfg,
3,584✔
458
                all_options, app_options, args, vm, error_mode, visible,
1,792✔
459
                unregistered_options);
1,792✔
460

461
            if (result && visible != nullptr)
1,792✔
462
            {
463
                (*visible).add(all_options[options_type::counter_options]);
598✔
464
            }
598✔
465

466
            detail::handle_generic_config_options(arg0, vm,
1,792✔
467
                all_options[options_type::desc_cfgfile], rtcfg, node,
1,792✔
468
                error_mode);
1,792✔
469
            detail::handle_config_options(vm,
1,792✔
470
                all_options[options_type::desc_cfgfile], rtcfg, node,
1,792✔
471
                error_mode);
1,792✔
472

473
            return result;
1,792✔
474
        }
1,792✔
475
        catch (std::exception const& e)
476
        {
477
            if (as_bool(error_mode &
×
478
                    util::commandline_error_mode::rethrow_on_error))
479
            {
480
                throw;
×
481
            }
482

483
            std::cerr << "hpx::init: exception caught: " << e.what()
×
484
                      << std::endl;
×
485
        }
×
486
        return false;
×
487
    }
1,792✔
488

489
    ///////////////////////////////////////////////////////////////////////////
490
    namespace detail {
491

492
        std::string extract_arg0(std::string const& cmdline)
596✔
493
        {
494
            std::string::size_type p = cmdline.find_first_of(" \t");
596✔
495
            if (p != std::string::npos)
596✔
496
            {
497
                return cmdline.substr(0, p);
596✔
498
            }
499
            return cmdline;
×
500
        }
596✔
501
    }    // namespace detail
502

503
    bool parse_commandline(util::section const& rtcfg,
596✔
504
        hpx::program_options::options_description const& app_options,
505
        std::string const& cmdline, hpx::program_options::variables_map& vm,
506
        std::size_t node, util::commandline_error_mode error_mode,
507
        hpx::runtime_mode mode,
508
        hpx::program_options::options_description* visible,
509
        std::vector<std::string>* unregistered_options)
510
    {
511
        using namespace hpx::program_options;
512
#if defined(HPX_WINDOWS)
513
        std::vector<std::string> args = split_winmain(cmdline);
514
#else
515
        std::vector<std::string> args = split_unix(cmdline);
596✔
516
#endif
517
        return parse_commandline(rtcfg, app_options,
596✔
518
            detail::extract_arg0(cmdline), args, vm, node, error_mode, mode,
596✔
519
            visible, unregistered_options);
596✔
520
    }
596✔
521
}    // 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