• 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

91.1
/examples/quickstart/fibonacci_futures.cpp
1
//  Copyright (c) 2007-2013 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
// This is a purely local version demonstrating different versions of making
8
// the calculation of a fibonacci asynchronous.
9

10
#include <hpx/chrono.hpp>
11
#include <hpx/format.hpp>
12
#include <hpx/future.hpp>
13
#include <hpx/init.hpp>
14

15
#include <cstddef>
16
#include <cstdint>
17
#include <iostream>
18
#include <string>
19
#include <utility>
20

21
///////////////////////////////////////////////////////////////////////////////
22
std::uint64_t threshold = 2;
23

24
///////////////////////////////////////////////////////////////////////////////
25
HPX_NOINLINE std::uint64_t fibonacci_serial(std::uint64_t n)
89✔
26
{
27
    if (n < 2)
177✔
28
        return n;
29
    return fibonacci_serial(n - 1) + fibonacci_serial(n - 2);
88✔
30
}
31

32
///////////////////////////////////////////////////////////////////////////////
33
std::uint64_t add(hpx::future<std::uint64_t> f1, hpx::future<std::uint64_t> f2)
525✔
34
{
35
    return f1.get() + f2.get();
613✔
36
}
37

38
///////////////////////////////////////////////////////////////////////////////
39
struct when_all_wrapper
40
{
41
    typedef hpx::tuple<hpx::future<std::uint64_t>, hpx::future<std::uint64_t>>
42
        data_type;
43

44
    std::uint64_t operator()(hpx::future<data_type> data) const
3✔
45
    {
46
        data_type v = data.get();
3✔
47
        return hpx::get<0>(v).get() + hpx::get<1>(v).get();
6✔
48
    }
49
};
50

51
///////////////////////////////////////////////////////////////////////////////
52
hpx::future<std::uint64_t> fibonacci_future_one(std::uint64_t n);
53

54
struct fibonacci_future_one_continuation
55
{
56
    explicit fibonacci_future_one_continuation(std::uint64_t n)
57
      : n_(n)
88✔
58
    {
59
    }
60

61
    std::uint64_t operator()(hpx::future<std::uint64_t> res) const
88✔
62
    {
63
        return add(fibonacci_future_one(n_ - 2), std::move(res));
176✔
64
    }
65

66
    std::uint64_t n_;
67
};
68

69
std::uint64_t fib(std::uint64_t n)
88✔
70
{
71
    return fibonacci_future_one(n).get();
176✔
72
}
73

74
hpx::future<std::uint64_t> fibonacci_future_one(std::uint64_t n)
177✔
75
{
76
    // if we know the answer, we return a future encapsulating the final value
77
    if (n < 2)
177✔
78
        return hpx::make_ready_future(n);
79
    if (n < threshold)
88✔
80
        return hpx::make_ready_future(fibonacci_serial(n));
×
81

82
    // asynchronously launch the calculation of one of the sub-terms
83
    // attach a continuation to this future which is called asynchronously on
84
    // its completion and which calculates the other sub-term
85
    return hpx::async(&fib, n - 1).then(fibonacci_future_one_continuation(n));
176✔
86
}
87

88
///////////////////////////////////////////////////////////////////////////////
89
std::uint64_t fibonacci(std::uint64_t n)
177✔
90
{
91
    // if we know the answer, we return the final value
92
    if (n < 2)
177✔
93
        return n;
94
    if (n < threshold)
88✔
95
        return fibonacci_serial(n);
×
96

97
    // asynchronously launch the creation of one of the sub-terms of the
98
    // execution graph
99
    hpx::future<std::uint64_t> f = hpx::async(&fibonacci, n - 1);
88✔
100
    std::uint64_t r = fibonacci(n - 2);
88✔
101

102
    return f.get() + r;
88✔
103
}
104

