• 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

8.89
/components/parcel_plugins/coalescing/src/performance_counters.cpp
1
//  Copyright (c) 2016-2025 Hartmut Kaiser
2
//
3
//  SPDX-License-Identifier: BSL-1.0
4
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
5
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6

7
#include <hpx/config.hpp>
8

9
#if defined(HPX_HAVE_NETWORKING) && defined(HPX_HAVE_PARCEL_COALESCING)
10
#include <hpx/modules/errors.hpp>
11
#include <hpx/modules/format.hpp>
12
#include <hpx/modules/functional.hpp>
13
#include <hpx/modules/runtime_local.hpp>
14
#include <hpx/modules/string_util.hpp>
15

16
#include <hpx/components_base/component_startup_shutdown.hpp>
17
#include <hpx/naming_base/id_type.hpp>
18
#include <hpx/parcel_coalescing/counter_registry.hpp>
19
#include <hpx/performance_counters/counter_creators.hpp>
20
#include <hpx/performance_counters/counters.hpp>
21
#include <hpx/performance_counters/manage_counter_type.hpp>
22

23
#include <cstdint>
24
#include <exception>
25
#include <string>
26
#include <utility>
27
#include <vector>
28

29
namespace hpx::plugins::parcel {
30

31
    ///////////////////////////////////////////////////////////////////////////
32
    // Discoverer for the explicit (hand-rolled performance counter. The
33
    // purpose of this function is to invoke the supplied function f for all
34
    // allowed counter instance names supported by the counter type this
35
    // function has been registered with.
×
36
    bool counter_discoverer(hpx::performance_counters::counter_info const& info,
37
        hpx::performance_counters::discover_counter_func const& f,
38
        hpx::performance_counters::discover_counters_mode mode,
39
        hpx::error_code& ec)
40
    {
41
        // compose the counter name templates
42
        performance_counters::counter_path_elements p;
43
        performance_counters::counter_status status =
×
44
            get_counter_path_elements(info.fullname_, p, ec);
×
45
        if (!status_is_valid(status))
46
            return false;
47

48
        bool result =
×
49
            coalescing_counter_registry::instance().counter_discoverer(
50
                info, p, f, mode, ec);
×
51
        if (!result || ec)
52
            return false;
53

×
54
        if (&ec != &throws)
×
55
            ec = make_success_code();
56

57
        return true;
×
58
    }
59

60
    ///////////////////////////////////////////////////////////////////////////
61
    // Creation function for explicit sine performance counter. It's purpose is
62
    // to create and register a new instance of the given name (or reuse an
63
    // existing instance).
×
64
    struct num_parcels_counter_surrogate
65
    {
×
66
        explicit num_parcels_counter_surrogate(std::string const& parameters)
×
67
          : parameters_(parameters)
68
        {
×
69
        }
70

×
71
        std::int64_t operator()(bool reset)
72
        {
×
73
            if (counter_.empty())
74
            {
75
                counter_ =
×
76
                    coalescing_counter_registry::instance().get_parcels_counter(
×
77
                        parameters_);
×
78
                if (counter_.empty())
79
                    return 0;    // no counter available yet
80
            }
81

82
            // dispatch to actual counter
×
83
            return counter_(reset);
84
        }
85

86
        hpx::function<std::int64_t(bool)> counter_;
87
        std::string parameters_;
88
    };
89

×
90
    hpx::naming::gid_type num_parcels_counter_creator(
91
        hpx::performance_counters::counter_info const& info,
92
        hpx::error_code& ec)
93
    {
×
94
        if (info.type_ !=
95
            performance_counters::counter_type::monotonically_increasing)
96
        {
97
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
98
                "num_parcels_counter_creator",
×
99
                "invalid counter type requested");
×
100
            return naming::invalid_gid;
×
101
        }
102

103
        performance_counters::counter_path_elements paths;
×
104
        performance_counters::get_counter_path_elements(
105
            info.fullname_, paths, ec);
×
106
        if (ec)
107
            return naming::invalid_gid;
108

109
        if (paths.parentinstance_is_basename_)
110
        {
111
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
112
                "num_parcels_counter_creator",
×
113
                "invalid counter name for number of parcels (instance "
114
                "name must not be a valid base counter name)");
×
115
            return naming::invalid_gid;
116
        }
117

118
        if (paths.parameters_.empty())
119
        {
120
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
121
                "num_parcels_counter_creator",
122
                "invalid counter parameter for number of parcels: must "
123
                "specify an action type");
×
124
            return naming::invalid_gid;
