• 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

6.94
/libs/full/performance_counters/src/registry.cpp
1
//  Copyright (c) 2007-2025 Hartmut Kaiser
2
//  Copyright (c)      2011 Bryce Lelbach
3
//
4
//  SPDX-License-Identifier: BSL-1.0
5
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
6
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7

8
#include <hpx/config.hpp>
9
#include <hpx/components_base/agas_interface.hpp>
10
#include <hpx/components_base/server/create_component.hpp>
11
#include <hpx/modules/errors.hpp>
12
#include <hpx/modules/functional.hpp>
13
#include <hpx/modules/logging.hpp>
14
#include <hpx/modules/util.hpp>
15
#include <hpx/performance_counters/counters.hpp>
16
#include <hpx/performance_counters/registry.hpp>
17
#include <hpx/performance_counters/server/arithmetics_counter.hpp>
18
#include <hpx/performance_counters/server/arithmetics_counter_extended.hpp>
19
#include <hpx/performance_counters/server/elapsed_time_counter.hpp>
20
#include <hpx/performance_counters/server/raw_counter.hpp>
21
#include <hpx/performance_counters/server/raw_values_counter.hpp>
22
#include <hpx/performance_counters/server/statistics_counter.hpp>
23
#include <hpx/statistics/rolling_max.hpp>
24
#include <hpx/statistics/rolling_min.hpp>
25

26
#include <boost/accumulators/statistics/rolling_variance.hpp>
27
#include <boost/accumulators/statistics_fwd.hpp>
28

29
#include <cstddef>
30
#include <cstdint>
31
#include <functional>
32
#include <regex>
33
#include <string>
34
#include <utility>
35
#include <vector>
36

37
#include <hpx/config/warnings_prefix.hpp>
38

