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

STEllAR-GROUP / hpx / #853

19 Dec 2022 01:01AM UTC coverage: 86.287% (+0.4%) from 85.912%
#853

push

StellarBot
Merge #6109

6109: Modernize serialization module r=hkaiser a=hkaiser

- flyby separate serialization of Boost types

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

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

53 of 53 new or added lines in 6 files covered. (100.0%)

173939 of 201582 relevant lines covered (86.29%)

1931657.12 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-2021 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_base/launch_policy.hpp>
10
#include <hpx/async_combinators/wait_all.hpp>
11
#include <hpx/async_distributed/continuation.hpp>
12
#include <hpx/components_base/agas_interface.hpp>
13
#include <hpx/functional/bind_front.hpp>
14
#include <hpx/modules/format.hpp>
15
#include <hpx/performance_counters/apex_sample_value.hpp>
16
#include <hpx/performance_counters/counters.hpp>
17
#include <hpx/performance_counters/performance_counter.hpp>
18
#include <hpx/performance_counters/query_counters.hpp>
19
#include <hpx/runtime_local/config_entry.hpp>
20
#include <hpx/runtime_local/get_thread_name.hpp>
21
#include <hpx/thread_support/unlock_guard.hpp>
22
#include <hpx/threading_base/external_timer.hpp>
23
#include <hpx/threading_base/thread_helpers.hpp>
24
#include <hpx/timing/high_resolution_clock.hpp>
25
#include <hpx/type_support/unused.hpp>
26

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

37
#if HPX_HAVE_ITTNOTIFY != 0 && !defined(HPX_HAVE_APEX)
38
#include <ittnotify.h>
39
#include <map>
40
#endif
41