×
125
        }
126

×
127
        // ask registry
128
        hpx::function<std::int64_t(bool)> f =
129
            coalescing_counter_registry::instance().get_parcels_counter(
×
130
                paths.parameters_);
131

132
        if (!f.empty())
133
        {
134
            return performance_counters::detail::create_raw_counter(
×
135
                info, HPX_MOVE(f), ec);
×
136
        }
137

138
        // the counter is not available yet, create surrogate function
139
        return performance_counters::detail::create_raw_counter(
×
140
            info, num_parcels_counter_surrogate(paths.parameters_), ec);
141
    }
142

143
    ///////////////////////////////////////////////////////////////////////////
144
    struct num_messages_counter_surrogate
145
    {
146
        explicit num_messages_counter_surrogate(std::string const& parameters)
147
          : parameters_(parameters)
×
148
        {
149
        }
×
150

×
151
        std::int64_t operator()(bool reset)
152
        {
×
153
            if (counter_.empty())
154
            {
×
155
                counter_ = coalescing_counter_registry::instance()
156
                               .get_messages_counter(parameters_);
×
157
                if (counter_.empty())
158
                    return 0;    // no counter available yet
×
159
            }
×
160

×
161
            // dispatch to actual counter
162
            return counter_(reset);
163
        }
164

165
        hpx::function<std::int64_t(bool)> counter_;
×
166
        std::string parameters_;
167
    };
168

169
    hpx::naming::gid_type num_messages_counter_creator(
170
        hpx::performance_counters::counter_info const& info,
171
        hpx::error_code& ec)
172
    {
×
173
        if (info.type_ !=
174
            performance_counters::counter_type::monotonically_increasing)
175
        {
176
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
×
177
                "num_messages_counter_creator",
178
                "invalid counter type requested");
179
            return naming::invalid_gid;
180
        }
181

×
182
        performance_counters::counter_path_elements paths;
×
183
        performance_counters::get_counter_path_elements(
×
184
            info.fullname_, paths, ec);
185
        if (ec)
186
            return naming::invalid_gid;
×
187

188
        if (paths.parentinstance_is_basename_)
×
189
        {
190
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
191
                "num_messages_counter_creator",
192
                "invalid counter name for number of parcels (instance "
193
                "name must not be a valid base counter name)");
194
            return naming::invalid_gid;
195
        }
×
196

197
        if (paths.parameters_.empty())
×
198
        {
199
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
200
                "num_messages_counter_creator",
201
                "invalid counter parameter for number of parcels: must "
202
                "specify an action type");
203
            return naming::invalid_gid;
204
        }
205

206
        // ask registry
×
207
        hpx::function<std::int64_t(bool)> f =
×
208
            coalescing_counter_registry::instance().get_messages_counter(
209
                paths.parameters_);
×
210

211
        if (!f.empty())
212
        {
×
213
            return performance_counters::detail::create_raw_counter(
214
                info, HPX_MOVE(f), ec);
215
        }
216

217
        // the counter is not available yet, create surrogate function
×
218
        return performance_counters::detail::create_raw_counter(
×
219
            info, num_messages_counter_surrogate(paths.parameters_), ec);
220
    }
221

222
    ///////////////////////////////////////////////////////////////////////////
×
223
    struct num_parcels_per_message_counter_surrogate
224
    {
225
        explicit num_parcels_per_message_counter_surrogate(
226
            std::string const& parameters)
227
          : parameters_(parameters)
228
        {
229
        }
230

×
231
        std::int64_t operator()(bool reset)
232
        {
×
233
            if (counter_.empty())
234
            {
×
235
                counter_ = coalescing_counter_registry::instance()
236
                               .get_parcels_per_message_counter(parameters_);
×
237
                if (counter_.empty())
238
                    return 0;    // no counter available yet
×
239
            }
240

×
241
            // dispatch to actual counter
242
            return counter_(reset);
×
243
        }
×
244

×
245
        hpx::function<std::int64_t(bool)> counter_;
246
        std::string parameters_;
247
    };
248

249
    hpx::naming::gid_type num_parcels_per_message_counter_creator(
×
250
        hpx::performance_counters::counter_info const& info,
251
        hpx::error_code& ec)
252
    {
253
        if (info.type_ != performance_counters::counter_type::average_count)
254
        {
255
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
256
                "num_parcels_per_message_counter_creator",
×
257
                "invalid counter type requested");
258
            return naming::invalid_gid;
259
        }
260

×
261
        performance_counters::counter_path_elements paths;