39
///////////////////////////////////////////////////////////////////////////////
40
namespace hpx { namespace performance_counters {
41

42
    ///////////////////////////////////////////////////////////////////////////
32✔
43
    void registry::clear()
44
    {
45
        countertypes_.clear();
32✔
46
    }
47

8,060✔
48
    registry::counter_type_map_type::iterator registry::locate_counter_type(
49
        std::string const& type_name)
50
    {
51
        auto it = countertypes_.find(type_name);
8,060✔
52
        if (it == countertypes_.end())
53
        {
54
            // if the full type is not available, try to locate the object name
55
            // as a type only
56
            error_code ec(throwmode::lightweight);
57
            counter_path_elements p;
4,030✔
58
            get_counter_type_path_elements(type_name, p, ec);
4,030✔
59
            if (!ec)
8,060✔
60
                it = countertypes_.find("/" + p.objectname_);
4,030✔
61
        }
8,060✔
62
        return it;
63
    }
64

65
    registry::counter_type_map_type::const_iterator
×
66
    registry::locate_counter_type(std::string const& type_name) const
67
    {
68
        auto it = countertypes_.find(type_name);
69
        if (it == countertypes_.end())
×
70
        {
71
            // if the full type is not available, try to locate the object name
72
            // as a type only
73
            error_code ec(throwmode::lightweight);
74
            counter_path_elements p;
75
            get_counter_type_path_elements(type_name, p, ec);
×
76
            if (!ec)
×
77
                it = countertypes_.find("/" + p.objectname_);
×
78
        }
×
79
        return it;
×
80
    }
81

82
    ///////////////////////////////////////////////////////////////////////////
83
    counter_status registry::add_counter_type(counter_info const& info,
4,030✔
84
        create_counter_func const& create_counter_,
85
        discover_counters_func const& discover_counters_, error_code& ec)
86
    {
87
        // create canonical type name
88
        std::string type_name;
89
        counter_status status =
90
            get_counter_type_name(info.fullname_, type_name, ec);
4,030✔
91
        if (!status_is_valid(status))
4,030✔
92
            return status;
93

94
        auto it = locate_counter_type(type_name);
4,030✔
95
        if (it != countertypes_.end())
4,030✔
96
        {
97
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
×
98
                "registry::add_counter_type",
99
                "counter type already defined: {}", type_name);
100
            return counter_status::already_defined;
×
101
        }
102

103
        std::pair<counter_type_map_type::iterator, bool> p =
104
            countertypes_.emplace(type_name,
4,030✔
105
                counter_data(info, create_counter_, discover_counters_));
8,060✔
106

107
        if (!p.second)
4,030✔
108
        {
109
            LPCS_(warning).format(
×
110
                "failed to register counter type {}", type_name);
111
            return counter_status::invalid_data;
×
112
        }
113

114
        LPCS_(info).format("counter type {} registered", type_name);
4,030✔
115

116
        if (&ec != &throws)
4,030✔
117
            ec = make_success_code();
×
118
        return counter_status::valid_data;
119
    }
120

121
    /// \brief Call the supplied function for the given registered counter type.
122
    counter_status registry::discover_counter_type(std::string const& fullname,
×
123
        discover_counter_func discover_counter, discover_counters_mode mode,
124
        error_code& ec)
125
    {
126
        // create canonical type name
127
        std::string type_name;
128
        counter_status status = get_counter_type_name(fullname, type_name, ec);
×
129
        if (!status_is_valid(status))
×
130
            return status;
131

132
        if (type_name.find_first_of("*?[]") == std::string::npos)
×
133
        {
134
            auto it = locate_counter_type(type_name);
×
135
            if (it == countertypes_.end())
×
136
            {
137
                // compose a list of known counter types
138
                std::string types;
139
                auto end = countertypes_.end();
140
                for (auto it_ct = countertypes_.begin(); it_ct != end; ++it_ct)
×
141
                {
142
                    types += "  " + it_ct->first + "\n";
×
143
                }
144

×
145
                HPX_THROWS_IF(ec, hpx::error::bad_parameter,
146
                    "registry::discover_counter_type",
147
                    "unknown counter type: {}, known counter types: \n{}",
×
148
                    type_name, types);
149
                return counter_status::counter_type_unknown;
150
            }
151

152
            if (mode == discover_counters_mode::full)
153
            {
154
                using hpx::placeholders::_1;
×
155
                discover_counter = hpx::bind(
156
                    &expand_counter_info, _1, discover_counter, std::ref(ec));
157
            }
×
158

159
            counter_info info = it->second.info_;
160
            info.fullname_ = fullname;
161

×
162
            if (!it->second.discover_counters_.empty() &&
163
                !it->second.discover_counters_(
164
                    info, discover_counter, mode, ec))
×
165
            {
×
166
                return counter_status::invalid_data;
167
            }
168
        }
169
        else
170
        {
×
171
            std::string str_rx(util::regex_from_pattern(type_name, ec));
172
            if (ec)
173
                return counter_status::invalid_data;
×
174

×
175
            if (mode == discover_counters_mode::full)
176
            {
177
                using hpx::placeholders::_1;
×
178
                discover_counter = hpx::bind(
179
                    &expand_counter_info, _1, discover_counter, std::ref(ec));
180
            }
×
181

182
            // split name
183
            counter_path_elements p;
184
            get_counter_path_elements(fullname, p, ec);
185
            if (ec)
186
                return counter_status::invalid_data;
×
187

×
188
            bool found_one = false;
189
            std::regex rx(str_rx);
190

191
            counter_type_map_type::const_iterator end = countertypes_.end();
×
192
            for (counter_type_map_type::const_iterator it =
193
                     countertypes_.begin();
194
                it != end; ++it)
×
195
            {
196
                if (!std::regex_match(it->first, rx))
×
197
                    continue;
198
                found_one = true;
×
199

×
200
                // propagate parameters
201
                counter_info info = it->second.info_;
202
                if (!p.parameters_.empty())
203
                    info.fullname_ += "@" + p.parameters_;
×
204

×
205
                if (!it->second.discover_counters_.empty() &&
×
206
                    !it->second.discover_counters_(
207
                        info, discover_counter, mode, ec))
×
208
                {
×
209
                    return counter_status::invalid_data;
210
                }
211
            }
212

213
            if (!found_one)
×
214
            {
215
                // compose a list of known counter types
×
216
                std::string types;
217
                auto end_ct = countertypes_.end();
218
                for (auto it = countertypes_.begin(); it != end_ct; ++it)
219
                {
220
                    types += "  " + it->first + "\n";
×
221
                }
222

×
223
                HPX_THROWS_IF(ec, hpx::error::bad_parameter,
224
                    "registry::discover_counter_type",
×
225
                    "counter type {} does not match any known type, known "
226
                    "counter types: \n{}",
227
                    type_name, types);
×
228
                return counter_status::counter_type_unknown;
229
            }
230
        }
231

232
        if (&ec != &throws)
233
            ec = make_success_code();
234

×
235
        return counter_status::valid_data;
236
    }
×
237

×
238
    /// \brief Call the supplied function for all registered counter types.
239
    counter_status registry::discover_counter_types(
240
        discover_counter_func discover_counter, discover_counters_mode mode,
×
241
        error_code& ec) const
242
    {
243
        // Introducing this temporary silence a report about a potential memory
×
244
        // from clang's static analyzer
245
        discover_counter_func discover_counter_;
246
        if (mode == discover_counters_mode::full)
247
        {
248
            using hpx::placeholders::_1;
249
            discover_counter_ = hpx::bind(&expand_counter_info, _1,
×
250
                HPX_MOVE(discover_counter), std::ref(ec));
×
251
        }
252
        else
253
        {
×
254
            discover_counter_ = HPX_MOVE(discover_counter);
255
        }
256

257
        for (auto const& [k, v] : countertypes_)
258
        {
259
            if (!v.discover_counters_.empty() &&
260
                !v.discover_counters_(v.info_, discover_counter_, mode, ec))
261
            {
×
262
                return counter_status::invalid_data;
263
            }
×
264
        }
×
265

×
266
        if (&ec != &throws)
267
            ec = make_success_code();
268

269
        return counter_status::valid_data;
270
    }
271

×
272
    ///////////////////////////////////////////////////////////////////////////
×
273
    counter_status registry::get_counter_create_function(
274
        counter_info const& info, create_counter_func& func,
275
        error_code& ec) const
276
    {
277
        // create canonical type name
278
        std::string type_name;
×
279
        counter_status status =
280
            get_counter_type_name(info.fullname_, type_name, ec);
281
        if (!status_is_valid(status))
282
            return status;
283

284
        auto it = locate_counter_type(type_name);
285
        if (it == countertypes_.end())
×
286
        {
×
287
            // compose a list of known counter types
288
            std::string types;
289
            auto end = countertypes_.end();
290
            for (auto it_ct = countertypes_.begin(); it_ct != end; ++it_ct)
×
291
            {
×
292
                types += "  " + it_ct->first + "\n";
293
            }
294

295
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
296
                "registry::get_counter_create_function",
×
297
                "counter type {} is not defined, known counter types: \n{}",
298
                type_name, types);
×
299
            return counter_status::counter_type_unknown;
300
        }
×
301

302
        if (it->second.create_counter_.empty())
303
        {
×
304
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
305
                "registry::get_counter_create_function",
306
                "counter type {} has no associated create function", type_name);
307
            return counter_status::invalid_data;
308
        }
309

310
        func = it->second.create_counter_;
×
311

312
        if (&ec != &throws)
