• 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/core/debugging/include/hpx/debugging/print.hpp
1
//  Copyright (c) 2019-2020 John Biddiscombe
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
#pragma once
8

9
#include <hpx/config.hpp>
10

11
#include <array>
12
#include <atomic>
13
#include <chrono>
14
#include <cstddef>
15
#include <cstdint>
16
#include <iosfwd>
17
#include <sstream>
18
#include <string>
19
#include <tuple>
20
#include <type_traits>
21
#include <utility>
22
#include <vector>
23

24
// ------------------------------------------------------------
25
// This file provides a simple to use printf style debugging
26
// tool that can be used on a per-file basis to enable output.
27
// It is not intended to be exposed to users, but rather as
28
// an aid for hpx development.
29
// ------------------------------------------------------------
30
// Usage: Instantiate a debug print object at the top of a file
31
// using a template param of true/false to enable/disable output.
32
// When the template parameter is false, the optimizer will
33
// not produce code and so the impact is nil.
34
//
35
// static hpx::debug::enable_print<true> spq_deb("SUBJECT");
36
//
37
// Later in code you may print information using
38
//
39
//             spq_deb.debug(str<16>("cleanup_terminated"), "v1"
40
//                  , "D" , dec<2>(domain_num)
41
//                  , "Q" , dec<3>(q_index)
42
//                  , "thread_num", dec<3>(local_num));
43
//
44
// various print formatters (dec/hex/str) are supplied to make
45
// the output regular and aligned for easy parsing/scanning.
46
//
47
// In tight loops, huge amounts of debug information might be
48
// produced, so a simple timer based output is provided
49
// To instantiate a timed output
50
//      static auto getnext = spq_deb.make_timer(1
51
//              , str<16>("get_next_thread"));
52
// then inside a tight loop
53
//      spq_deb.timed(getnext, dec<>(thread_num));
54
// The output will only be produced every N seconds
55
// ------------------------------------------------------------
56