42
namespace hpx { namespace util {
43

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

73
    query_counters::~query_counters()
×
74
    {
75
        counters_.release();
×
76
    }
×
77

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

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

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

104
    void query_counters::start()
×
105
    {
106
        if (print_counters_locally_ && destination_ != "cout")
×
107
            destination_ += "." + std::to_string(hpx::get_locality_id());
×
108

109
        find_counters();
×
110

111
        counters_.start(launch::sync);
×
112

113
        // this will invoke the evaluate function for the first time
114
        timer_.start();
×
115
    }
×
116

117
    void query_counters::stop_evaluating_counters(bool terminate)
×
118
    {
119
        timer_.stop(terminate);
×
120
        counters_.stop(launch::sync);
×
121
    }
×
122

123
    ///////////////////////////////////////////////////////////////////////////
124
    namespace strings {
125

126
        char const* const counter_type_short_names[] = {
127
            "counter_type::text",
128
            "counter_type::raw",
129
            "counter_type::monotonically_increasing",
130
            "counter_type::average_base",
131
            "counter_type::average_count",
132
            "counter_type::aggregated",
133
            "counter_type::average_timer",
134
            "counter_type::elapsed_time",
135
            "counter_type::histogram",
136
            "counter_type::raw_values",
137
        };
138
    }
139

140
    char const* get_counter_short_type_name(
×
141
        performance_counters::counter_type type)
142
    {
143
        if (type < performance_counters::counter_type::text ||
×
144
            type > performance_counters::counter_type::raw_values)
×
145
        {
146
            return "unknown";
×
147
        }
148
        return strings::counter_type_short_names[static_cast<int>(type)];
×
149
    }
×
150

151
    template <typename Stream>
152
    void query_counters::print_name_csv(Stream& out, std::string const& name)
×
153
    {
154
        std::string s = performance_counters::remove_counter_prefix(name);
×
155
        if (s.find_first_of(',') != std::string::npos)
×
156
            out << "\"" << s << "\"";
×
157
        else
158
            out << s;
×
159
    }
×
160

161
    template <typename Stream>
162
    void query_counters::print_value(Stream* out,
×
163
        performance_counters::counter_info const& info,
164
        performance_counters::counter_value const& value)
165
    {
166
        std::string const& name = info.fullname_;
×
167
        std::string const& uom = info.unit_of_measure_;
×
168

169
        error_code ec(throwmode::lightweight);    // do not throw
×
170
        double val = value.get_value<double>(ec);
×
171

172
        if (!ec)
×
173
        {
174
#ifdef HPX_HAVE_APEX
175
            external_timer::sample_value(info, val);
176
#elif HPX_HAVE_ITTNOTIFY != 0
177
            if (use_ittnotify_api)
178
            {
179
                auto it = itt_counters_.find(name);
180
                if (it != itt_counters_.end())
181
                {
182
                    (*it).second.set_value(val);
183
                }
184
            }
185
#endif
186

187
            if (out == nullptr)
×
188
                return;
×
189

190
            print_name_csv(*out, name);
×
191
            *out << "," << value.count_ << ",";
×
192

193
            double elapsed = static_cast<double>(value.time_) * 1e-9;
×
194
            *out << hpx::util::format("{:.6}", elapsed) << ",[s]," << val;
×
195
            if (!uom.empty())
×
196
                *out << ",[" << uom << "]";
×
197

198
            if (counter_types_)
×
199
            {
200
                if (uom.empty())
×
201
                    *out << ",[]";
×
202
                *out << "," << get_counter_short_type_name(info.type_);
×
203
            }
×
204
            *out << "\n";
×
205
        }
×
206
        else
207
        {
208
            if (out != nullptr)
×
209
                *out << "invalid\n";
×
210
        }
211
    }
×
212

213
    template <typename Stream>
214
    void query_counters::print_value(Stream* out,
×
215
        performance_counters::counter_info const& info,
216
        performance_counters::counter_values_array const& value)
217
    {
218
        if (out == nullptr)
×
219
            return;
×
220

221
        std::string const& name = info.fullname_;
×
222
        std::string const& uom = info.unit_of_measure_;
×
223

224
        error_code ec(throwmode::lightweight);    // do not throw
×
225

226
        print_name_csv(*out, name);
×
227
        *out << "," << value.count_ << ",";
×
228

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

232
        bool first = true;
×
233
        for (std::int64_t val : value.values_)
×
234
        {
235
            if (!first)
×
236
                *out << ':';
×
237
            first = false;
×
238
            *out << val;
×
239
        }
240

241
        if (!uom.empty())
×
242
            *out << ",[" << uom << "]";
×
243

244
        if (counter_types_)
×
245
        {
246
            if (uom.empty())
×
247
                *out << ",[]";
×
248
            *out << "," << get_counter_short_type_name(info.type_);
×
249
        }
×
250
        *out << "\n";
×
251
    }
×
252

253
    template <typename Stream>
254
    void query_counters::print_value_csv(Stream* out,
×
255
        performance_counters::counter_info const& info,
256
        performance_counters::counter_value const& value)
257
    {
258
        error_code ec(throwmode::lightweight);
×
259
        double val = value.get_value<double>(ec);
×
260

261
        if (!ec)
×
262
        {
263
#ifdef HPX_HAVE_APEX
264
            external_timer::sample_value(info, val);
265
#elif HPX_HAVE_ITTNOTIFY != 0
266
            if (use_ittnotify_api)
267
            {
268
                auto it = itt_counters_.find(info.fullname_);
269
                if (it != itt_counters_.end())
270
                {
271
                    (*it).second.set_value(val);
272
                }
273
            }
274
#else
275
            HPX_UNUSED(info);
×
276
#endif
277
            if (out == nullptr)
×
278
                return;
×
279

280
            *out << val;
×
281
        }
×
282
        else
283
        {
284
            if (out != nullptr)
×
285
                *out << "invalid";
×
286
        }
287
    }
×
288

289
    template <typename Stream>
290
    void query_counters::print_value_csv(Stream* out,
×
291
        performance_counters::counter_info const& /* info */,
292
        performance_counters::counter_values_array const& value)
293
    {
294
        if (out == nullptr)
×
295
            return;
×
296

297
        bool first = true;
×
298
        for (std::int64_t val : value.values_)
×
299
        {
300
            if (!first)
×
301
                *out << ':';
×
302
            first = false;
×
303
            *out << val;
×
304
        }
305
    }
×
306

307
    template <typename Stream>
308
    void query_counters::print_name_csv_short(
×
309
        Stream& out, std::string const& name)
310
    {
311
        out << name;
×
312
    }
×
313

314
    template <typename Stream>
315
    void query_counters::print_headers(Stream& output,
×
316
        std::vector<performance_counters::counter_info> const& infos)
317
    {
318
        if (csv_header_)
×
319
        {
320
            if (format_ == "csv")
×
321
            {
322
                // first print raw value counters
323
                bool first = true;
×
324
                for (std::size_t i = 0; i != infos.size(); ++i)
×
325
                {
326
                    using namespace performance_counters;
327
                    if (infos[i].type_ != counter_type::raw &&
×
328
                        infos[i].type_ !=
×
329
                            counter_type::monotonically_increasing &&
×
330
                        infos[i].type_ != counter_type::aggregating &&
×
331
                        infos[i].type_ != counter_type::elapsed_time &&
×
332
                        infos[i].type_ != counter_type::average_count &&
×
333
                        infos[i].type_ != counter_type::average_timer)
×
334
                    {
335
                        continue;
×
336
                    }
337
                    if (!first)
×
338
                        output << ",";
×
339
                    first = false;
×
340
                    print_name_csv(output, infos[i].fullname_);
×
341
                }
×
342

343
                // now print array value counters
344
                for (std::size_t i = 0; i != infos.size(); ++i)
×
345
                {
346
                    if (infos[i].type_ !=
×
347
                            performance_counters::counter_type::histogram &&
×
348
                        infos[i].type_ !=
×
349
                            performance_counters::counter_type::raw_values)
350
                    {
351
                        continue;
×
352
                    }
353

354
                    if (!first)
×
355
                        output << ",";
×
356
                    first = false;
×
357
                    print_name_csv(output, infos[i].fullname_);
×
358
                }
×
359

360
                output << "\n";
×
361
            }
×
362
            else if (format_ == "csv-short")
×
363
            {
364
                // first print raw value counters
365
                bool first = true;
×
366
                for (std::size_t i = 0; i != counter_shortnames_.size(); ++i)
×
367
                {
368
                    using namespace performance_counters;
369
                    if (infos[i].type_ != counter_type::raw &&
×
370
                        infos[i].type_ !=
×
371
                            counter_type::monotonically_increasing &&
×
372
                        infos[i].type_ != counter_type::aggregating &&
×
373
                        infos[i].type_ != counter_type::elapsed_time &&
×
374
                        infos[i].type_ != counter_type::average_count &&
×
375
                        infos[i].type_ != counter_type::average_timer)
×
376
                    {
377
                        continue;
×
378
                    }
379
                    if (!first)
×
380
                        output << ",";
×
381
                    first = false;
×
382
                    print_name_csv_short(output, counter_shortnames_[i]);
×
383
                }
×
384

385
                // now print array value counters
386
                for (std::size_t i = 0; i != counter_shortnames_.size(); ++i)
×
387
                {
388
                    if (infos[i].type_ !=
×
389
                            performance_counters::counter_type::histogram &&
×
390
                        infos[i].type_ !=
×
391
                            performance_counters::counter_type::raw_values)
392
                    {
393
                        continue;
×
394
                    }
395

396
                    if (!first)
×
397
                        output << ",";
×
398
                    first = false;
×
399
                    print_name_csv_short(output, counter_shortnames_[i]);
×
400
                }
×
401

402
                output << "\n";
×
403
            }
×
404
            csv_header_ = false;
×
405
        }
×
406
    }
×
407

408
    template <typename Stream, typename Value>
409
    void query_counters::print_values(Stream* output,
×
410
        std::vector<Value>&& values, std::vector<std::size_t>&& indices,
411
        std::vector<performance_counters::counter_info> const& infos)
412
    {
413
        if (format_ == "csv" || format_ == "csv-short")
×
414
        {
415
            bool first = true;
×
416
            for (std::size_t i = 0; i != values.size(); ++i)
×
417
            {
418
                if (!first && output != nullptr)
×
419
                    *output << ",";
×
420
                first = false;
×
421
                print_value_csv(output, infos[i], values[i]);
×
422
            }
×
423
            if (output != nullptr)
×
424
                *output << "\n";
×
425
        }
×
426
        else
427
        {
428
            std::size_t idx = 0;
×
429
            for (std::size_t i : indices)
×
430
            {
431
                print_value(output, infos[i], values[idx]);
×
432
                ++idx;
×
433
            }
434
        }
435
    }
×
436

437
    ///////////////////////////////////////////////////////////////////////////
438
    bool query_counters::evaluate(bool force)
×
439
    {
440
        bool reset = false;
×
441
        if (get_config_entry("hpx.print_counter.reset", "0") == "1")
×
442
            reset = true;
×
443

444
        return evaluate_counters(reset, nullptr, force);
×
445
    }
×
446

447
    void query_counters::terminate() {}
×
448

449
    ///////////////////////////////////////////////////////////////////////////
450
    void query_counters::start_counters(error_code& ec)
×
451
    {
452
        if (counters_.size() == 0)
×
453
        {
454
            // start has not been called yet
455
            HPX_THROWS_IF(ec, hpx::error::invalid_status,
×
456
                "query_counters::start_counters",
457
                "The counters to be evaluated have not been initialized yet");
458
            return;
×
459
        }
460

461
        // Start the performance counters.
462
        counters_.start(launch::sync, ec);
×
463
    }
×
464

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

476
        // Stop the performance counters.
477
        counters_.stop(launch::sync, ec);
×
478
    }
×
479

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

491
        // Reset the performance counters.
492
        counters_.reset(launch::sync, ec);
×
493
    }