105
///////////////////////////////////////////////////////////////////////////////
106
std::uint64_t fibonacci_fork(std::uint64_t n)
177✔
107
{
108
    // if we know the answer, we return the final value
109
    if (n < 2)
177✔
110
        return n;
111
    if (n < threshold)
88✔
112
        return fibonacci_serial(n);
×
113

114
    // asynchronously launch the creation of one of the sub-terms of the
115
    // execution graph
116
    hpx::future<std::uint64_t> f =
117
        hpx::async(hpx::launch::fork, &fibonacci_fork, n - 1);
88✔
118
    std::uint64_t r = fibonacci_fork(n - 2);
88✔
119

120
    return f.get() + r;
88✔
121
}
122

123
///////////////////////////////////////////////////////////////////////////////
124
hpx::future<std::uint64_t> fibonacci_future(std::uint64_t n)
529✔
125
{
126
    // if we know the answer, we return a future encapsulating the final value
127
    if (n < 2)
529✔
128
        return hpx::make_ready_future(n);
129
    if (n < threshold)
262✔
130
        return hpx::make_ready_future(fibonacci_serial(n));
×
131

132
    // asynchronously launch the creation of one of the sub-terms of the
133
    // execution graph
134
    hpx::future<std::uint64_t> f = hpx::async(&fibonacci_future, n - 1);
262✔
135
    hpx::future<std::uint64_t> r = fibonacci_future(n - 2);
262✔
136

137
    return hpx::async(&add, std::move(f), std::move(r));
138
}
139

140
///////////////////////////////////////////////////////////////////////////////
141
hpx::future<std::uint64_t> fibonacci_future_fork(std::uint64_t n)
177✔
142
{
143
    // if we know the answer, we return a future encapsulating the final value
144
    if (n < 2)
177✔
145
        return hpx::make_ready_future(n);
146
    if (n < threshold)
88✔
147
        return hpx::make_ready_future(fibonacci_serial(n));
×
148

149
    // asynchronously launch the creation of one of the sub-terms of the
150
    // execution graph
151
    hpx::future<std::uint64_t> f =
152
        hpx::async(hpx::launch::fork, &fibonacci_future_fork, n - 1);
88✔
153
    hpx::future<std::uint64_t> r = fibonacci_future_fork(n - 2);
88✔
154

155
    return hpx::async(&add, std::move(f), std::move(r));
156
}
157

158
///////////////////////////////////////////////////////////////////////////////
159
hpx::future<std::uint64_t> fibonacci_future_when_all(std::uint64_t n)
1✔
160
{
161
    // if we know the answer, we return a future encapsulating the final value
162
    if (n < 2)
1✔
163
        return hpx::make_ready_future(n);
164
    if (n < threshold)
1✔
165
        return hpx::make_ready_future(fibonacci_serial(n));
×
166

167
    // asynchronously launch the creation of one of the sub-terms of the
168
    // execution graph
169
    hpx::future<hpx::future<std::uint64_t>> f =
170
        hpx::async(&fibonacci_future, n - 1);
1✔
171
    hpx::future<std::uint64_t> r = fibonacci_future(n - 2);
1✔
172

173
    return hpx::when_all(f.get(), r).then(when_all_wrapper());
3✔
174
}
175

176
hpx::future<std::uint64_t> fibonacci_future_unwrapped_when_all(std::uint64_t n)
1✔
177
{
178
    // if we know the answer, we return a future encapsulating the final value
179
    if (n < 2)
1✔
180
        return hpx::make_ready_future(n);
181
    if (n < threshold)
1✔
182
        return hpx::make_ready_future(fibonacci_serial(n));
×
183

184
    // asynchronously launch the creation of one of the sub-terms of the
185
    // execution graph
186
    hpx::future<std::uint64_t> f = hpx::async(&fibonacci_future, n - 1);
1✔
187
    hpx::future<std::uint64_t> r = fibonacci_future(n - 2);
1✔
188

189
    return hpx::when_all(f, r).then(when_all_wrapper());
1✔
190
}
191

192
/////////////////////////////////////////////////////////////////////////////
193
hpx::future<std::uint64_t> fibonacci_future_all(std::uint64_t n)
353✔
194
{
195
    // if we know the answer, we return a future encapsulating the final value
196
    if (n < 2)
353✔
197
        return hpx::make_ready_future(n);
198
    if (n < threshold)
175✔
199
        return hpx::make_ready_future(fibonacci_serial(n));
×
200

201
    // asynchronously launch the calculation of both of the sub-terms
202
    hpx::future<std::uint64_t> f1 = fibonacci_future_all(n - 1);
175✔
203
    hpx::future<std::uint64_t> f2 = fibonacci_future_all(n - 2);
175✔
204

205
    // create a future representing the successful calculation of both sub-terms
206
    return hpx::async(&add, std::move(f1), std::move(f2));
350✔
207
}
208