57
// ------------------------------------------------------------
58
/// \cond NODETAIL
59
namespace hpx::debug {
60

61
    // ------------------------------------------------------------------
62
    // format as zero padded int
63
    // ------------------------------------------------------------------
64
    namespace detail {
65

66
        template <typename Int>
67
        HPX_CORE_EXPORT void print_dec(std::ostream& os, Int const& v, int n);
68

69
        extern template HPX_CORE_EXPORT void print_dec(
70
            std::ostream&, std::int16_t const&, int);
71
        extern template HPX_CORE_EXPORT void print_dec(
72
            std::ostream&, std::uint16_t const&, int);
73
        extern template HPX_CORE_EXPORT void print_dec(
74
            std::ostream&, std::int32_t const&, int);
75
        extern template HPX_CORE_EXPORT void print_dec(
76
            std::ostream&, std::uint32_t const&, int);
77
        extern template HPX_CORE_EXPORT void print_dec(
78
            std::ostream&, std::int64_t const&, int);
79
        extern template HPX_CORE_EXPORT void print_dec(
80
            std::ostream&, std::uint64_t const&, int);
81
#if defined(__APPLE__)
82
        extern template HPX_CORE_EXPORT void print_dec(
83
            std::ostream&, long const&, int);
84
        extern template HPX_CORE_EXPORT void print_dec(
85
            std::ostream&, unsigned long const&, int);
×
86
#endif
87

88
        extern template HPX_CORE_EXPORT void print_dec(
89
            std::ostream&, std::atomic<int> const&, int);
90
        extern template HPX_CORE_EXPORT void print_dec(
91
            std::ostream&, std::atomic<unsigned int> const&, int);
92

93
        template <int N, typename T>
94
        struct dec
95
        {
96
            explicit constexpr dec(T const& v) noexcept
97
              : data_(v)
98
            {
99
            }
100

101
            T const& data_;
102

103
            friend std::ostream& operator<<(
104
                std::ostream& os, dec<N, T> const& d)
105
            {
106
                detail::print_dec(os, d.data_, N);
107
                return os;
108
            }
109
        };
110
    }    // namespace detail
111

112
    HPX_CXX_EXPORT template <int N = 2, typename T>
113
    [[nodiscard]] constexpr detail::dec<N, T> dec(T const& v) noexcept
114
    {
115
        return detail::dec<N, T>(v);
116
    }
117

118
    // ------------------------------------------------------------------
119
    // format as pointer
120
    // ------------------------------------------------------------------
121
    HPX_CXX_EXPORT struct ptr
122
    {
123
        HPX_CORE_EXPORT explicit ptr(void const* v) noexcept;
124
        HPX_CORE_EXPORT explicit ptr(std::uintptr_t v) noexcept;
125

126
        void const* data_;
127

128
        HPX_CORE_EXPORT friend std::ostream& operator<<(
129
            std::ostream& os, ptr const& d);
130
    };
131

132
    // ------------------------------------------------------------------
133
    // format as zero padded hex
134
    // ------------------------------------------------------------------
135
    namespace detail {
×
136

137
        template <typename Int>
138
        HPX_CORE_EXPORT void print_hex(std::ostream& os, Int v, int n);
139

140
        template <int N = 4, typename T = int, typename Enable = void>
141
        struct hex;
142

143
        template <int N, typename T>
144
        struct hex<N, T, std::enable_if_t<!std::is_pointer_v<T>>>
145
        {
146
            explicit constexpr hex(T const& v) noexcept
147
              : data_(v)
148
            {
149
            }
150

151
            T const& data_;
152

153
            friend std::ostream& operator<<(
154
                std::ostream& os, hex<N, T> const& d)
155
            {
156
                detail::print_hex(os, d.data_, N);
157
                return os;
158
            }
159
        };
160

161
        HPX_CORE_EXPORT void print_ptr(std::ostream& os, void const* v, int n);
162

163
        template <int N, typename T>
164
        struct hex<N, T, std::enable_if_t<std::is_pointer_v<T>>>
165
        {
166
            explicit constexpr hex(T const& v) noexcept
167
              : data_(v)
168
            {
169
            }
170

171
            T const& data_;
172

173
            friend std::ostream& operator<<(
174
                std::ostream& os, hex<N, T> const& d)
175
            {
176
                detail::print_ptr(os, d.data_, N);
177
                return os;
178
            }
179
        };
180
    }    // namespace detail
181

182
    HPX_CXX_EXPORT template <int N = 4, typename T>
183
    [[nodiscard]] constexpr detail::hex<N, T> hex(T const& v) noexcept
184
    {
185
        return detail::hex<N, T>(v);
186
    }
187

188
    // ------------------------------------------------------------------
189
    // format as binary bits
190
    // ------------------------------------------------------------------
191
    namespace detail {
192

193
        template <typename Int>
194
        HPX_CORE_EXPORT void print_bin(std::ostream& os, Int v, int n);
195

196
        template <int N = 8, typename T = int>
197
        struct bin
198
        {
199
            explicit constexpr bin(T const& v) noexcept
200
              : data_(v)
201
            {
202
            }
203

204
            T const& data_;
205

206
            friend std::ostream& operator<<(
207
                std::ostream& os, bin<N, T> const& d)
208
            {
209
                detail::print_bin(os, d.data_, N);
210
                return os;
211
            }
212
        };
213
    }    // namespace detail
214

215
    HPX_CXX_EXPORT template <int N = 8, typename T>
216
    [[nodiscard]] constexpr detail::bin<N, T> bin(T const& v) noexcept
217
    {
218
        return detail::bin<N, T>(v);
219
    }
220

×
221
    // ------------------------------------------------------------------
222
    // format as padded string
223
    // ------------------------------------------------------------------
224
    namespace detail {
225

226
        HPX_CORE_EXPORT void print_str(std::ostream& os, char const* v, int n);
227
    }
228

229
    HPX_CXX_EXPORT template <int N = 20>
230
    struct str
231
    {
232
        explicit constexpr str(char const* v) noexcept
233
          : data_(v)
234
        {
235
        }
236

237
        char const* data_;
238

239
        friend std::ostream& operator<<(std::ostream& os, str<N> const& d)
240
        {
241
            detail::print_str(os, d.data_, N);
242
            return os;
243
        }
244
    };
245

246
    // ------------------------------------------------------------------
247
    // format as ip address
248
    // ------------------------------------------------------------------
249
    HPX_CXX_EXPORT struct ipaddr
250
    {
251
        HPX_CORE_EXPORT explicit ipaddr(void const* a) noexcept;
252
        HPX_CORE_EXPORT explicit ipaddr(std::uint32_t a) noexcept;
253

254
        std::uint8_t const* data_;
255
        std::uint32_t const ipdata_;
256

257
        HPX_CORE_EXPORT friend std::ostream& operator<<(
258
            std::ostream& os, ipaddr const& p);
259
    };
260

261
    // ------------------------------------------------------------------
262
    // helper class for printing time since start
263
    // ------------------------------------------------------------------
264
    namespace detail {
265

266
        struct current_time_print_helper
267
        {
268
            HPX_CORE_EXPORT friend std::ostream& operator<<(
269
                std::ostream& os, current_time_print_helper);
270
        };
271
    }    // namespace detail
272

273
    // ------------------------------------------------------------------
274
    // helper function for printing CRC32
275
    // ------------------------------------------------------------------
276
    HPX_CXX_EXPORT [[nodiscard]] constexpr std::uint32_t crc32(
277
        void const*, std::size_t) noexcept
278
    {
279
        return 0;
280
    }
281

282
    // ------------------------------------------------------------------
283
    // helper function for printing short memory dump and crc32
284
    // useful for debugging corruptions in buffers during
285
    // rma or other transfers
286
    // ------------------------------------------------------------------
287
    HPX_CXX_EXPORT struct mem_crc32
288
    {
289
        HPX_CORE_EXPORT mem_crc32(
290
            void const* a, std::size_t len, char const* txt) noexcept;
291

292
        std::uint64_t const* addr_;
293
        std::size_t const len_;
294
        char const* txt_;
295

296
        HPX_CORE_EXPORT friend std::ostream& operator<<(
297
            std::ostream& os, mem_crc32 const& p);
298
    };
299

300
    namespace detail {
301

302
        template <typename TupleType, std::size_t... I>
303
        void tuple_print(
304
            std::ostream& os, TupleType const& t, std::index_sequence<I...>)
305
        {
306
            (..., (os << (I == 0 ? "" : " ") << std::get<I>(t)));
307
        }
308

309
        template <typename... Args>
310
        void tuple_print(std::ostream& os, std::tuple<Args...> const& t)
311
        {
312
            tuple_print(os, t, std::make_index_sequence<sizeof...(Args)>());
313
        }
314
    }    // namespace detail
315

316
    namespace detail {
317

318
        // ------------------------------------------------------------------
319
        // helper class for printing time since start
320
        // ------------------------------------------------------------------
321
        struct hostname_print_helper
322
        {
323
            [[nodiscard]] HPX_CORE_EXPORT char const* get_hostname() const;
324
            [[nodiscard]] HPX_CORE_EXPORT int guess_rank() const;
325

326
            HPX_CORE_EXPORT friend std::ostream& operator<<(
327
                std::ostream& os, hostname_print_helper h);
328
        };
329

330
        ///////////////////////////////////////////////////////////////////////
331
        HPX_CORE_EXPORT void register_print_info(void (*)(std::ostream&));
332
        HPX_CORE_EXPORT void generate_prefix(std::ostream& os);
333

334
        ///////////////////////////////////////////////////////////////////////
335
        HPX_CORE_EXPORT void display_to_cout(std::string const& str);
336

337
        template <typename... Args>
338
        void display(char const* prefix, Args const&... args)
339
        {
340
            // using a temp stream object with a single copy to cout at the end
341
            // prevents multiple threads from injecting overlapping text
342
            std::stringstream tempstream;
343
            tempstream << prefix;
344
            generate_prefix(tempstream);
345
            ((tempstream << args << " "), ...);
346
            tempstream << std::endl;
347
            display_to_cout(tempstream.str());
348
        }
349

350
        template <typename... Args>
351
        void debug(Args const&... args)
352
        {
353
            display("<DEB> ", args...);
354
        }
355

356
        template <typename... Args>
357
        void warning(Args const&... args)
358
        {
359
            display("<WAR> ", args...);
360
        }
361

362
        template <typename... Args>
363
        void error(Args const&... args)
364
        {
365
            display("<ERR> ", args...);
366
        }
367

368
        template <typename... Args>
369
        void scope(Args const&... args)
370
        {
371
            display("<SCO> ", args...);
372
        }
373

374
        template <typename... Args>
375
        void trace(Args const&... args)
376
        {
377
            display("<TRC> ", args...);
378
        }
379

380
        template <typename... Args>
381
        void timed(Args const&... args)
382
        {
383
            display("<TIM> ", args...);
384
        }
385
    }    // namespace detail
386

387
    HPX_CXX_EXPORT template <typename... Args>
388
    struct scoped_var
389
    {
390
        // capture tuple elements by reference - no temp vars in constructor please
391
        char const* prefix_;
392
        std::tuple<Args const&...> const message_;
393
        std::string buffered_msg;
394

395
        //
396
        explicit scoped_var(char const* p, Args const&... args)
397
          : prefix_(p)
398
          , message_(args...)
399
        {
400
            std::stringstream tempstream;
401
            detail::tuple_print(tempstream, message_);
402
            buffered_msg = tempstream.str();
403
            detail::display("<SCO> ", prefix_, debug::str<>(">> enter <<"),
404
                tempstream.str());
405
        }
406

407
        ~scoped_var()
408
        {
409
            detail::display(
410
                "<SCO> ", prefix_, debug::str<>("<< leave >>"), buffered_msg);
411
        }
412

413
        scoped_var(scoped_var const&) = delete;
414
        scoped_var(scoped_var&&) = delete;
415
        scoped_var& operator=(scoped_var const&) = delete;
416
        scoped_var& operator=(scoped_var&&) = delete;
417
    };
418

419
    HPX_CXX_EXPORT template <typename... Args>
420
    struct timed_var
421
    {
422
        mutable std::chrono::steady_clock::time_point time_start_;
423
        double const delay_;
424
        std::tuple<Args...> const message_;
425
        //
426
        explicit timed_var(double delay, Args const&... args)
427
          : time_start_(std::chrono::steady_clock::now())
428
          , delay_(delay)
429
          , message_(args...)
430
        {
431
        }
432

433
        bool elapsed(std::chrono::steady_clock::time_point const& now) const
434
        {
435
            double const elapsed_ =
436
                std::chrono::duration_cast<std::chrono::duration<double>>(
437
                    now - time_start_)
438
                    .count();
439

440
            if (elapsed_ > delay_)
441
            {
442
                time_start_ = now;
443
                return true;
444
            }
445
            return false;
446
        }
447

448
        friend std::ostream& operator<<(
449
            std::ostream& os, timed_var<Args...> const& ti)
450
        {
451
            detail::tuple_print(os, ti.message_);
452
            return os;
453
        }
454
    };
455

456
    ///////////////////////////////////////////////////////////////////////////
457
    HPX_CXX_EXPORT template <bool Enable>
458
    struct enable_print;
459

460
    // when false, debug statements should produce no code
461
    template <>
462
    struct enable_print<false>
463
    {
464
        explicit constexpr enable_print(char const*) noexcept {}
465

466
        [[nodiscard]] static constexpr bool is_enabled() noexcept
467
        {
468
            return false;
469
        }
470

471
        template <typename... Args>
472
        static constexpr void debug(Args const&...) noexcept
473
        {
474
        }
475

476
        template <typename... Args>
477
        static constexpr void warning(Args const&...) noexcept
478
        {
479
        }
480

481
        template <typename... Args>
482
        static constexpr void trace(Args const&...) noexcept
483
        {
484
        }
485

486
        template <typename... Args>
487
        static constexpr void error(Args const&...) noexcept
488
        {
489
        }
490

491
        template <typename... Args>
492
        static constexpr void timed(Args const&...) noexcept
493
        {
494
        }
495

496
        template <typename T>
497
        static constexpr void array(
498
            std::string const&, std::vector<T> const&) noexcept
499
        {
500
        }
501

502
        template <typename T, std::size_t N>
503
        static constexpr void array(
504
            std::string const&, std::array<T, N> const&) noexcept
505
        {
506
        }
507

508
        template <typename T>
509
        static constexpr void array(
510
            std::string const&, T const*, std::size_t) noexcept
511
        {
512
        }
513

514
        template <typename... Args>
515
        static constexpr bool scope(Args const&...) noexcept
516
        {
517
            return true;
518
        }
519

520
        template <typename T, typename... Args>
521
        [[nodiscard]] static constexpr bool declare_variable(
522
            Args const&...) noexcept
523
        {
524
            return true;
525
        }
526

527
        template <typename T, typename V>
528
        static constexpr void set(T&, V const&) noexcept
529
        {
530
        }
531

532
        // @todo, return void so that timers have zero footprint when disabled
533
        template <typename... Args>
534
        [[nodiscard]] static constexpr int make_timer(
535
            double const, Args const&...) noexcept
536
        {
537
            return 0;
538
        }
539

540
        template <typename Expr>
541
        [[nodiscard]] static constexpr bool eval(Expr const&) noexcept
542
        {
543
            return true;
544
        }
545
    };
546

547
    namespace detail {
548

549
        template <typename T>
550
        HPX_CORE_EXPORT void print_array(
551
            std::string const& name, T const* data, std::size_t size);
552
    }
553

554
    // when true, debug statements produce valid output
555
    template <>
556
    struct enable_print<true>
557
    {
558
    private:
559
        char const* prefix_;
560

561
    public:
562
        constexpr enable_print() noexcept
563
          : prefix_("")
564
        {
565
        }
566

567
        explicit constexpr enable_print(char const* p) noexcept
568
          : prefix_(p)
569
        {
570
        }
571

572
        [[nodiscard]] static constexpr bool is_enabled() noexcept
573
        {
574
            return true;
575
        }
576

577
        template <typename... Args>
578
        constexpr void debug(Args const&... args) const
579
        {
580
            detail::debug(prefix_, args...);
581
        }
582

583
        template <typename... Args>
584
        constexpr void warning(Args const&... args) const
585
        {
586
            detail::warning(prefix_, args...);
587
        }
588

589
        template <typename... Args>
590
        constexpr void trace(Args const&... args) const
591
        {
592
            detail::trace(prefix_, args...);
593
        }
594

595
        template <typename... Args>
596
        constexpr void error(Args const&... args) const
597
        {
598
            detail::error(prefix_, args...);
599
        }
600

601
        template <typename... Args>
602
        [[nodiscard]] scoped_var<Args...> scope(Args const&... args)
603
        {
604
            return scoped_var<Args...>(prefix_, args...);
605
        }
606

607
        template <typename... T, typename... Args>
608
        void timed(timed_var<T...> const& init, Args const&... args) const
609
        {
610
            if (auto now = std::chrono::steady_clock::now(); init.elapsed(now))
611
            {
612
                detail::timed(prefix_, init, args...);
613
            }
614
        }
615

616
        template <typename T>
617
        static void array(std::string const& name, std::vector<T> const& v)
618
        {
619
            detail::print_array(name, v.data(), v.size());
620
        }
621

622
        template <typename T, std::size_t N>
623
        static void array(std::string const& name, std::array<T, N> const& v)
624
        {
625
            detail::print_array(name, v.data(), N);
626
        }
627

628
        template <typename T>
629
        static void array(
630
            std::string const& name, T const* data, std::size_t size)
631
        {
632
            detail::print_array(name, data, size);
633
        }
634

635
        template <typename T, typename... Args>
636
        [[nodiscard]] static T declare_variable(Args const&... args)
637
        {
638
            return T(args...);
639
        }
640

641
        template <typename T, typename V>
642
        static void set(T& var, V const& val)
643
        {
644
            var = val;
645
        }
646

647
        template <typename... Args>
648
        [[nodiscard]] static timed_var<Args...> make_timer(
649
            double const delay, Args const... args)
650
        {
651
            return timed_var<Args...>(delay, args...);
652
        }
653

654
        template <typename Expr>
655
        [[nodiscard]] static auto eval(Expr const& e)
656
        {
657
            return e();
658
        }
659
    };
660
}    // namespace hpx::debug
661
/// \endcond
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

© 2026 Coveralls, Inc