262
        performance_counters::get_counter_path_elements(
263
            info.fullname_, paths, ec);
264
        if (ec)
265
            return naming::invalid_gid;
×
266

×
267
        if (paths.parentinstance_is_basename_)
×
268
        {
269
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
270
                "num_parcels_per_message_counter_creator",
×
271
                "invalid counter name for number of parcels (instance "
272
                "name must not be a valid base counter name)");
×
273
            return naming::invalid_gid;
274
        }
275

276
        if (paths.parameters_.empty())
277
        {
278
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
279
                "num_parcels_per_message_counter_creator",
×
280
                "invalid counter parameter for number of parcels: must "
281
                "specify an action type");
×
282
            return naming::invalid_gid;
283
        }
284

285
        // ask registry
286
        hpx::function<std::int64_t(bool)> f =
287
            coalescing_counter_registry::instance()
288
                .get_parcels_per_message_counter(paths.parameters_);
289

290
        if (!f.empty())
×
291
        {
×
292
            return performance_counters::detail::create_raw_counter(
293
                info, HPX_MOVE(f), ec);
×
294
        }
295

296
        // the counter is not available yet, create surrogate function
×
297
        return performance_counters::detail::create_raw_counter(info,
298
            num_parcels_per_message_counter_surrogate(paths.parameters_), ec);
299
    }
300

301
    ///////////////////////////////////////////////////////////////////////////
×
302
    struct average_time_between_parcels_counter_surrogate
×
303
    {
×
304
        explicit average_time_between_parcels_counter_surrogate(
305
            std::string const& parameters)
306
          : parameters_(parameters)
307
        {
×
308
        }
309

310
        std::int64_t operator()(bool reset)
311
        {
312
            if (counter_.empty())
313
            {
314
                counter_ =
315
                    coalescing_counter_registry::instance()
×
316
                        .get_average_time_between_parcels_counter(parameters_);
317
                if (counter_.empty())
×
318
                    return 0;    // no counter available yet
319
            }
×
320

321
            // dispatch to actual counter
×
322
            return counter_(reset);
323
        }
×
324

325
        hpx::function<std::int64_t(bool)> counter_;
×
326
        std::string parameters_;
327
    };
328

×
329
    hpx::naming::gid_type average_time_between_parcels_counter_creator(
×
330
        hpx::performance_counters::counter_info const& info,
×
331
        hpx::error_code& ec)
332
    {
333
        if (info.type_ != performance_counters::counter_type::average_timer)
334
        {
335
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
×
336
                "average_time_between_parcels_counter_creator",
337
                "invalid counter type requested");
338
            return naming::invalid_gid;
339
        }
340

341
        performance_counters::counter_path_elements paths;
342
        performance_counters::get_counter_path_elements(
×
343
            info.fullname_, paths, ec);
344
        if (ec)
345
            return naming::invalid_gid;
346

×
347
        if (paths.parentinstance_is_basename_)
348
        {
349
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
350
                "average_time_between_parcels_counter_creator",
351
                "invalid counter name for number of parcels (instance "
×
352
                "name must not be a valid base counter name)");
×
353
            return naming::invalid_gid;
×
354
        }
355

356
        if (paths.parameters_.empty())
×
357
        {
358
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
×
359
                "average_time_between_parcels_counter_creator",
360
                "invalid counter parameter for number of parcels: must "
361
                "specify an action type");
362
            return naming::invalid_gid;
363
        }
364

365
        // ask registry
×
366
        hpx::function<std::int64_t(bool)> f =
367
            coalescing_counter_registry::instance()
×
368
                .get_average_time_between_parcels_counter(paths.parameters_);
369

370
        if (!f.empty())
371
        {
372
            return performance_counters::detail::create_raw_counter(
373
                info, HPX_MOVE(f), ec);
374
        }
375

376
        // the counter is not available yet, create surrogate function
×
377
        return performance_counters::detail::create_raw_counter(info,
378
            average_time_between_parcels_counter_surrogate(paths.parameters_),
×
379
            ec);
380
    }
×
381

382
    ///////////////////////////////////////////////////////////////////////////
383
    struct time_between_parcels_histogram_counter_surrogate