209
/////////////////////////////////////////////////////////////////////////////
210
hpx::future<std::uint64_t> fibonacci_future_all_when_all(std::uint64_t n)
1✔
211
{
212
    // if we know the answer, we return a future encapsulating the final value
213
    if (n < 2)
1✔
214
        return hpx::make_ready_future(n);
215
    if (n < threshold)
1✔
216
        return hpx::make_ready_future(fibonacci_serial(n));
×
217

218
    // asynchronously launch the calculation of both of the sub-terms
219
    hpx::future<std::uint64_t> f1 = fibonacci_future_all(n - 1);
1✔
220
    hpx::future<std::uint64_t> f2 = fibonacci_future_all(n - 2);
1✔
221

222
    // create a future representing the successful calculation of both sub-terms
223
    // attach a continuation to this future which is called asynchronously on
224
    // its completion and which calculates the final result
225
    return hpx::when_all(f1, f2).then(when_all_wrapper());
1✔
226
}
227

228
///////////////////////////////////////////////////////////////////////////////
229
int hpx_main(hpx::program_options::variables_map& vm)
1✔
230
{
231
    // extract command line argument, i.e. fib(N)
232
    std::uint64_t n = vm["n-value"].as<std::uint64_t>();
2✔
233
    std::string test = vm["test"].as<std::string>();
1✔
234
    std::uint64_t max_runs = vm["n-runs"].as<std::uint64_t>();
2✔
235

236
    if (max_runs == 0)
1✔
237
    {
238
        std::cerr << "fibonacci_futures: wrong command line argument value for "
239
                     "option 'n-runs', should not be zero"
240
                  << std::endl;
241
        return hpx::local::finalize();    // Handles HPX shutdown
×
242
    }
243

244
    threshold = vm["threshold"].as<unsigned int>();
2✔
245
    if (threshold < 2 || threshold > n)
1✔
246
    {
247
        std::cerr << "fibonacci_futures: wrong command line argument value for "
248
                     "option 'threshold', should be in between 2 and n-value"
249
                     ", value specified: "
250
                  << threshold << std::endl;
×
251
        return hpx::local::finalize();    // Handles HPX shutdown
×
252
    }
253

254
    bool executed_one = false;
255
    std::uint64_t r = 0;
1✔
256

257
    if (test == "all" || test == "0")
1✔
258
    {
259
        // Keep track of the time required to execute.
260
        std::uint64_t start = hpx::chrono::high_resolution_clock::now();
261

262
        for (std::size_t i = 0; i != max_runs; ++i)
2✔
263
        {
264
            // Create a Future for the whole calculation, execute it locally,
265
            // and wait for it.
266
            r = fibonacci_serial(n);
1✔
267
        }
268

269
        std::uint64_t d = hpx::chrono::high_resolution_clock::now() - start;
1✔
270
        char const* fmt = "fibonacci_serial({1}) == {2},"
271
                          "elapsed time:,{3},[s]\n";
272
        hpx::util::format_to(std::cout, fmt, n, r, d / max_runs);
1✔
273

274
        executed_one = true;
275
    }
276

277
    if (test == "all" || test == "1")
1✔
278
    {
279
        // Keep track of the time required to execute.
280
        std::uint64_t start = hpx::chrono::high_resolution_clock::now();
281

282
        for (std::size_t i = 0; i != max_runs; ++i)
2✔
283
        {
284
            // Create a Future for the whole calculation, execute it locally,
285
            // and wait for it.
286
            r = fibonacci_future_one(n).get();
1✔
287
        }
288

289
        std::uint64_t d = hpx::chrono::high_resolution_clock::now() - start;
1✔
290
        char const* fmt = "fibonacci_future_one({1}) == {2},"
291
                          "elapsed time:,{3},[s]\n";
292
        hpx::util::format_to(std::cout, fmt, n, r, d / max_runs);
1✔
293

294
        executed_one = true;
295
    }
296

297
    if (test == "all" || test == "2")
1✔
298
    {
299
        // Keep track of the time required to execute.
300
        std::uint64_t start = hpx::chrono::high_resolution_clock::now();
301

302
        for (std::size_t i = 0; i != max_runs; ++i)
2✔
303
        {
304
            // Create a Future for the whole calculation, execute it locally, and
305
            // wait for it.
306
            r = fibonacci(n);
1✔
307
        }
308

309
        std::uint64_t d = hpx::chrono::high_resolution_clock::now() - start;
1✔
310
        char const* fmt = "fibonacci({1}) == {2},elapsed time:,{3},[s]\n";
311
        hpx::util::format_to(std::cout, fmt, n, r, d / max_runs);
1✔
312

313
        executed_one = true;
314
    }
315

316
    if (test == "all" || test == "9")
1✔
317
    {
318
        // Keep track of the time required to execute.
319
        std::uint64_t start = hpx::chrono::high_resolution_clock::now();
320

321
        for (std::size_t i = 0; i != max_runs; ++i)
2✔
322
        {
323
            // Create a Future for the whole calculation, execute it locally, and
324
            // wait for it. Use continuation stealing
325
            r = fibonacci_fork(n);
1✔
326
        }
327

328
        std::uint64_t d = hpx::chrono::high_resolution_clock::now() - start;
1✔
329
        char const* fmt = "fibonacci_fork({1}) == {2},elapsed time:,{3},[s]\n";
330
        hpx::util::format_to(std::cout, fmt, n, r, d / max_runs);
1✔
331

332
        executed_one = true;
333
    }
334

335
    if (test == "all" || test == "3")
1✔
336
    {
337
        // Keep track of the time required to execute.
338
        std::uint64_t start = hpx::chrono::high_resolution_clock::now();
339

340
        for (std::size_t i = 0; i != max_runs; ++i)
2✔
341
        {
342
            // Create a Future for the whole calculation, execute it locally, and
343
            // wait for it.
344
            r = fibonacci_future(n).get();
1✔
345
        }
346

347
        std::uint64_t d = hpx::chrono::high_resolution_clock::now() - start;
1✔
348
        char const* fmt =
349
            "fibonacci_future({1}) == {2},elapsed time:,{3},[s]\n";
350
        hpx::util::format_to(std::cout, fmt, n, r, d / max_runs);
1✔
351

352
        executed_one = true;
353
    }
354

355
    if (test == "all" || test == "8")
1✔
356
    {
357
        // Keep track of the time required to execute.
358
        std::uint64_t start = hpx::chrono::high_resolution_clock::now();
359

360
        for (std::size_t i = 0; i != max_runs; ++i)
2✔
361
        {
362
            // Create a Future for the whole calculation, execute it locally, and
363
            // wait for it. Use continuation stealing.
364
            r = fibonacci_future_fork(n).get();
1✔
365
        }
366

367
        std::uint64_t d = hpx::chrono::high_resolution_clock::now() - start;
1✔
368
        char const* fmt =
369
            "fibonacci_future_fork({1}) == {2},elapsed time:,{3},[s]\n";
370
        hpx::util::format_to(std::cout, fmt, n, r, d / max_runs);
1✔
371

372
        executed_one = true;
373
    }
374

375
    if (test == "all" || test == "6")
1✔
376
    {
377
        // Keep track of the time required to execute.
378
        std::uint64_t start = hpx::chrono::high_resolution_clock::now();
379

380
        for (std::size_t i = 0; i != max_runs; ++i)
2✔
381
        {
382
            // Create a Future for the whole calculation, execute it locally, and
383
            // wait for it.
384
            r = fibonacci_future_when_all(n).get();
1✔
385
        }
386

387
        std::uint64_t d = hpx::chrono::high_resolution_clock::now() - start;
1✔
388
        char const* fmt =
389
            "fibonacci_future_when_all({1}) == {2},elapsed time:,{3},[s]\n";
390
        hpx::util::format_to(std::cout, fmt, n, r, d / max_runs);
1✔
391

392
        executed_one = true;
393
    }
394

395
    if (test == "all" || test == "7")
1✔
396
    {
397
        // Keep track of the time required to execute.
398
        std::uint64_t start = hpx::chrono::high_resolution_clock::now();
399

400
        for (std::size_t i = 0; i != max_runs; ++i)
2✔
401
        {
402
            // Create a Future for the whole calculation, execute it locally, and
403
            // wait for it.
404
            r = fibonacci_future_unwrapped_when_all(n).get();
1✔
405
        }
406

407
        std::uint64_t d = hpx::chrono::high_resolution_clock::now() - start;
1✔
408
        char const* fmt = "fibonacci_future_unwrapped_when_all({1}) == "
409
                          "{2},elapsed time:,{3},[s]\n";
410
        hpx::util::format_to(std::cout, fmt, n, r, d / max_runs);
1✔
411

412
        executed_one = true;
413
    }
414

415
    if (test == "all" || test == "4")
1✔
416
    {
417
        // Keep track of the time required to execute.
418
        std::uint64_t start = hpx::chrono::high_resolution_clock::now();
419

420
        for (std::size_t i = 0; i != max_runs; ++i)
2✔
421
        {
422
            // Create a future for the whole calculation, execute it locally, and
423
            // wait for it.
424
            r = fibonacci_future_all(n).get();
1✔
425
        }
426

427
        std::uint64_t d = hpx::chrono::high_resolution_clock::now() - start;
1✔
428
        char const* fmt =
429
            "fibonacci_future_all({1}) == {2},elapsed time:,{3},[s]\n";
430
        hpx::util::format_to(std::cout, fmt, n, r, d / max_runs);
1✔
431

432
        executed_one = true;
433
    }
434

435
    if (test == "all" || test == "5")
1✔
436
    {
437
        // Keep track of the time required to execute.
438
        std::uint64_t start = hpx::chrono::high_resolution_clock::now();
439

440
        for (std::size_t i = 0; i != max_runs; ++i)
2✔
441
        {
442
            // Create a Future for the whole calculation, execute it locally, and
443
            // wait for it.
444
            r = fibonacci_future_all_when_all(n).get();
1✔
445
        }
446

447
        std::uint64_t d = hpx::chrono::high_resolution_clock::now() - start;
1✔
448
        char const* fmt =
449
            "fibonacci_future_all_when_all({1}) == {2},elapsed time:,{3},[s]\n";
450
        hpx::util::format_to(std::cout, fmt, n, r, d / max_runs);
1✔
451

452
        executed_one = true;
453
    }
454

455
    if (!executed_one)
×
456
    {
457
        std::cerr << "fibonacci_futures: wrong command line argument value for "
458
                     "option 'tests', should be either 'all' or a number "
459
                     "between zero "
460
                     "and 7, value specified: "
461
                  << test << std::endl;
462
    }
463

464
    return hpx::local::finalize();    // Handles HPX shutdown
1✔
465
}
466

467
///////////////////////////////////////////////////////////////////////////////
468
int main(int argc, char* argv[])
1✔
469
{
470
    // Configure application-specific options
471
    hpx::program_options::options_description desc_commandline(
472
        "Usage: " HPX_APPLICATION_STRING " [options]");
1✔
473

474
    using hpx::program_options::value;
475
    // clang-format off
476
    desc_commandline.add_options()
1✔
477
        ("n-value", value<std::uint64_t>()->default_value(10),
1✔
478
         "n value for the Fibonacci function")
479
        ("n-runs", value<std::uint64_t>()->default_value(1),
1✔
480
         "number of runs to perform")
481
        ("threshold", value<unsigned int>()->default_value(2),
1✔
482
         "threshold for switching to serial code")
483
        ("test", value<std::string>()->default_value("all"),
1✔
484
        "select tests to execute (0-9, default: all)");
485
    // clang-format on
486

487
    // Initialize and run HPX
488
    hpx::local::init_params init_args;
1✔
489
    init_args.desc_cmdline = desc_commandline;
1✔
490

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

© 2025 Coveralls, Inc