×
313
            ec = make_success_code();
314
        return counter_status::valid_data;
315
    }
×
316

317
    ///////////////////////////////////////////////////////////////////////////
318
    counter_status registry::get_counter_discovery_function(
319
        counter_info const& info, discover_counters_func& func,
320
        error_code& ec) const
×
321
    {
×
322
        // create canonical type name
323
        std::string type_name;
324
        counter_status status =
325
            get_counter_type_name(info.fullname_, type_name, ec);
326
        if (!status_is_valid(status))
×
327
            return status;
328

329
        auto it = locate_counter_type(type_name);
330
        if (it == countertypes_.end())
331
        {
332
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
333
                "registry::get_counter_discovery_function",
×
334
                "counter type {} is not defined", type_name);
×
335
            return counter_status::counter_type_unknown;
336
        }
337

338
        if (it->second.discover_counters_.empty())
×
339
        {
×
340
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
341
                "registry::get_counter_discovery_function",
×
342
                "counter type {} has no associated discovery function",
343
                type_name);
344
            return counter_status::invalid_data;
×
345
        }
346

347
        func = it->second.discover_counters_;
×
348

349
        if (&ec != &throws)
×
350
            ec = make_success_code();
351
        return counter_status::valid_data;
352
    }
353

×
354
    ///////////////////////////////////////////////////////////////////////////
355
    counter_status registry::remove_counter_type(
356
        counter_info const& info, error_code& ec)
357
    {
358
        // create canonical type name
×
359
        std::string type_name;
×
360
        counter_status status =
361
            get_counter_type_name(info.fullname_, type_name, ec);
362
        if (!status_is_valid(status))
363
            return status;
364

4,030✔
365
        auto it = locate_counter_type(type_name);
366
        if (it == countertypes_.end())
367
        {
368
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
369
                "registry::remove_counter_type", "counter type is not defined");
370
            return counter_status::counter_type_unknown;
4,030✔
371
        }
4,030✔
372

373
        LPCS_(info).format("counter type {} unregistered", type_name);
374

4,030✔
375
        countertypes_.erase(it);
4,030✔
376

377
        if (&ec != &throws)
×
378
            ec = make_success_code();
379
        return counter_status::valid_data;
×
380
    }
381

382
    ///////////////////////////////////////////////////////////////////////////
4,030✔
383
    std::int64_t wrap_counter(std::int64_t* p, bool /* reset */)
384
    {
385
        std::int64_t result = *p;
386
        *p = 0;
4,030✔
387
        return result;
8,060✔
388
    }
389

390
    ///////////////////////////////////////////////////////////////////////////
391
    counter_status registry::create_raw_counter_value(counter_info const& info,
392
        std::int64_t* countervalue, naming::gid_type& id, error_code& ec)
×
393
    {
394
        hpx::function<std::int64_t(bool)> func(
×
395
            hpx::bind_front(wrap_counter, countervalue));
×
396
        return create_raw_counter(info, func, id, ec);
×
397
    }
398

399
    static std::int64_t wrap_raw_counter(
400
        hpx::function<std::int64_t()> const& f, bool)
×
401
    {
402
        return f();
403
    }
404

405
    static std::vector<std::int64_t> wrap_raw_values_counter(
×
406
        hpx::function<std::vector<std::int64_t>()> const& f, bool)
407
    {
408
        return f();
×
409
    }
410

411
    counter_status registry::create_raw_counter(counter_info const& info,
×
412
        hpx::function<std::int64_t()> const& f, naming::gid_type& id,
413
        error_code& ec)
414
    {
×
415
        hpx::function<std::int64_t(bool)> func(
416
            hpx::bind_front(&wrap_raw_counter, f));
417
        return create_raw_counter(info, func, id, ec);
×
418
    }
419

420
    namespace {
×
421

422
        constexpr bool is_not_counter_type(
423
            counter_type ct, counter_type ct1, counter_type ct2) noexcept
424
        {
425
            return ct != ct1 || ct != ct2;
×
426
        }
×
427
    }    // namespace
428

429
    counter_status registry::create_raw_counter(counter_info const& info,
×
430
        hpx::function<std::int64_t(bool)> const& f, naming::gid_type& id,
431
        error_code& ec)
432
    {
433
        // create canonical type name
434
        std::string type_name;
435
        counter_status status =
436
            get_counter_type_name(info.fullname_, type_name, ec);
×
437
        if (!status_is_valid(status))
×
438
            return status;
439

440
        auto it = locate_counter_type(type_name);
×
441
        if (it == countertypes_.end())
×
442
        {
443
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
×
444
                "registry::create_raw_counter", "unknown counter type {}",
445
                type_name);
446
            return counter_status::counter_type_unknown;
×
447
        }
448

449
        // make sure the counter type requested is supported
450
        if (is_not_counter_type(
×
451
                counter_type::raw, it->second.info_.type_, info.type_) &&
×
452
            is_not_counter_type(counter_type::monotonically_increasing,
453
                it->second.info_.type_, info.type_) &&
×
454
            is_not_counter_type(counter_type::aggregating,
×
455
                it->second.info_.type_, info.type_) &&
×
456
            is_not_counter_type(counter_type::elapsed_time,
×
457
                it->second.info_.type_, info.type_) &&
×
458
            is_not_counter_type(counter_type::average_count,
×
459
                it->second.info_.type_, info.type_) &&
×
460
            is_not_counter_type(counter_type::average_timer,
×
461
                it->second.info_.type_, info.type_))
×
462
        {
×
463
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
464
                "registry::create_raw_counter",
×
465
                "invalid counter type requested (only counter_type::raw, "
466
                "counter_type::monotonically_increasing, "
467
                "counter_type::aggregating, "
468
                "counter_type::elapsed_time, counter_type::average_count, or "
469
                "counter_type::average_timer are supported)");