×
384
    {
385
        time_between_parcels_histogram_counter_surrogate(
386
            std::string const& action_name, std::int64_t min_boundary,
387
            std::int64_t max_boundary, std::int64_t num_buckets)
388
          : action_name_(action_name)
×
389
          , min_boundary_(min_boundary)
390
          , max_boundary_(max_boundary)
×
391
          , num_buckets_(num_buckets)
×
392
        {
393
        }
394

395
        time_between_parcels_histogram_counter_surrogate(
×
396
            time_between_parcels_histogram_counter_surrogate const& rhs)
397
          : counter_(rhs.counter_)
398
          , action_name_(rhs.action_name_)
399
          , min_boundary_(rhs.min_boundary_)
400
          , max_boundary_(rhs.max_boundary_)
401
          , num_buckets_(rhs.num_buckets_)
402
        {
403
        }
×
404

405
        time_between_parcels_histogram_counter_surrogate& operator=(
×
406
            time_between_parcels_histogram_counter_surrogate const& rhs)
407
        {
408
            counter_ = rhs.counter_;
×
409
            action_name_ = rhs.action_name_;
×
410
            min_boundary_ = rhs.min_boundary_;
×
411
            max_boundary_ = rhs.max_boundary_;
×
412
            num_buckets_ = rhs.num_buckets_;
413
            return *this;
×
414
        }
415

×
416
        std::vector<std::int64_t> operator()(bool reset)
417
        {
×
418
            {
×
419
                std::lock_guard<hpx::spinlock> l(mtx_);
×
420
                if (counter_.empty())
×
421
                {
×
422
                    counter_ = coalescing_counter_registry::instance()
423
                                   .get_time_between_parcels_histogram_counter(
×
424
                                       action_name_, min_boundary_,
425
                                       max_boundary_, num_buckets_);
426

427
                    // no counter available yet
428
                    if (counter_.empty())
429
                        return coalescing_counter_registry::empty_histogram(
430
                            reset);
431
                }
432
            }
433

434
            // dispatch to actual counter
435
            return counter_(reset);
436
        }
×
437

438
        hpx::spinlock mtx_;
439
        hpx::function<std::vector<std::int64_t>(bool)> counter_;
×
440
        std::string action_name_;
×
441
        std::int64_t min_boundary_;
442
        std::int64_t max_boundary_;
×
443
        std::int64_t num_buckets_;
×
444
    };
×
445

446
    hpx::naming::gid_type time_between_parcels_histogram_counter_creator(
447
        hpx::performance_counters::counter_info const& info,
448
        hpx::error_code& ec)
×
449
    {
450
        if (info.type_ != performance_counters::counter_type::histogram)
451
        {
452
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
453
                "time_between_parcels_histogram_counter_creator",
454
                "invalid counter type requested");
455
            return naming::invalid_gid;
×
456
        }
457

458
        performance_counters::counter_path_elements paths;
459
        performance_counters::get_counter_path_elements(
460
            info.fullname_, paths, ec);
461
        if (ec)
462
            return naming::invalid_gid;
463

464
        if (paths.parentinstance_is_basename_)
465
        {
466
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
×
467
                "time_between_parcels_histogram_counter_creator",
468
                "invalid counter name for "
469
                "time-between-parcels histogram (instance "
470
                "name must not be a valid base counter name)");
×
471
            return naming::invalid_gid;
472
        }
473

474
        if (paths.parameters_.empty())
475
        {
×
476
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
×
477
                "time_between_parcels_histogram_counter_creator",
×
478
                "invalid counter parameter for "
479
                "time-between-parcels histogram: must "
480
                "specify an action type");
×
481
            return naming::invalid_gid;
482
        }
×
483

484
        // split parameters, extract separate values
485
        std::vector<std::string> params;
486
        hpx::string_util::split(params, paths.parameters_,
487
            hpx::string_util::is_any_of(","),
488
            hpx::string_util::token_compress_mode::off);
489

490
        std::int64_t min_boundary = 0;
×
491
        std::int64_t max_boundary = 1000000;    // 1ms
492
        std::int64_t num_buckets = 20;
×
493

494
        if (params.empty() || params[0].empty())
495
        {
496
            HPX_THROWS_IF(ec, hpx::error::bad_parameter,
497
                "time_between_parcels_histogram_counter_creator",
498
                "invalid counter parameter for "
499
                "time-between-parcels histogram: "
500
                "must specify an action type");
501
            return naming::invalid_gid;
×
502
        }
×
503

×
504
        if (params.size() > 1 && !params[1].empty())
505
            min_boundary = util::from_string<std::int64_t>(params[1]);
506
        if (params.size() > 2 && !params[2].empty())
507
            max_boundary = util::from_string<std::int64_t>(params[2]);
508
        if (params.size() > 3 && !params[3].empty())
509
            num_buckets = util::from_string<std::int64_t>(params[3]);
