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

STEllAR-GROUP / hpx / #873

24 Jan 2023 10:55PM UTC coverage: 85.883% (+0.2%) from 85.694%
#873

push

StellarBot
Merge #6152

6152: The -rd and -mr options didn't work, and they should have been --rd and --mr r=hkaiser a=stevenrbrandt

The arg parsing logic was broken in a number of ways. For example, if any option was provided after -rd (RelWithDebInfo), it automatically reverted to -r (Release). The same for -g, etc. In addition "-rd" is non-standard for a multi-letter unix arg. It was changed to --rd.


Co-authored-by: Steven R. Brandt <sbrandt@cct.lsu.edu>

173457 of 201969 relevant lines covered (85.88%)

2069076.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.74
/libs/core/resiliency/tests/performance/replicate/1d_stencil_replicate.cpp
1
//  Copyright (c) 2019 National Technology & Engineering Solutions of Sandia,
2
//                     LLC (NTESS).
3
//  Copyright (c) 2014-2022 Hartmut Kaiser
4
//  Copyright (c) 2014 Patricia Grubel
5
//  Copyright (c) 2019 Nikunj Gupta
6
//
7
//  SPDX-License-Identifier: BSL-1.0
8
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
9
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10

11
// This is the fourth in a series of examples demonstrating the development of
12
// a fully distributed solver for a simple 1D heat distribution problem.
13
//
14
// This example builds on example three. It futurizes the code from that
15
// example. Compared to example two this code runs much more efficiently. It
16
// allows for changing the amount of work executed in one HPX thread which
17
// enables tuning the performance for the optimal grain size of the
18
// computation. This example is still fully local but demonstrates nice
19
// scalability on SMP machines.
20

21
#include <hpx/local/algorithm.hpp>
22
#include <hpx/local/init.hpp>
23
#include <hpx/modules/iterator_support.hpp>
24
#include <hpx/modules/resiliency.hpp>
25
#include <hpx/modules/synchronization.hpp>
26

27
#include <atomic>
28
#include <cstddef>
29
#include <cstdint>
30
#include <exception>
31
#include <iostream>
32
#include <memory>
33
#include <random>
34
#include <utility>
35
#include <vector>
36

37
struct validate_exception : std::exception
×
38
{
39
};
40

41
///////////////////////////////////////////////////////////////////////////////
42
double const pi = std::acos(-1.0);
1✔
43

44
// Variable to count the number of failed attempts
45
std::atomic<int> counter(0);
46

47
// Variables to generate errors
48
std::random_device rd;
1✔
49
std::mt19937 gen(rd());
1✔
50

51
///////////////////////////////////////////////////////////////////////////////
52
// Our partition data type
53
struct partition_data
2,420✔
54
{
55
public:
56
    partition_data(std::size_t size)
500✔
57
      : data_(size)
500✔
58
      , size_(size)
500✔
59
    {
60
    }
500✔
61

62
    partition_data(std::size_t subdomain_width, double subdomain_index,
10✔
63
        std::size_t subdomains)
64
      : data_(subdomain_width + 1)
10✔
65
      , size_(subdomain_width + 1)
10✔
66
    {
67
        for (std::size_t k = 0; k != subdomain_width + 1; ++k)
1,300✔
68
        {
69
            data_[k] = std::sin(2 * pi *
2,580✔
70
                ((0.0 + subdomain_width * subdomain_index + k) /
2,580✔
71
                    static_cast<double>(subdomain_width * subdomains)));
1,290✔
72
        }
1,290✔
73
    }
10✔
74

75
    partition_data(partition_data&& other)
1,910✔
76
      : data_(std::move(other.data_))
1,910✔
77
      , size_(other.size_)
1,910✔
78
    {
79
    }
1,910✔
80

81
    double& operator[](std::size_t idx)
4,609,500✔
82
    {
83
        return data_[idx];
4,609,500✔
84
    }
85
    double operator[](std::size_t idx) const
×
86
    {
87
        return data_[idx];
×
88
    }
89

90
    friend std::vector<double>::const_iterator begin(const partition_data& v)
1,500✔
91
    {
92
        return begin(v.data_);
1,500✔
93
    }
94
    friend std::vector<double>::const_iterator end(const partition_data& v)
1,500✔
95
    {
96
        return end(v.data_);
1,500✔
97
    }
98

99
    std::size_t size() const
500✔
100
    {
101
        return size_;
500✔
102
    }
103

104
    void resize(std::size_t size)
500✔
105
    {
106
        data_.resize(size);
500✔
107
        size_ = size;
500✔
108
    }
500✔
109

110
private:
111
    std::vector<double> data_;
112
    std::size_t size_;
113
};
114