470
            return counter_status::counter_type_unknown;
471
        }
×
472

473
        // make sure parent instance name is set properly
474
        counter_info complemented_info = info;
475
        complement_counter_info(complemented_info, it->second.info_, ec);
×
476
        if (ec)
×
477
            return counter_status::invalid_data;
×
478

479
        // create the counter as requested
480
        try
481
        {
482
            using counter_t = components::component<server::raw_counter>;
483
            id = components::server::construct<counter_t>(complemented_info, f);
484
        }
×
485
        catch (hpx::exception const& e)
486
        {
×
487
            id = naming::invalid_gid;    // reset result
488
            if (&ec == &throws)
489
                throw;
×
490
            ec = make_error_code(e.get_error(), e.what());
×
491
            LPCS_(warning).format("failed to create raw counter {} ({})",
×
492
                complemented_info.fullname_, e.what());
×
493
            return counter_status::invalid_data;
×
494
        }
495

×
496
        LPCS_(info).format(
497
            "raw counter {} created at {}", complemented_info.fullname_, id);
×
498

499
        if (&ec != &throws)
500
            ec = make_success_code();
×
501
        return counter_status::valid_data;
×
502
    }
503

×
504
    counter_status registry::create_raw_counter(counter_info const& info,
505
        hpx::function<std::vector<std::int64_t>()> const& f,
×
506
        naming::gid_type& id, error_code& ec)
507
    {
508
        hpx::function<std::vector<std::int64_t>(bool)> func(
509
            hpx::bind_front(&wrap_raw_values_counter, f));
510
        return create_raw_counter(info, func, id, ec);
×
511
    }
×
512

513
    counter_status registry::create_raw_counter(counter_info const& info,
514
        hpx::function<std::vector<std::int64_t>(bool)> const& f,
×
515
        naming::gid_type& id, error_code& ec)
516
    {
517
        // create canonical type name
518
        std::string type_name;
519
        counter_status status =
520
            get_counter_type_name(info.fullname_, type_name, ec);
521
        if (!status_is_valid(status))
×
522
            return status;
×
523

524
        auto it = locate_counter_type(type_name);
525
        if (it == countertypes_.end())
×
526
        {
×
527
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
528
                "registry::create_raw_counter", "unknown counter type {}",
×
529
                type_name);
530
            return counter_status::counter_type_unknown;
531
        }
×
532

533
        // make sure the counter type requested is supported
534
        if (!((counter_type::histogram == it->second.info_.type_ &&
535
                  counter_type::histogram == info.type_) ||
×
536
                (counter_type::raw_values == it->second.info_.type_ &&
×
537
                    counter_type::raw_values == info.type_)))
×
538
        {
×
539
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
540
                "registry::create_raw_counter",
×
541
                "invalid counter type requested (only counter_histogram or "
542
                "counter_raw_values are supported)");
543
            return counter_status::counter_type_unknown;
544
        }
×
545

546
        // make sure parent instance name is set properly
547
        counter_info complemented_info = info;
548
        complement_counter_info(complemented_info, it->second.info_, ec);
×
549
        if (ec)
×
550
            return counter_status::invalid_data;
×
551

552
        // create the counter as requested
553
        try
554
        {
555
            using counter_t = components::component<server::raw_values_counter>;
556
            id = components::server::construct<counter_t>(complemented_info, f);
557
        }
×
558
        catch (hpx::exception const& e)
559
        {
×
560
            id = naming::invalid_gid;    // reset result
561
            if (&ec == &throws)
562
                throw;
×
563
            ec = make_error_code(e.get_error(), e.what());
×
564
            LPCS_(warning).format("failed to create raw counter {} ({})",
×
565
                complemented_info.fullname_, e.what());
×
566
            return counter_status::invalid_data;
×
567
        }
568

×
569
        LPCS_(info).format(
570
            "raw counter {} created at {}", complemented_info.fullname_, id);
×
571

572
        if (&ec != &throws)
573
            ec = make_success_code();
×
574
        return counter_status::valid_data;
×
575
    }
576

×
577
    ///////////////////////////////////////////////////////////////////////////
578
    counter_status registry::create_counter(
579
        counter_info const& info, naming::gid_type& id, error_code& ec)
×
580
    {
581
        // create canonical type name
582
        std::string type_name;
583
        counter_status status =
584
            get_counter_type_name(info.fullname_, type_name, ec);
585
        if (!status_is_valid(status))
×
586
            return status;
×
587

588
        auto it = locate_counter_type(type_name);
589
        if (it == countertypes_.end())
×
590
        {
×
591
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
592
                "registry::create_counter", "unknown counter type {}",
×
593
                type_name);
594
            return counter_status::counter_type_unknown;
595
        }
×
596

597
        // make sure parent instance name is set properly
598
        counter_info complemented_info = info;
599
        complement_counter_info(complemented_info, it->second.info_, ec);
×
600
        if (ec)
×
601
            return counter_status::invalid_data;
×
602

603
        // create the counter as requested
604
        try
