• 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

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

7
#include <hpx/config.hpp>
8
#include <hpx/assert.hpp>
9
#include <hpx/async_distributed/continuation.hpp>
10
#include <hpx/components_base/agas_interface.hpp>
11
#include <hpx/modules/async_base.hpp>
12
#include <hpx/modules/async_combinators.hpp>
13
#include <hpx/modules/errors.hpp>
14
#include <hpx/modules/format.hpp>
15
#include <hpx/modules/functional.hpp>
16
#include <hpx/modules/runtime_local.hpp>
17
#include <hpx/modules/thread_support.hpp>
18
#include <hpx/modules/threading_base.hpp>
19
#include <hpx/modules/timing.hpp>
20
#include <hpx/modules/type_support.hpp>
21
#include <hpx/performance_counters/apex_sample_value.hpp>
22
#include <hpx/performance_counters/counters.hpp>
23
#include <hpx/performance_counters/performance_counter.hpp>
24
#include <hpx/performance_counters/query_counters.hpp>
25

26
#include <cstddef>
27
#include <cstdint>
28
#include <fstream>
29
#include <iostream>
30
#include <mutex>
31
#include <sstream>
32
#include <string>
33
#include <utility>
34
#include <vector>
35

36
#if HPX_HAVE_ITTNOTIFY != 0 && !defined(HPX_HAVE_APEX)
37
#include <hpx/itt_notify/detail/use_ittnotify_api.hpp>
38
#include <hpx/modules/itt_notify.hpp>
39
#include <map>
40
#endif
41

42
#include <hpx/config/warnings_prefix.hpp>
43