115
std::ostream& operator<<(std::ostream& os, partition_data const& c)
×
116
{
117
    os << "{";
×
118
    for (std::size_t i = 0; i != c.size() - 1; ++i)
×
119
    {
120
        if (i != 0)
×
121
            os << ", ";
×
122
        os << c[i];
×
123
    }
×
124
    os << "}";
×
125
    return os;
×
126
}
127

128
///////////////////////////////////////////////////////////////////////////////
129
struct stepper
130
{
131
    // Our data for one time step
132
    typedef hpx::shared_future<partition_data> partition;
133
    typedef std::vector<partition> space;
134

135
    // Our operator
136
    static double stencil(double left, double center, double right)
1,152,000✔
137
    {
138
        return 0.5 * (0.75) * left + (0.75) * center - 0.5 * (0.25) * right;
1,152,000✔
139
    }
140

141
    static double left_flux(double left, double center)
142
    {
143
        return (0.625) * left - (0.125) * center;
144
    }
145

146
    static double right_flux(double center, double right)
147
    {
148
        return 0.5 * (0.75) * center + (1.125) * right;
149
    }
150

151
    // The partitioned operator, it invokes the heat operator above on all
152
    // elements of a partition.
153
    static partition_data heat_part(std::size_t sti, double error,
500✔
154
        partition_data const& left_input, partition_data const& center_input,
155
        partition_data const& right_input)
156
    {
157
        static thread_local std::exponential_distribution<> dist_(error);
500✔
158

159
        double num = dist_(gen);
500✔
160
        bool error_flag = false;
500✔
161

162
        // Probability of error occurrence is proportional to exp(-error_rate)
163
        if (num > 1.0)
500✔
164
        {
165
            error_flag = true;
×
166
            ++counter;
×
167
        }
×
168

169
        std::size_t const size = center_input.size() - 1;
500✔
170
        partition_data workspace(size + 2 * sti + 1);
500✔
171

172
        std::copy(
500✔
173
            end(left_input) - sti - 1, end(left_input) - 1, &workspace[0]);
500✔
174
        std::copy(begin(center_input), end(center_input) - 1, &workspace[sti]);
500✔
175
        std::copy(begin(right_input), begin(right_input) + sti + 1,
500✔
176
            &workspace[size + sti]);
500✔
177

178
        for (std::size_t t = 0; t != sti; ++t)
8,500✔
179
        {
180
            for (std::size_t k = 0; k != size + 2 * sti - 1 - 2 * t; ++k)
1,160,000✔
181
                workspace[k] =
1,152,000✔
182
                    stencil(workspace[k], workspace[k + 1], workspace[k + 2]);
1,152,000✔
183
        }
8,000✔
184

185
        workspace.resize(size + 1);
500✔
186

187
        // Artificial error injection to get replay in action
188
        if (error_flag)
500✔
189
            throw validate_exception();
×
190

191
        return workspace;
500✔
192
    }
500✔
193

194
    hpx::future<space> do_work(std::size_t subdomains,
1✔
195
        std::size_t subdomain_width, std::size_t iterations, std::size_t sti,
196
        std::uint64_t nd, std::uint64_t n_value, double error,
197
        hpx::sliding_semaphore& sem)
198
    {
199
        using hpx::unwrapping;
200
        using hpx::resiliency::experimental::dataflow_replicate;
201

202
        // U[t][i] is the state of position i at time t.
203
        std::vector<space> U(2);
1✔
204
        for (space& s : U)
3✔
205
            s.resize(subdomains);
2✔
206

207
        auto range = hpx::util::counting_shape(subdomains);
1✔
208
        hpx::ranges::for_each(hpx::execution::par, range,
1✔
209
            [&U, subdomain_width, subdomains](std::size_t i) {
11✔
210
                U[0][i] = hpx::make_ready_future(
10✔
211
                    partition_data(subdomain_width, double(i), subdomains));
10✔
212
            });
10✔
213

214
        auto Op = unwrapping(&stepper::heat_part);
1✔
215

216
        // Actual time step loop
217
        for (std::size_t t = 0; t != iterations; ++t)
11✔
218
        {
219
            space const& current = U[t % 2];
10✔
220
            space& next = U[(t + 1) % 2];
10✔
221

222
            for (std::size_t i = 0; i != subdomains; ++i)
110✔
223
            {
224
                next[i] = dataflow_replicate(n_value, Op, sti, error,
100✔
225
                    current[(i - 1 + subdomains) % subdomains], current[i],
100✔
226
                    current[(i + 1) % subdomains]);
100✔
227
            }
100✔
228

229
            // every nd time steps, attach additional continuation which will
230
            // trigger the semaphore once computation has reached this point
231
            if ((t % nd) == 0)
10✔
232
            {
233
                next[0].then([&sem, t](partition&&) {
2✔
234
                    // inform semaphore about new lower limit
235
                    sem.signal(t);
1✔
236
                });
1✔
237
            }
1✔
238

239
            // suspend if the tree has become too deep, the continuation above
240
            // will resume this thread once the computation has caught up
241
            sem.wait(t);
10✔
242
        }
10✔
243

244
        // Return the solution at time-step 'iterations'.
245
        return hpx::when_all(U[iterations % 2]);
1✔
246
    }
1✔
247
};
248