605
        {
606
            switch (complemented_info.type_)
607
            {
×
608
            case counter_type::elapsed_time:
609
            {
×
610
                using counter_t =
611
                    components::component<server::elapsed_time_counter>;
612
                id =
613
                    components::server::construct<counter_t>(complemented_info);
614
            }
×
615
            break;
616

617
            // NOLINTNEXTLINE(bugprone-branch-clone)
618
            case counter_type::raw:
619
                [[fallthrough]];
620
            case counter_type::monotonically_increasing:
621
                [[fallthrough]];
622
            case counter_type::aggregating:
623
                [[fallthrough]];
624
            case counter_type::average_count:
625
                [[fallthrough]];
626
            case counter_type::average_timer:
627
                HPX_THROWS_IF(ec, hpx::error::bad_parameter,
628
                    "registry::create_counter",
×
629
                    "need function parameter for raw_counter");
630
                return counter_status::counter_type_unknown;
631

×
632
            default:
633
                HPX_THROWS_IF(ec, hpx::error::bad_parameter,
634
                    "registry::create_counter",
×
635
                    "invalid counter type requested");
636
                return counter_status::counter_type_unknown;
637
            }
×
638
        }
639
        catch (hpx::exception const& e)
640
        {
×
641
            id = naming::invalid_gid;    // reset result
642
            if (&ec == &throws)
643
                throw;
×
644
            ec = make_error_code(e.get_error(), e.what());
×
645
            LPCS_(warning).format("failed to create counter {} ({})",
×
646
                complemented_info.fullname_, e.what());
×
647
            return counter_status::invalid_data;
×
648
        }
649

×
650
        LPCS_(info).format(
651
            "counter {} created at {}", complemented_info.fullname_, id);
×
652

653
        if (&ec != &throws)
654
            ec = make_success_code();
×
655
        return counter_status::valid_data;
×
656
    }
657

×
658
    /// \brief Create a new statistics performance counter instance based
659
    ///        on given base counter name and given base time interval
660
    ///        (milliseconds).
661
    counter_status registry::create_statistics_counter(counter_info const& info,
662
        std::string const& base_counter_name,
×
663
        std::vector<std::size_t> const& parameters, naming::gid_type& gid,
664
        error_code& ec)
665
    {
666
        // create canonical type name
667
        std::string type_name;
668
        counter_status status =
669
            get_counter_type_name(info.fullname_, type_name, ec);
670
        if (!status_is_valid(status))
×
671
            return status;
×
672

673
        auto it = locate_counter_type(type_name);
674
        if (it == countertypes_.end())
×
675
        {
×
676
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
677
                "registry::create_statistics_counter",
×
678
                "unknown counter type {}", type_name);
679
            return counter_status::counter_type_unknown;
680
        }
×
681

682
        // make sure the requested counter type is supported
683
        if (counter_type::aggregating != it->second.info_.type_ ||
684
            counter_type::aggregating != info.type_)
×
685
        {
×
686
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
687
                "registry::create_statistics_counter",
×
688
                "invalid counter type requested (only "
689
                "counter_type::aggregating is "
690
                "supported)");
691
            return counter_status::counter_type_unknown;
692
        }
×
693

694
        // make sure parent instance name is set properly
695
        counter_info complemented_info = info;
696
        complement_counter_info(complemented_info, it->second.info_, ec);
×
697
        if (ec)
×
698
            return counter_status::invalid_data;
×
699

700
        // split name
701
        counter_path_elements p;
702
        get_counter_path_elements(complemented_info.fullname_, p, ec);
703
        if (ec)
×
704
            return counter_status::invalid_data;
×
705

706
        // create the counter as requested
707
        try