510

×
511
        // ask registry
512
        hpx::function<std::vector<std::int64_t>(bool)> f =
×
513
            coalescing_counter_registry::instance()
514
                .get_time_between_parcels_histogram_counter(
515
                    params[0], min_boundary, max_boundary, num_buckets);
516

517
        if (!f.empty())
518
        {
519
            return performance_counters::detail::create_raw_counter(
520
                info, HPX_MOVE(f), ec);
×
521
        }
×
522

×
523
        // the counter is not available yet, create surrogate function
×
524
        return performance_counters::detail::create_raw_counter(info,
×
525
            time_between_parcels_histogram_counter_surrogate(
×
526
                params[0], min_boundary, max_boundary, num_buckets),
527
            ec);
528
    }
529

×
530
    ///////////////////////////////////////////////////////////////////////////
531
    // This function will be registered as a startup function for HPX below.
×
532
    //
533
    // That means it will be executed in a HPX-thread before hpx_main, but after
×
534
    // the runtime has been initialized and started.
535
    void startup()
536
    {
×
537
        using namespace hpx::performance_counters;
538

539
        // define the counter types
540
        generic_counter_type_data const counter_types[] = {
541
            // /coalescing(locality#<locality_id>/total)/count/parcels@action-name
×
542
            {"/coalescing/count/parcels",
543
                counter_type::monotonically_increasing,
×
544
                "returns the number of parcels handled by the message handler "
×
545
                "associated with the action which is given by the counter "
546
                "parameter",
547
                HPX_PERFORMANCE_COUNTER_V1, &num_parcels_counter_creator,
548
                &counter_discoverer, ""},
×
549
            // /coalescing(locality#<locality_id>/total)/count/messages@action-name
550
            {"/coalescing/count/messages",
551
                counter_type::monotonically_increasing,
552
                "returns the number of messages creates as the result of "
553
                "coalescing parcels of the action which is given by the "
554
                "counter "
555
                "parameter",
556
                HPX_PERFORMANCE_COUNTER_V1, &num_messages_counter_creator,
557
                &counter_discoverer, ""},
558
            // /coalescing(...)/count/average-parcels-per-message@action-name
559
            {"/coalescing/count/average-parcels-per-message",
560
                counter_type::average_count,
32✔
561
                "returns the average number of parcels sent in a message "
562
                "generated by the message handler associated with the action "
563
                "which is given by the counter parameter",
564
                HPX_PERFORMANCE_COUNTER_V1,
565
                &num_parcels_per_message_counter_creator, &counter_discoverer,
566
                ""},
567
            // /coalescing(...)/time/between-parcels-average@action-name
568
            {"/coalescing/time/between-parcels-average",
569
                counter_type::average_timer,
570
                "returns the average time between parcels for the "
571
                "action which is given by the counter parameter",
572
                HPX_PERFORMANCE_COUNTER_V1,
32✔
573
                &average_time_between_parcels_counter_creator,
32✔
574
                &counter_discoverer, "ns"},
575
            // /coalescing(...)/time/between-parcels-histogram@action-name,min,max,buckets
576
            {"/coalescing/time/between-parcels-histogram",
577
                counter_type::histogram,
578
                "returns the histogram for the times between parcels for "
579
                "the action which is given by the counter parameter",
580
                HPX_PERFORMANCE_COUNTER_V1,
581
                &time_between_parcels_histogram_counter_creator,
32✔
582
                &counter_discoverer, "ns/0.1%"}};
32✔
583

584
        // Install the counter types, un-installation of the types is handled
585
        // automatically.
586
        install_counter_types(counter_types, std::size(counter_types));
587
    }
588

589
    ///////////////////////////////////////////////////////////////////////////
590
    bool get_startup(
32✔
591
        hpx::startup_function_type& startup_func, bool& pre_startup)
592
    {
593
        // return our startup-function if performance counters are required
594
        startup_func = startup;    // function to run during startup
595
        pre_startup = true;        // run 'startup' as pre-startup function
596
        return true;
597
    }
598
}    // namespace hpx::plugins::parcel
32✔
599

32✔
600
///////////////////////////////////////////////////////////////////////////////
601
// Register a startup function which will be called as a HPX-thread during
602
// runtime startup. We use this function to register our performance counter
603
// type and performance counter instances.
604
//
605
// Note that this macro can be used not more than once in one module.
606
HPX_REGISTER_STARTUP_MODULE_DYNAMIC(hpx::plugins::parcel::get_startup)
32✔
607

192✔
608
#endif
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