249
///////////////////////////////////////////////////////////////////////////////
250
int hpx_main(hpx::program_options::variables_map& vm)
1✔
251
{
252
    std::uint64_t n_value =
1✔
253
        vm["n-value"].as<std::uint64_t>();    // Number of partitions.
1✔
254
    std::uint64_t subdomains =
1✔
255
        vm["subdomains"].as<std::uint64_t>();    // Number of partitions.
1✔
256
    std::uint64_t subdomain_width =
1✔
257
        vm["subdomain-width"].as<std::uint64_t>();    // Number of grid points.
1✔
258
    std::uint64_t iterations =
1✔
259
        vm["iterations"].as<std::uint64_t>();    // Number of steps.
1✔
260
    std::uint64_t nd =
1✔
261
        vm["nd"].as<std::uint64_t>();    // Max depth of dep tree.
1✔
262
    std::uint64_t sti =
1✔
263
        vm["steps-per-iteration"]
2✔
264
            .as<std::uint64_t>();    // Number of time steps per iteration
1✔
265
    double error = vm["error-rate"].as<double>();
1✔
266

267
    // Create the stepper object
268
    stepper step;
269

270
    std::cout << "Starting 1d stencil with dataflow replicate" << std::endl;
1✔
271

272
    // Measure execution time.
273
    std::uint64_t t = hpx::chrono::high_resolution_clock::now();
1✔
274

275
    {
276
        // limit depth of dependency tree
277
        hpx::sliding_semaphore sem(nd);
1✔
278

279
        hpx::future<stepper::space> result = step.do_work(subdomains,
2✔
280
            subdomain_width, iterations, sti, nd, n_value, error, sem);
1✔
281

282
        stepper::space solution = result.get();
1✔
283
        hpx::wait_all(solution);
1✔
284
    }
1✔
285

286
    std::cout << "Time elapsed: "
1✔
287
              << static_cast<double>(
1✔
288
                     hpx::chrono::high_resolution_clock::now() - t) /
1✔
289
            1e9
290
              << std::endl;
1✔
291
    std::cout << "Errors occurred: " << counter << std::endl;
1✔
292

293
    // for (std::size_t i = 0; i != subdomains; ++i)
294
    //     std::cout << solution[i].get() << " ";
295
    // std::cout << std::endl;
296

297
    return hpx::local::finalize();
1✔
298
}
×
299

300
int main(int argc, char* argv[])
1✔
301
{
302
    using namespace hpx::program_options;
303

304
    // Configure application-specific options.
305
    options_description desc_commandline;
1✔
306

307
    desc_commandline.add_options()(
1✔
308
        "results", "print generated results (default: false)");
309

310
    desc_commandline.add_options()("n-value",
2✔
311
        value<std::uint64_t>()->default_value(5), "Number of allowed replays");
1✔
312

313
    desc_commandline.add_options()("error-rate",
2✔
314
        value<double>()->default_value(5), "Error rate for injecting errors");
1✔
315

316
    desc_commandline.add_options()("subdomain-width",
2✔
317
        value<std::uint64_t>()->default_value(128),
1✔
318
        "Local x dimension (of each partition)");
319

320
    desc_commandline.add_options()("iterations",
2✔
321
        value<std::uint64_t>()->default_value(10), "Number of time steps");
1✔
322

323
    desc_commandline.add_options()("steps-per-iteration",
2✔
324
        value<std::uint64_t>()->default_value(16),
1✔
325
        "Number of time steps per iterations");
326

327
    desc_commandline.add_options()("nd",
2✔
328
        value<std::uint64_t>()->default_value(10),
1✔
329
        "Number of time steps to allow the dependency tree to grow to");
330

331
    desc_commandline.add_options()("subdomains",
2✔
332
        value<std::uint64_t>()->default_value(10), "Number of partitions");
1✔
333

334
    // Initialize and run HPX
335
    hpx::local::init_params init_args;
1✔
336
    init_args.desc_cmdline = desc_commandline;
1✔
337

338
    return hpx::local::init(hpx_main, argc, argv, init_args);
1✔
339
}
1✔
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