708
        {
709
            // extract parameters
710
            std::size_t sample_interval = 1000;    // default sampling interval
711
            bool reset_base_counter = false;
×
712

×
713
            if (!parameters.empty())
714
                sample_interval = parameters[0];
×
715

×
716
            // create base counter only if it does not exist yet
717
            if (p.countername_ == "average")
718
            {
×
719
                using counter_t = hpx::components::component<
720
                    hpx::performance_counters::server::statistics_counter<
721
                        boost::accumulators::tag::mean>>;
722

723
                if (parameters.size() > 1)
724
                    reset_base_counter = parameters[1] != 0;
725

×
726
                gid = components::server::construct<counter_t>(
×
727
                    complemented_info, base_counter_name, sample_interval, 0,
728
                    reset_base_counter);
×
729
            }
×
730
            else if (p.countername_ == "stddev")
731
            {
732
                using counter_t = hpx::components::component<
×
733
                    hpx::performance_counters::server::statistics_counter<
734
                        boost::accumulators::tag::variance>>;
735

736
                if (parameters.size() > 1)
737
                    reset_base_counter = parameters[1] != 0;
738

739
                gid = components::server::construct<counter_t>(
×
740
                    complemented_info, base_counter_name, sample_interval, 0,
×
741
                    reset_base_counter);
742
            }
×
743
            else if (p.countername_ == "rolling_average")
×
744
            {
745
                using counter_t = hpx::components::component<
746
                    hpx::performance_counters::server::statistics_counter<
×
747
                        boost::accumulators::tag::rolling_mean>>;
748

749
                std::size_t window_size = 10;    // default rolling window size
750
                if (parameters.size() > 1)
751
                    window_size = parameters[1];
752

753
                if (parameters.size() > 2)
×
754
                    reset_base_counter = parameters[2] != 0;
×
755

×
756
                gid = components::server::construct<counter_t>(
757
                    complemented_info, base_counter_name, sample_interval,
×
758
                    window_size, reset_base_counter);
×
759
            }
760
            else if (p.countername_ == "rolling_stddev")
×
761
            {
762
                using counter_t = hpx::components::component<
763
                    hpx::performance_counters::server::statistics_counter<
764
                        boost::accumulators::tag::rolling_variance>>;
×
765

766
                std::size_t window_size = 10;    // default rolling window size
767
                if (parameters.size() > 1)
768
                    window_size = parameters[1];
769

770
                if (parameters.size() > 2)
771
                    reset_base_counter = parameters[2] != 0;
×
772

×
773
                gid = components::server::construct<counter_t>(
×
774
                    complemented_info, base_counter_name, sample_interval,
775
                    window_size, reset_base_counter);
×
776
            }
×
777
            else if (p.countername_ == "median")
778
            {
×
779
                using counter_t = hpx::components::component<
780
                    hpx::performance_counters::server::statistics_counter<
781
                        boost::accumulators::tag::median>>;
782

×
783
                if (parameters.size() > 1)
784
                    reset_base_counter = parameters[1] != 0;
785

786
                gid = components::server::construct<counter_t>(
787
                    complemented_info, base_counter_name, sample_interval, 0,
788
                    reset_base_counter);
789
            }
×
790
            else if (p.countername_ == "max")
×
791
            {
792
                using counter_t = hpx::components::component<
×
793
                    hpx::performance_counters::server::statistics_counter<
×
794
                        boost::accumulators::tag::max>>;
795

796
                if (parameters.size() > 1)
×
797
                    reset_base_counter = parameters[1] != 0;
798

799
                gid = components::server::construct<counter_t>(
800
                    complemented_info, base_counter_name, sample_interval, 0,
801
                    reset_base_counter);
802
            }
803
            else if (p.countername_ == "min")
×
804
            {
×
805
                using counter_t = hpx::components::component<
806
                    hpx::performance_counters::server::statistics_counter<
×
807
                        boost::accumulators::tag::min>>;
×
808

809
                if (parameters.size() > 1)
810
                    reset_base_counter = parameters[1] != 0;
×
811

812
                gid = components::server::construct<counter_t>(
813
                    complemented_info, base_counter_name, sample_interval, 0,
814
                    reset_base_counter);
815
            }
816
            else if (p.countername_ == "rolling_min")
817
            {
×
818
                using counter_t = hpx::components::component<
×
819
                    hpx::performance_counters::server::statistics_counter<
820
                        hpx::util::tag::rolling_min>>;
×
821

×
822
                std::size_t window_size = 10;    // default rolling window size
823
                if (parameters.size() > 1)
824
                    window_size = parameters[1];
×
825

826
                if (parameters.size() > 2)
827
                    reset_base_counter = parameters[2] != 0;
828

829
                gid = components::server::construct<counter_t>(
830
                    complemented_info, base_counter_name, sample_interval,
×
831
                    window_size, reset_base_counter);
×
832
            }
×
833
            else if (p.countername_ == "rolling_max")
834
            {
×
835
                using counter_t = hpx::components::component<
×
836
                    hpx::performance_counters::server::statistics_counter<
837
                        hpx::util::tag::rolling_max>>;
×
838

839
                std::size_t window_size = 10;    // default rolling window size
840
                if (parameters.size() > 1)
841
                    window_size = parameters[1];
×
842

843
                if (parameters.size() > 2)
844
                    reset_base_counter = parameters[2] != 0;
845

846
                gid = components::server::construct<counter_t>(
847
                    complemented_info, base_counter_name, sample_interval,
×
848
                    window_size, reset_base_counter);
×
849
            }
×
850
            else
851
            {
×
852
                HPX_THROWS_IF(ec, hpx::error::bad_parameter,
×
853
                    "registry::create_statistics_counter",
854
                    "invalid counter type requested: {}", p.countername_);
×
855
                return counter_status::counter_type_unknown;
856
            }
857
        }
858
        catch (hpx::exception const& e)
859
        {
860
            gid = naming::invalid_gid;    // reset result
×
861
            if (&ec == &throws)
862
                throw;
863

×
864
            ec = make_error_code(e.get_error(), e.what());
865
            LPCS_(warning).format("failed to create statistics counter {} ({})",
866
                complemented_info.fullname_, e.what());
×
867
            return counter_status::invalid_data;
868
        }
869

×
870
        LPCS_(info).format("statistics counter {} created at {}",
×
871
            complemented_info.fullname_, gid);
872

×
873
        if (&ec != &throws)
×
874
            ec = make_success_code();
×
875
        return counter_status::valid_data;
876
    }
×
877

878
    /// \brief Create a new arithmetics performance counter instance based
×
879
    ///        on given base counter names
880
    counter_status registry::create_arithmetics_counter(
881
        counter_info const& info,
×
882
        std::vector<std::string> const& base_counter_names,
×
883
        naming::gid_type& gid, error_code& ec)
884
    {
×
885
        // create canonical type name
886
        std::string type_name;
887
        counter_status status =
888
            get_counter_type_name(info.fullname_, type_name, ec);
×
889
        if (!status_is_valid(status))
890
            return status;
891

892
        auto it = locate_counter_type(type_name);
893
        if (it == countertypes_.end())
894
        {
895
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
896
                "registry::create_arithmetics_counter",
×
897
                "unknown counter type {}", type_name);
×
898
            return counter_status::counter_type_unknown;
899
        }
900

×
901
        // make sure the requested counter type is supported
×
902
        if (counter_type::aggregating != it->second.info_.type_ ||
903
            counter_type::aggregating != info.type_)
×
904
        {
905
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
906
                "registry::create_arithmetics_counter",
×
907
                "invalid counter type requested "
908
                "(only counter_type::aggregating is supported)");
909
            return counter_status::counter_type_unknown;
910
        }
×
911

×
912
        // make sure parent instance name is set properly
913
        counter_info complemented_info = info;
×
914
        complement_counter_info(complemented_info, it->second.info_, ec);
915
        if (ec)
916
            return counter_status::invalid_data;
917

×
918
        // split name
919
        counter_path_elements p;
920
        get_counter_path_elements(complemented_info.fullname_, p, ec);
921
        if (ec)
×
922
            return counter_status::invalid_data;
×
923

×
924
        // create the counter as requested
925
        try