44
namespace hpx::util {
×
45

46
    query_counters::query_counters(std::vector<std::string> const& names,
47
        std::vector<std::string> const& reset_names, std::int64_t interval,
48
        std::string const& dest, std::string const& form,
×
49
        std::vector<std::string> const& shortnames, bool csv_header,
×
50
        bool print_counters_locally, bool counter_types)
×
51
      : names_(names)
×
52
      , reset_names_(reset_names)
×
53
      , counters_(print_counters_locally)
×
54
      , destination_(dest)
×
55
      , format_(form)
×
56
      , counter_shortnames_(shortnames)
×
57
      , csv_header_(csv_header)
×
58
      , print_counters_locally_(print_counters_locally)
×
59
      , counter_types_(counter_types)
60
      , timer_(hpx::bind_front(&query_counters::evaluate, this_(), false),
×
61
            hpx::bind_front(&query_counters::terminate, this_()),
62
            interval * 1000, "query_counters", true)
63
    {
×
64
        // add counter prefix, if necessary
65
        for (std::string& name : names_)
×
66
        {
67
            performance_counters::ensure_counter_prefix(name);
×
68
        }
69
        for (std::string& name : reset_names_)
×
70
        {
71
            performance_counters::ensure_counter_prefix(name);
×
72
        }
73
    }
×
74

75
    query_counters::~query_counters()
×
76
    {
×
77
        counters_.release();
78
    }
×
79

80
    void query_counters::find_counters()
×
81
    {
×
82
        if (!names_.empty())
×
83
            counters_.add_counters(names_);
×
84
        if (!reset_names_.empty())
85
            counters_.add_counters(reset_names_, true);
86

87
#if HPX_HAVE_ITTNOTIFY != 0 && !defined(HPX_HAVE_APEX)
88
        if (use_ittnotify_api)
89
        {
90
            typedef std::map<std::string, util::itt::counter>::value_type
91
                value_type;
92

93
            for (auto const& info : counters_.get_counter_infos())
94
            {
95
                std::string real_name =
96
                    performance_counters::remove_counter_prefix(info.fullname_);
97
                itt_counters_.insert(value_type(info.fullname_,
98
                    util::itt::counter(real_name.c_str(),
99
                        hpx::get_thread_name().c_str(),
100
                        __itt_metadata_double)));
101
            }
102
        }
×
103
#endif
104
    }
×
105

106
    void query_counters::start()
107
    {
108
#if defined(HPX_GCC_VERSION) && HPX_GCC_VERSION >= 110000
109
#pragma GCC diagnostic push
110
#pragma GCC diagnostic ignored "-Wrestrict"
×
111
#endif
112
        if (print_counters_locally_ && destination_ != "cout")
×
113
        {
114
            destination_ += "." + std::to_string(hpx::get_locality_id());
115
        }
116
#if defined(HPX_GCC_VERSION) && HPX_GCC_VERSION >= 110000
117
#pragma GCC diagnostic pop
118
#endif
×
119

120
        find_counters();
×
121

122
        counters_.start(launch::sync);
123

124
        // this will invoke the evaluate function for the first time
×
125
        timer_.start();
126
    }
×
127

128
    void query_counters::stop_evaluating_counters(bool terminate)
×
129
    {
×
130
        timer_.stop(terminate);
×
131
        counters_.stop(launch::sync);
132
    }
133

134
    ///////////////////////////////////////////////////////////////////////////
135
    namespace strings {
136

137
        constexpr char const* counter_type_short_names[] = {
138
            "counter_type::text",
139
            "counter_type::raw",
140
            "counter_type::monotonically_increasing",
141
            "counter_type::average_base",
142
            "counter_type::average_count",
143
            "counter_type::aggregated",
144
            "counter_type::average_timer",
145
            "counter_type::elapsed_time",
146
            "counter_type::histogram",
147
            "counter_type::raw_values",
148
        };
149
    }
×
150

151
    char const* get_counter_short_type_name(
152
        performance_counters::counter_type type)
×
153
    {
154
        if (type < performance_counters::counter_type::text ||
155
            type > performance_counters::counter_type::raw_values)
156
        {
157
            return "unknown";
×
158
        }
159
        return strings::counter_type_short_names[static_cast<int>(type)];
160
    }
161

×
162
    template <typename Stream>
163
    void query_counters::print_name_csv(Stream& out, std::string const& name)
×
164
    {
×
165
        std::string s = performance_counters::remove_counter_prefix(name);
×
166
        if (s.find_first_of(',') != std::string::npos)
167
            out << "\"" << s << "\"";
×
168
        else
×
169
            out << s;
170
    }
171

×
172
    template <typename Stream>
173
    void query_counters::print_value(Stream* out,
174
        performance_counters::counter_info const& info,
175
        performance_counters::counter_value const& value)
×
176
    {
177
        std::string const& name = info.fullname_;
178
        std::string const& uom = info.unit_of_measure_;
179

×
180
        error_code ec(throwmode::lightweight);    // do not throw
181
        double val = value.get_value<double>(ec);
×
182

183
        if (!ec)
184
        {
185
#ifdef HPX_HAVE_APEX
186
            external_timer::sample_value(info, val);
187
#elif HPX_HAVE_ITTNOTIFY != 0
188
            if (use_ittnotify_api)
189
            {
190
                auto it = itt_counters_.find(name);
191
                if (it != itt_counters_.end())
192
                {
193
                    (*it).second.set_value(val);
194
                }
195
            }
196
#endif
×
197

×
198
            if (out == nullptr)
199
                return;
×
200

×
201
            print_name_csv(*out, name);
202
            *out << "," << value.count_ << ",";
×
203

×
204
            double const elapsed = static_cast<double>(value.time_) * 1e-9;
×
205
            *out << hpx::util::format("{:.6}", elapsed) << ",[s]," << val;
×
206
            if (!uom.empty())
207
                *out << ",[" << uom << "]";
×
208

209
            if (counter_types_)
×
210
            {
×
211
                if (uom.empty())
×
212
                    *out << ",[]";
213
                *out << "," << get_counter_short_type_name(info.type_);
×
214
            }
215
            *out << "\n";
216
        }
217
        else
×
218
        {
×
219
            if (out != nullptr)
220
                *out << "invalid\n";
221
        }
222
    }
223

×
224
    template <typename Stream>
225
    void query_counters::print_value(Stream* out,
226
        performance_counters::counter_info const& info,
227
        performance_counters::counter_values_array const& value)
×
228
    {
×
229
        if (out == nullptr)
230
            return;
×
231

232
        std::string const& name = info.fullname_;
233
        std::string const& uom = info.unit_of_measure_;
234

235
        error_code ec(throwmode::lightweight);    // do not throw
×
236

×
237
        print_name_csv(*out, name);
238
        *out << "," << value.count_ << ",";
×
239

×
240
        double const elapsed = static_cast<double>(value.time_) * 1e-9;
241
        *out << hpx::util::format("{:.6}", elapsed) << ",[s],";
242

×
243
        bool first = true;
244
        for (std::int64_t val : value.values_)
×
245
        {
×
246
            if (!first)
247
                *out << ':';
248
            first = false;
249
            *out << val;
250
        }
×
251

×
252
        if (!uom.empty())
253
            *out << ",[" << uom << "]";
×
254

255
        if (counter_types_)
×
256
        {
×
257
            if (uom.empty())
×
258
                *out << ",[]";
259
            *out << "," << get_counter_short_type_name(info.type_);
×
260
        }
261
        *out << "\n";
262
    }
263

×
264
    template <typename Stream>
265
    void query_counters::print_value_csv(Stream* out,
266
        performance_counters::counter_info const& info,
267
        performance_counters::counter_value const& value)
268
    {
×
269
        error_code ec(throwmode::lightweight);
270
        double val = value.get_value<double>(ec);
×
271

272
        if (!ec)
273
        {
274
#ifdef HPX_HAVE_APEX
275
            external_timer::sample_value(info, val);
276
#elif HPX_HAVE_ITTNOTIFY != 0
277
            if (use_ittnotify_api)
278
            {
279
                auto it = itt_counters_.find(info.fullname_);
280
                if (it != itt_counters_.end())
281
                {
282
                    (*it).second.set_value(val);
283
                }
284
            }
285
#else
286
            HPX_UNUSED(info);
×
287
#endif
288
            if (out == nullptr)
289
                return;
×
290

291
            *out << val;
292
        }
293
        else
×
294
        {
×
295
            if (out != nullptr)
296
                *out << "invalid";
297
        }
298
    }
299

×
300
    template <typename Stream>
301
    void query_counters::print_value_csv(Stream* out,
302
        performance_counters::counter_info const& /* info */,
303
        performance_counters::counter_values_array const& value)
×
304
    {
305
        if (out == nullptr)
306
            return;
307

×
308
        bool first = true;
309
        for (std::int64_t val : value.values_)
×
310
        {
×
311
            if (!first)
312
                *out << ':';
×
313
            first = false;
314
            *out << val;
315
        }
316
    }
317

318
    template <typename Stream>
319
    void query_counters::print_name_csv_short(
320
        Stream& out, std::string const& name)
×
321
    {
×
322
        out << name;
323
    }
324

×
325
    template <typename Stream>
326
    void query_counters::print_headers(Stream& output,
327
        std::vector<performance_counters::counter_info> const& infos)
×
328
    {
329
        if (csv_header_)
×
330
        {
331
            if (format_ == "csv")
332
            {
333
                // first print raw value counters
×
334
                bool first = true;
335
                for (std::size_t i = 0; i != infos.size(); ++i)
336
                {
×
337
                    using performance_counters::counter_type;
338
                    if (infos[i].type_ != counter_type::raw &&
×
339
                        infos[i].type_ !=
×
340
                            counter_type::monotonically_increasing &&
×
341
                        infos[i].type_ != counter_type::aggregating &&
×
342
                        infos[i].type_ != counter_type::elapsed_time &&
343
                        infos[i].type_ != counter_type::average_count &&
344
                        infos[i].type_ != counter_type::average_timer)
×
345
                    {
346
                        continue;
×
347
                    }
×
348
                    if (!first)
349
                        output << ",";
×
350
                    first = false;
351
                    print_name_csv(output, infos[i].fullname_);
352
                }
353

×
354
                // now print array value counters
355
                for (std::size_t i = 0; i != infos.size(); ++i)
×
356
                {
×
357
                    if (infos[i].type_ !=
358
                            performance_counters::counter_type::histogram &&
359
                        infos[i].type_ !=
360
                            performance_counters::counter_type::raw_values)
×
361
                    {
362
                        continue;
363
                    }
×
364

×
365
                    if (!first)
366
                        output << ",";
×
367
                    first = false;
368
                    print_name_csv(output, infos[i].fullname_);
369
                }
×
370

371
                output << "\n";
×
372
            }
373
            else if (format_ == "csv-short")
374
            {
375
                // first print raw value counters
×
376
                bool first = true;
377
                for (std::size_t i = 0; i != counter_shortnames_.size(); ++i)
378
                {
×
379
                    using performance_counters::counter_type;
380
                    if (infos[i].type_ != counter_type::raw &&
×
381
                        infos[i].type_ !=
×
382
                            counter_type::monotonically_increasing &&
×
383
                        infos[i].type_ != counter_type::aggregating &&
×
384
                        infos[i].type_ != counter_type::elapsed_time &&
385
                        infos[i].type_ != counter_type::average_count &&
386
                        infos[i].type_ != counter_type::average_timer)
×
387
                    {
388
                        continue;
×
389
                    }
×
390
                    if (!first)
391
                        output << ",";
392
                    first = false;
393
                    print_name_csv_short(output, counter_shortnames_[i]);
394
                }
395

×
396
                // now print array value counters
397
                for (std::size_t i = 0; i != counter_shortnames_.size(); ++i)
×
398
                {
×
399
                    if (infos[i].type_ !=
400
                            performance_counters::counter_type::histogram &&
401
                        infos[i].type_ !=
402
                            performance_counters::counter_type::raw_values)
×
403
                    {
404
                        continue;
405
                    }
×
406

×
407
                    if (!first)
408
                        output << ",";
409
                    first = false;
410
                    print_name_csv_short(output, counter_shortnames_[i]);
411
                }
×
412

413
                output << "\n";
×
414
            }
415
            csv_header_ = false;
×
416
        }
417
    }
418

×
419
    template <typename Stream, typename Value>
420
    void query_counters::print_values(Stream* output,
421
        std::vector<Value>&& values, std::vector<std::size_t>&& indices,
422
        std::vector<performance_counters::counter_info> const& infos)
×
423
    {
424
        if (format_ == "csv" || format_ == "csv-short")
425
        {
×
426
            bool first = true;
427
            for (std::size_t i = 0; i != values.size(); ++i)
×
428
            {
×
429
                if (!first && output != nullptr)
430
                    *output << ",";
×
431
                first = false;
432
                print_value_csv(output, infos[i], values[i]);
×
433
            }
×
434
            if (output != nullptr)
435
                *output << "\n";
436
        }
437
        else
438
        {
×
439
            std::size_t idx = 0;
440
            for (std::size_t const i : indices)
×
441
            {
×
442
                print_value(output, infos[i], values[idx]);
443
                ++idx;
444
            }
×
445
        }
446
    }
447

×
448
    ///////////////////////////////////////////////////////////////////////////
449
    bool query_counters::evaluate(bool force)
450
    {
×
451
        bool reset = false;
452
        if (get_config_entry("hpx.print_counter.reset", "0") == "1")
453
            reset = true;
×
454

455
        return evaluate_counters(reset, nullptr, force);
456
    }
×
457

458
    void query_counters::terminate() {}
459

×
460
    ///////////////////////////////////////////////////////////////////////////
461
    void query_counters::start_counters(error_code& ec)
×
462
    {
463
        if (counters_.size() == 0)
464
        {
×
465
            // start has not been called yet
466
            HPX_THROWS_IF(ec, hpx::error::invalid_status,
467
                "query_counters::start_counters",
×
468
                "The counters to be evaluated have not been initialized yet");
469
            return;
470
        }
471

×
472
        // Start the performance counters.
473
        counters_.start(launch::sync, ec);
474
    }
×
475

476
    void query_counters::stop_counters(error_code& ec)
×
477
    {
478
        if (counters_.size() == 0)
479
        {
×
480
            // start has not been called yet
481
            HPX_THROWS_IF(ec, hpx::error::invalid_status,
482
                "query_counters::stop_counters",
×
483
                "The counters to be evaluated have not been initialized yet");
484
            return;
485
        }
486

×
487
        // Stop the performance counters.
488
        counters_.stop(launch::sync, ec);
489
    }
×
490

491
    void query_counters::reset_counters(error_code& ec)
×
492
    {
493
        if (counters_.size() == 0)
494
        {
×
495
            // start has not been called yet
496
            HPX_THROWS_IF(ec, hpx::error::invalid_status,
497
                "query_counters::reset_counters",
×
498
                "The counters to be evaluated have not been initialized yet");
499
            return;
500
        }
501

×
502
        // Reset the performance counters.
503
        counters_.reset(launch::sync, ec);
504
    }
×
505

506
    void query_counters::reinit_counters(bool reset, error_code& ec)
×
507
    {
508
        if (counters_.size() == 0)
509
        {
×
510
            // start has not been called yet
511
            HPX_THROWS_IF(ec, hpx::error::invalid_status,
512
                "query_counters::reinit_counters",
×
513
                "The counters to be evaluated have not been initialized yet");
514
            return;
515
        }
516

×
517
        // Reset the performance counters.
518
        counters_.reinit(launch::sync, reset, ec);
519
    }
520

×
521
    ///////////////////////////////////////////////////////////////////////////
522
    bool query_counters::print_raw_counters(bool destination_is_cout,
523
        bool reset, bool no_output, char const* description,
524
        std::vector<performance_counters::counter_info> const& infos,
525
        error_code& ec)
526
    {
×
527
        // Query the performance counters.
×
528
        std::vector<std::size_t> indices;
529
        indices.reserve(infos.size());
×
530

531
        for (std::size_t i = 0; i != infos.size(); ++i)
×
532
        {
×
533
            if (infos[i].type_ ==
534
                    performance_counters::counter_type::histogram ||
535
                infos[i].type_ ==
536
                    performance_counters::counter_type::raw_values)
×
537
            {
538
                continue;
539
            }
×
540

541
            indices.push_back(i);
542
        }
×
543

544
        if (indices.empty())
545
            return false;
×
546

×
547
        std::ostringstream output;
×
548
        if (description && !no_output)
549
            output << description << std::endl;
550

×
551
        std::vector<performance_counters::counter_value> values =
552
            counters_.get_counter_values(launch::sync, reset, ec);
553

554
        HPX_ASSERT(values.size() == indices.size());
555

×
556
        // Output the performance counter value.
×
557
        if (!no_output)
×
558
            print_headers(output, infos);
559
        print_values(no_output ? nullptr : &output, HPX_MOVE(values),
560
            HPX_MOVE(indices), infos);
×
561

562
        if (!no_output)
×
563
        {
564
            if (destination_is_cout)
×
565
            {
566
                std::cout << output.str() << std::flush;
567
            }
568
            else
×
569
            {
×
570
                std::ofstream out(destination_.c_str(), std::ofstream::app);
×
571
                out << output.str();
572
            }
573
        }
×
574
        return true;
575
    }
576

×
577
    ///////////////////////////////////////////////////////////////////////////
578
    bool query_counters::print_array_counters(bool destination_is_cout,
579
        bool reset, bool no_output, char const* description,
580
        std::vector<performance_counters::counter_info> const& infos,
581
        error_code& ec)
582
    {
×
583
        // Query the performance counters.
×
584
        std::vector<std::size_t> indices;
585
        indices.reserve(infos.size());
×
586

587
        for (std::size_t i = 0; i != infos.size(); ++i)
×
588
        {
×
589
            if (infos[i].type_ !=
590
                    performance_counters::counter_type::histogram &&
591
                infos[i].type_ !=
592
                    performance_counters::counter_type::raw_values)
×
593
            {
594
                continue;
595
            }
×
596

597
            indices.push_back(i);
598
        }
×
599

600
        if (indices.empty())
601
            return false;
×
602

×
603
        std::ostringstream output;
×
604
        if (description && !no_output)
605
            output << description << std::endl;
606

×
607
        std::vector<performance_counters::counter_values_array> values =
608
            counters_.get_counter_values_array(launch::sync, reset, ec);
609

610
        HPX_ASSERT(values.size() == indices.size());
611

×
612
        // Output the performance counter value.
×
613
        if (!no_output)
×
614
            print_headers(output, infos);
615
        print_values(no_output ? nullptr : &output, HPX_MOVE(values),
616
            HPX_MOVE(indices), infos);
×
617

618
        if (!no_output)
×
619
        {
620
            if (destination_is_cout)
×
621
            {
622
                std::cout << output.str() << std::flush;
623
            }
624
            else
×
625
            {
×
626
                std::ofstream out(destination_.c_str(), std::ofstream::app);
×
627
                out << output.str();
628
            }
629
        }
×
630
        return true;
631
    }
×
632

633
    bool query_counters::evaluate_counters(
634
        bool reset, char const* description, bool force, error_code& ec)
×
635
    {
636
        if (!force && timer_.is_terminated())
637
        {
638
            // just do nothing as we're about to terminate the application
639
            return false;
640
        }
641

642
        bool destination_is_cout;
643
        bool no_output;
644

×
645
        {
×
646
            std::lock_guard<mutex_type> l(mtx_);
647
            destination_is_cout = destination_ == "cout";
648
            no_output = destination_ == "none";
649
        }
650

651
#if HPX_HAVE_ITTNOTIFY != 0 && !defined(HPX_HAVE_APEX)
652
        // don't generate any console-output if the ITTNotify API is used
653
        if (!no_output && destination_is_cout && use_ittnotify_api)
654
            no_output = true;
655
#endif
×
656

657
        if (counters_.size() == 0)
658
        {
×
659
            // start has not been called yet
660
            HPX_THROWS_IF(ec, hpx::error::invalid_status,
661
                "query_counters::evaluate",
×
662
                "The counters to be evaluated have not been initialized yet");
663
            return false;
664
        }
665

666
        std::vector<performance_counters::counter_info> const infos =
×
667
            counters_.get_counter_infos();
668

×
669
        bool result = print_raw_counters(
670
            destination_is_cout, reset, no_output, description, infos, ec);
×
671
        if (ec)
672
            return false;
673

×
674
        result = print_array_counters(destination_is_cout, reset, no_output,
×
675
                     description, infos, ec) ||
676
            result;
×
677
        if (ec)
678
            return false;
679

×
680
        if (&ec != &throws)
×
681
            ec = make_success_code();
682

683
        return result;
×
684
    }
685
}    // 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