×
494

495
    void query_counters::reinit_counters(bool reset, error_code& ec)
×
496
    {
497
        if (counters_.size() == 0)
×
498
        {
499
            // start has not been called yet
500
            HPX_THROWS_IF(ec, hpx::error::invalid_status,
×
501
                "query_counters::reinit_counters",
502
                "The counters to be evaluated have not been initialized yet");
503
            return;
×
504
        }
505

506
        // Reset the performance counters.
507
        counters_.reinit(launch::sync, reset, ec);
×
508
    }
×
509

510
    ///////////////////////////////////////////////////////////////////////////
511
    bool query_counters::print_raw_counters(bool destination_is_cout,
×
512
        bool reset, bool no_output, char const* description,
513
        std::vector<performance_counters::counter_info> const& infos,
514
        error_code& ec)
515
    {
516
        // Query the performance counters.
517
        std::vector<std::size_t> indices;
×
518
        indices.reserve(infos.size());
×
519

520
        for (std::size_t i = 0; i != infos.size(); ++i)
×
521
        {
522
            if (infos[i].type_ ==
×
523
                    performance_counters::counter_type::histogram ||
×
524
                infos[i].type_ ==
×
525
                    performance_counters::counter_type::raw_values)
526
            {
527
                continue;
×
528
            }
529

530
            indices.push_back(i);
×
531
        }
×
532

533
        if (indices.empty())
×
534
            return false;
×
535

536
        std::ostringstream output;
×
537
        if (description && !no_output)
×
538
            output << description << std::endl;
×
539

540
        std::vector<performance_counters::counter_value> values =
541
            counters_.get_counter_values(launch::sync, reset, ec);
×
542

543
        HPX_ASSERT(values.size() == indices.size());
×
544

545
        // Output the performance counter value.
546
        if (!no_output)
×
547
            print_headers(output, infos);
×
548
        print_values(no_output ? nullptr : &output, HPX_MOVE(values),
×
549
            HPX_MOVE(indices), infos);
×
550

551
        if (!no_output)
×
552
        {
553
            if (destination_is_cout)
×
554
            {
555
                std::cout << output.str() << std::flush;
×
556
            }
×
557
            else
558
            {
559
                std::ofstream out(destination_.c_str(), std::ofstream::app);
×
560
                out << output.str();
×
561
            }
×
562
        }
×
563
        return true;
×
564
    }
