• 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/testing/src/performance.cpp
1
//  Copyright (c) 2021 ETH Zurich
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/testing/performance.hpp>
8

9
#include <chrono>
10
#include <cstddef>
11
#include <iostream>
12
#include <map>
13
#include <string>
14
#include <tuple>
15
#include <type_traits>
16
#include <vector>
17

18
#if defined(HPX_HAVE_NANOBENCH)
19
#define ANKERL_NANOBENCH_IMPLEMENT
20
#include <nanobench.h>
21
#endif
22

23
namespace hpx::util {
24

25
    void perftests_cfg(hpx::program_options::options_description& cmdline)
26
    {
27
        cmdline.add_options()("detailed_bench",
28
            "Use if detailed benchmarks are required, showing the execution "
29
            "time taken for each epoch");
30
    }
31

32
    void perftests_init(hpx::program_options::variables_map const& vm)
33
    {
34
        if (vm.count("detailed_bench"))
35
        {
36
            detailed_ = true;
37
        }
38
    }
39

×
40
    namespace detail {
41

×
42
#if defined(HPX_HAVE_NANOBENCH)
×
43
        constexpr int nanobench_epochs = 24;
44
        constexpr int nanobench_warmup = 40;
45

×
46
        char const* nanobench_hpx_simple_template() noexcept
47
        {
48
            return R"DELIM(Results:
×
49
{{#result}}
×
50
name: {{name}},
51
executor: {{context(executor)}},
×
52
average: {{average(elapsed)}}{{^-last}}
53
{{/-last}}
×
54
{{/result}})DELIM";
×
55
        }
56

×
57
        char const* nanobench_hpx_template() noexcept
58
        {
×
59
            return R"DELIM({
×
60
    "outputs": [
×
61
{{#result}}        {
62
            "name": "{{name}}",
×
63
            "executor": "{{context(executor)}}",
64
            "series": [
×
65
                {{#measurement}}{{elapsed}}{{^-last}},
×
66
                {{/-last}}{{/measurement}}
67
            ]
68
        }{{^-last}},{{/-last}}
×
69
{{/result}}    ]
70
}
×
71
)DELIM";
×
72
        }
73

×
74
        ankerl::nanobench::Bench& bench()
×
75
        {
76
            static ankerl::nanobench::Bench b;
×
77
            static ankerl::nanobench::Config cfg;
×
78

×
79
            cfg.mWarmup = nanobench_warmup;
×
80
            cfg.mNumEpochs = nanobench_epochs;
81

×
82
            return b.config(cfg);
×
83
        }
×
84
#else
×
85
        // Json output for performance reports
×
86
        class json_perf_times
87
        {
88
            using key_t = std::tuple<std::string, std::string>;
×
89
            using value_t = std::vector<long double>;
90
            using map_t = std::map<key_t, value_t>;
91

×
92
            map_t m_map;
×
93

94
            HPX_CORE_EXPORT friend std::ostream& operator<<(
95
                std::ostream& strm, json_perf_times const& obj);
×
96

97
        public:
98
            HPX_CORE_EXPORT void add(std::string const& name,
×
99
                std::string const& executor, long double time);
100
        };
101

102
        json_perf_times& times()
103
        {
104
            static json_perf_times res;
×
105
            return res;
106
        }
107

108
        void add_time(std::string const& test_name, std::string const& executor,
×
109
            long double time)
110
        {
111
            times().add(test_name, executor, time);
112
        }
113

×
114
        std::ostream& operator<<(std::ostream& strm, json_perf_times const& obj)
115
        {
116
            if (detailed_)
117
            {
118
                strm << "{\n";
×
119
                strm << "  \"outputs\" : [";
120
                int outputs = 0;
×
121
                for (auto&& item : obj.m_map)
×
122
                {
123
                    long double average = static_cast<long double>(0.0);
124
                    if (outputs)
125
                        strm << ",";
126
                    strm << "\n    {\n";
127
                    strm << R"(      "name": ")" << std::get<0>(item.first)
128
                         << "\",\n";
129
                    strm << R"(      "executor": ")" << std::get<1>(item.first)
130
                         << "\",\n";
131
                    strm << R"(      "series": [)"
132
                         << "\n";
133
                    int series = 0;
134
                    strm.precision(
135
                        std::numeric_limits<long double>::max_digits10 - 1);
136
                    for (long double const val : item.second)
137
                    {
138
                        if (series)
139
                        {
140
                            strm << ",\n";
141
                        }
142
                        strm << R"(         )" << std::scientific << val;
143
                        ++series;
144
                        average += val;
145
                    }
146
                    strm << "\n       ],\n";
147
                    strm << std::scientific << R"(      "average": )"
148
                         << average / series << "\n";
149
                    strm << "    }";
150
                    ++outputs;
151
                }
152
                if (outputs)
153
                    strm << "\n";
154
                strm << "]\n";
155
                strm << "}\n";
156
            }
157
            else
158
            {
159
                strm << "Results:\n\n";
160
                for (auto&& item : obj.m_map)
161
                {
162
                    long double average = static_cast<long double>(0.0);
163
                    int series = 0;
164
                    strm << "name: " << std::get<0>(item.first) << "\n";
165
                    strm << "executor: " << std::get<1>(item.first) << "\n";
166
                    for (long double const val : item.second)
167
                    {
168
                        ++series;
169
                        average += val;
170
                    }
171
                    strm.precision(
172
                        std::numeric_limits<long double>::max_digits10 - 1);
173
                    strm << std::scientific << "average: " << average / series
174
                         << "\n\n";
175
                }
176
            }
177
            return strm;
178
        }
179

180
        void json_perf_times::add(std::string const& name,
181
            std::string const& executor, long double time)
182
        {
183
            m_map[key_t(name, executor)].push_back(time);
184
        }
185
#endif
186

187
    }    // namespace detail
188

189
#if defined(HPX_HAVE_NANOBENCH)
190
    void perftests_report(std::string const& name, std::string const& exec,
191
        std::size_t const steps, hpx::function<void()>&& test)
192
    {
193
        if (steps == 0)
194
            return;
195

196
        std::size_t const steps_per_epoch =
197
            steps / detail::nanobench_epochs + 1;
198

199
        detail::bench()
200
            .name(name)
201
            .context("executor", exec)
202
            .minEpochIterations(steps_per_epoch)
203
            .run(test);
204
    }
205

206
    // Print all collected results to the provided stream,
207
    // formatted the json according to the provided
208
    // "mustache-style" template
209
    void perftests_print_times(char const* templ, std::ostream& strm)
210
    {
211
        detail::bench().render(templ, strm);
212
    }
213

214
    // Overload that uses a default nanobench template
215
    void perftests_print_times(std::ostream& strm)
216
    {
217
        perftests_print_times(detail::nanobench_hpx_template(), strm);
218
    }
219

220
    // Overload that uses a default nanobench template and prints to std::cout
221
    void perftests_print_times()
222
    {
223
        if (detailed_)
224
            perftests_print_times(detail::nanobench_hpx_template(), std::cout);
225
        else
226
            perftests_print_times(
227
                detail::nanobench_hpx_simple_template(), std::cout);
228
    }
229
#else
230
    void perftests_report(std::string const& name, std::string const& exec,
231
        std::size_t const steps, hpx::function<void()>&& test)
232
    {
233
        if (steps == 0)
234
            return;
235

236
        // First iteration to cache the data
237
        test();
238
        using timer = std::chrono::high_resolution_clock;
239
        for (std::size_t i = 0; i != steps; ++i)
240
        {
241
            // For now, we don't flush the cache
242
            //flush_cache();
243
            timer::time_point start = timer::now();
244
            test();
245
            // default is in seconds
246
            auto time =
247
                std::chrono::duration_cast<std::chrono::duration<long double>>(
248
                    timer::now() - start);
249
            detail::add_time(name, exec, time.count());
250
        }
251
    }
252

253
    void perftests_print_times()
254
    {
255
        std::cout << detail::times();
256
    }
257
#endif
258
}    // 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