926
        {
927
            // create base counter only if it does not exist yet
928
            if (p.countername_ == "add")
×
929
            {
×
930
                using counter_t =
931
                    hpx::components::component<hpx::performance_counters::
932
                            server::arithmetics_counter<std::plus<double>>>;
933
                gid = components::server::construct<counter_t>(
934
                    complemented_info, base_counter_names);
935
            }
936
            else if (p.countername_ == "subtract")
×
937
            {
938
                using counter_t =
939
                    hpx::components::component<hpx::performance_counters::
940
                            server::arithmetics_counter<std::minus<double>>>;
941
                gid = components::server::construct<counter_t>(
×
942
                    complemented_info, base_counter_names);
943
            }
944
            else if (p.countername_ == "multiply")
×
945
            {
946
                using counter_t = hpx::components::component<
947
                    hpx::performance_counters::server::arithmetics_counter<
948
                        std::multiplies<double>>>;
949
                gid = components::server::construct<counter_t>(
×
950
                    complemented_info, base_counter_names);
951
            }
952
            else if (p.countername_ == "divide")
×
953
            {
954
                using counter_t =
955
                    hpx::components::component<hpx::performance_counters::
956
                            server::arithmetics_counter<std::divides<double>>>;
957
                gid = components::server::construct<counter_t>(
×
958
                    complemented_info, base_counter_names);
959
            }
960
            else
×
961
            {
962
                HPX_THROWS_IF(ec, hpx::error::bad_parameter,
963
                    "registry::create_arithmetics_counter",
964
                    "invalid counter type requested: {}", p.countername_);
965
                return counter_status::counter_type_unknown;
×
966
            }
967
        }
968
        catch (hpx::exception const& e)
969
        {
970
            gid = naming::invalid_gid;    // reset result
×
971
            if (&ec == &throws)
972
                throw;
973

×
974
            ec = make_error_code(e.get_error(), e.what());
975
            LPCS_(warning).format(
976
                "failed to create aggregating counter {} ({})",
×
977
                complemented_info.fullname_, e.what());
978
            return counter_status::invalid_data;
979
        }
×
980

×
981
        LPCS_(info).format("aggregating counter {} created at {}",
982
            complemented_info.fullname_, gid);
×
983

×
984
        if (&ec != &throws)
985
            ec = make_success_code();
×
986
        return counter_status::valid_data;
987
    }
×
988

989
    /// \brief Create a new arithmetics extended performance counter instance
×
990
    ///        based on given base counter names
991
    counter_status registry::create_arithmetics_counter_extended(
992
        counter_info const& info,
×
993
        std::vector<std::string> const& base_counter_names,
×
994
        naming::gid_type& gid, error_code& ec)
995
    {
×
996
        // create canonical type name
997
        std::string type_name;
998
        counter_status status =
999
            get_counter_type_name(info.fullname_, type_name, ec);
×
1000
        if (!status_is_valid(status))
1001
            return status;
1002

1003
        auto it = locate_counter_type(type_name);
1004
        if (it == countertypes_.end())
1005
        {
1006
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
1007
                "registry::create_arithmetics_counter_extended",
×
1008
                "unknown counter type {}", type_name);
×
1009
            return counter_status::counter_type_unknown;
1010
        }
1011

×
1012
        // make sure the requested counter type is supported
×
1013
        if (counter_type::aggregating != it->second.info_.type_ ||
1014
            counter_type::aggregating != info.type_)
×
1015
        {
1016
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
1017
                "registry::create_arithmetics_counter_extended",
×
1018
                "invalid counter type requested "
1019
                "(only counter_type::aggregating is supported)");
1020
            return counter_status::counter_type_unknown;
1021
        }
×
1022

×
1023
        // make sure parent instance name is set properly
1024
        counter_info complemented_info = info;
×
1025
        complement_counter_info(complemented_info, it->second.info_, ec);
1026
        if (ec)
1027
            return counter_status::invalid_data;
1028

×
1029
        // split name
1030
        counter_path_elements p;
1031
        get_counter_path_elements(complemented_info.fullname_, p, ec);
1032
        if (ec)
×
1033
            return counter_status::invalid_data;
×
1034

×
1035
        // create the counter as requested
1036
        try
1037
        {
1038
            // create base counter only if it does not exist yet
1039
            if (p.countername_ == "mean")
×
1040
            {
×
1041
                using counter_t =
1042
                    hpx::components::component<hpx::performance_counters::
1043
                            server::arithmetics_counter_extended<
1044
                                boost::accumulators::tag::mean>>;
1045
                gid = components::server::construct<counter_t>(
1046
                    complemented_info, base_counter_names);
1047
            }
×
1048
            else if (p.countername_ == "variance")
1049
            {
1050
                using counter_t = hpx::components::component<
1051
                    performance_counters::server::arithmetics_counter_extended<
1052
                        boost::accumulators::tag::variance>>;
1053
                gid = components::server::construct<counter_t>(
×
1054
                    complemented_info, base_counter_names);
1055
            }
1056
            else if (p.countername_ == "median")
×
1057
            {
1058
                using counter_t = hpx::components::component<
1059
                    performance_counters::server::arithmetics_counter_extended<
1060
                        boost::accumulators::tag::median>>;
1061
                gid = components::server::construct<counter_t>(
1062
                    complemented_info, base_counter_names);
×
1063
            }
1064
            else if (p.countername_ == "min")
1065
            {
×
1066
                using counter_t = hpx::components::component<
1067
                    performance_counters::server::arithmetics_counter_extended<
1068
                        boost::accumulators::tag::min>>;
1069
                gid = components::server::construct<counter_t>(
1070
                    complemented_info, base_counter_names);
1071
            }
×
1072
            else if (p.countername_ == "max")
1073
            {
1074
                using counter_t = hpx::components::component<
×
1075
                    performance_counters::server::arithmetics_counter_extended<
1076
                        boost::accumulators::tag::max>>;
1077
                gid = components::server::construct<counter_t>(
1078
                    complemented_info, base_counter_names);
1079
            }
1080
            else if (p.countername_ == "count")
×
1081
            {
1082
                using counter_t = hpx::components::component<
1083
                    performance_counters::server::arithmetics_counter_extended<
×
1084
                        boost::accumulators::tag::count>>;
1085
                gid = components::server::construct<counter_t>(
1086
                    complemented_info, base_counter_names);
1087
            }
1088
            else
1089
            {
×
1090
                HPX_THROWS_IF(ec, hpx::error::bad_parameter,
1091
                    "registry::create_arithmetics_counter",
1092
                    "invalid counter type requested: {}", p.countername_);
×
1093
                return counter_status::counter_type_unknown;
1094
            }
1095
        }