×
565

566
    ///////////////////////////////////////////////////////////////////////////
567
    bool query_counters::print_array_counters(bool destination_is_cout,
×
568
        bool reset, bool no_output, char const* description,
569
        std::vector<performance_counters::counter_info> const& infos,
570
        error_code& ec)
571
    {
572
        // Query the performance counters.
573
        std::vector<std::size_t> indices;
×
574
        indices.reserve(infos.size());
×
575

576
        for (std::size_t i = 0; i != infos.size(); ++i)
×
577
        {
578
            if (infos[i].type_ !=
×
579
                    performance_counters::counter_type::histogram &&
×
580
                infos[i].type_ !=
×
581
                    performance_counters::counter_type::raw_values)
582
            {
583
                continue;
×
584
            }
585

586
            indices.push_back(i);
×
587
        }
×
588

589
        if (indices.empty())
×
590
            return false;
×
591

592
        std::ostringstream output;
×
593
        if (description && !no_output)
×
594
            output << description << std::endl;
×
595

596
        std::vector<performance_counters::counter_values_array> values =
597
            counters_.get_counter_values_array(launch::sync, reset, ec);
×
598

599
        HPX_ASSERT(values.size() == indices.size());
×
600

601
        // Output the performance counter value.
602
        if (!no_output)
×
603
            print_headers(output, infos);
×
604
        print_values(no_output ? nullptr : &output, HPX_MOVE(values),
×
605
            HPX_MOVE(indices), infos);
×
606

607
        if (!no_output)
×
608
        {
609
            if (destination_is_cout)
×
610
            {
611
                std::cout << output.str() << std::flush;
×
612
            }
×
613
            else
614
            {
615
                std::ofstream out(destination_.c_str(), std::ofstream::app);
×
616
                out << output.str();
×
617
            }
×
618
        }
×
619
        return true;
×
620
    }
×
621

622
    bool query_counters::evaluate_counters(
×
623
        bool reset, char const* description, bool force, error_code& ec)
624
    {
625
        if (!force && timer_.is_terminated())
×
626
        {
627
            // just do nothing as we're about to terminate the application
628
            return false;
×
629
        }
630

631
        bool destination_is_cout = false;
×
632
        bool no_output = false;
×
633

634
        {
635
            std::lock_guard<mutex_type> l(mtx_);
×
636
            destination_is_cout = destination_ == "cout";
×
637
            no_output = destination_ == "none";
×
638
        }
×
639

640
#if HPX_HAVE_ITTNOTIFY != 0 && !defined(HPX_HAVE_APEX)
641
        // don't generate any console-output if the ITTNotify API is used
642
        if (!no_output && destination_is_cout && use_ittnotify_api)
643
            no_output = true;
644
#endif
645

646
        if (counters_.size() == 0)
×
647
        {
648
            // start has not been called yet
649
            HPX_THROWS_IF(ec, hpx::error::invalid_status,
×
650
                "query_counters::evaluate",
651
                "The counters to be evaluated have not been initialized yet");
652
            return false;
×
653
        }
654

655
        bool result = false;
×
656
        std::vector<performance_counters::counter_info> infos =
657
            counters_.get_counter_infos();
×
658

659
        result = print_raw_counters(
×
660
            destination_is_cout, reset, no_output, description, infos, ec);
×
661
        if (ec)
×
662
            return false;
×
663

664
        result = print_array_counters(destination_is_cout, reset, no_output,
×
665
                     description, infos, ec) ||
×
666
            result;
×
667
        if (ec)
×
668
            return false;
×
669

670
        if (&ec != &throws)
×
671
            ec = make_success_code();
×
672

673
        return result;
×
674
    }
×
675
}}    // 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