1096
        catch (hpx::exception const& e)
1097
        {
1098
            gid = naming::invalid_gid;    // reset result
×
1099
            if (&ec == &throws)
1100
                throw;
1101

1102
            ec = make_error_code(e.get_error(), e.what());
1103
            LPCS_(warning).format(
×
1104
                "failed to create aggregating counter {} ({})",
1105
                complemented_info.fullname_, e.what());
1106
            return counter_status::invalid_data;
×
1107
        }
1108

1109
        LPCS_(info).format("aggregating counter {} created at {}",
×
1110
            complemented_info.fullname_, gid);
1111

1112
        if (&ec != &throws)
×
1113
            ec = make_success_code();
×
1114
        return counter_status::valid_data;
1115
    }
×
1116

×
1117
    ///////////////////////////////////////////////////////////////////////////
1118
    /// \brief Add an existing performance counter instance to the registry
×
1119
    counter_status registry::add_counter(
1120
        hpx::id_type const& id, counter_info const& info, error_code& ec)
×
1121
    {
1122
        // complement counter info data
×
1123
        counter_info complemented_info = info;
1124
        complement_counter_info(complemented_info, ec);
1125
        if (ec)
×
1126
            return counter_status::invalid_data;
×
1127

1128
        // create canonical type name
×
1129
        std::string type_name;
1130
        counter_status status =
1131
            get_counter_type_name(complemented_info.fullname_, type_name, ec);
1132
        if (!status_is_valid(status))
×
1133
            return status;
1134

1135
        // make sure the type of the new counter is known to the registry
1136
        auto it = locate_counter_type(type_name);
×
1137
        if (it == countertypes_.end())
×
1138
        {
×
1139
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
1140
                "registry::add_counter", "unknown counter type {}", type_name);
1141
            return counter_status::counter_type_unknown;
1142
        }
1143

1144
        // register the canonical name with AGAS
×
1145
        std::string name(complemented_info.fullname_);
×
1146
        ensure_counter_prefix(name);    // pre-pend prefix, if necessary
1147
        agas::register_name(launch::sync, name, id, ec);
1148
        if (ec)
1149
            return counter_status::invalid_data;
×
1150

×
1151
        if (&ec != &throws)
1152
            ec = make_success_code();
×
1153
        return counter_status::valid_data;
1154
    }
×
1155

1156
    ///////////////////////////////////////////////////////////////////////////
1157
    counter_status registry::remove_counter(
1158
        counter_info const& info, hpx::id_type const& /* id */, error_code& ec)
1159
    {
×
1160
        // make sure parent instance name is set properly
×
1161
        counter_info complemented_info = info;
×
1162
        complement_counter_info(complemented_info, ec);
1163
        if (ec)
1164
            return counter_status::invalid_data;
×
1165

×
1166
        // create canonical name for the counter
1167
        std::string name;
×
1168
        counter_status status =
1169
            get_counter_name(complemented_info.fullname_, name, ec);
1170
        if (!status_is_valid(status))
×
1171
            return status;
1172

1173
        // unregister this counter from AGAS
1174
        ensure_counter_prefix(name);    // pre-pend prefix, if necessary
×
1175
        agas::unregister_name(launch::sync, name, ec);
×
1176
        if (ec)
×
1177
        {
1178
            LPCS_(warning).format(
1179
                "failed to remove counter {}", complemented_info.fullname_);
1180
            return counter_status::invalid_data;
1181
        }
1182

×
1183
        return counter_status::valid_data;
×
1184
    }
1185

1186
    ///////////////////////////////////////////////////////////////////////////
1187
    /// \brief Retrieve counter type information for given counter name
×
1188
    counter_status registry::get_counter_type(
×
1189
        std::string const& name, counter_info& info, error_code& ec)
×
1190
    {
1191
        // create canonical type name
×
1192
        std::string type_name;
1193
        counter_status status = get_counter_type_name(name, type_name, ec);
×
1194
        if (!status_is_valid(status))
1195
            return status;
1196

1197
        // make sure the type of the counter is known to the registry
×
1198
        auto it = locate_counter_type(type_name);
1199
        if (it == countertypes_.end())
1200
        {
1201
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
×
1202
                "registry::get_counter_type", "unknown counter type {}",
1203
                type_name);
1204
            return counter_status::counter_type_unknown;
1205
        }
1206

×
1207
        info = it->second.info_;
×
1208

1209
        if (&ec != &throws)
1210
            ec = make_success_code();
1211
        return counter_status::valid_data;
×
1212
    }
×
1213

1214
    registry& registry::instance()
×
1215
    {
1216
        static registry instance_;
1217
        return instance_;
×
1218
    }
1219

1220
}}    // namespace hpx::performance_counters
×
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