• 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.53
/examples/quickstart/receive_buffer.cpp
1
//  Copyright (c) 2016-2022 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 example demonstrates the use of the hpx::lcos::local::receive_buffer
8
// facility It can be used to decouple time-step based operations between
9
// remote partitions of a spatially decomposed problem.
10

11
// Including 'hpx/hpx_main.hpp' instead of the usual 'hpx/hpx_init.hpp' enables
12
// to use the plain C-main below as the direct main HPX entry point.
13
#include <hpx/config.hpp>
14
#if !defined(HPX_COMPUTE_DEVICE_CODE)
15
#include <hpx/hpx.hpp>
16
#include <hpx/hpx_main.hpp>
17

18
#include <cstddef>
19
#include <deque>
20
#include <utility>
21

22
// This example assumes that the computational space is divided into two
23
// partitions. Here we place both partitions on the same locality, but they
24
// could be easily placed on different HPX localities without any changes to
25
// the code as well.
26
//
27
// The example rotates the data stored in both partitions by one position
28
// during each time step while making sure that the right-most value is
29
// transferred to the neighboring partition.
30
//
31
// Each partition is represented by a component type 'partition' which holds
32
// the data (here a simple std::deque<int>) and an instance of a
33
// receive_buffer for the neighboring partition. The two partitions in
34
// this example are connected in a circular fashion, thus both of them have
35
// one receive_buffer, always representing the data to be received from the
36
// 'left'.
37

38
char const* partition_basename = "/receive_buffer_example/partition/";
39

40
// The neighbor of partition '0' is partition '1', and v.v.
41
std::size_t neighbor(std::size_t partition_num)
×
42
{
43
    return partition_num == 0 ? 1 : 0;
×
44
}
45

46
///////////////////////////////////////////////////////////////////////////////
47
struct partition_server : hpx::components::component_base<partition_server>
48
{
49
    partition_server() {}
50

51
    // Retrieve the neighboring partition
52
    partition_server(std::size_t partition_num, std::size_t num_elements)
2✔
53
      : data_(num_elements)
2✔
54
      , left_(hpx::find_from_basename(
4✔
55
            partition_basename, neighbor(partition_num)))
56
    {
57
        // fill with some random data
58
        std::generate(data_.begin(), data_.end(), std::rand);
59
    }
2✔
60

61
public:
62
    // Action definitions
63

64
    // Do all the work for 'nt' time steps on the local
65
    hpx::future<void> do_work(std::size_t nt);
66
    HPX_DEFINE_COMPONENT_ACTION(partition_server, do_work, do_work_action)
67

68
    // Receive the data from the left partition. This will be called by the
69
    // other partition, sending us its data.
70
    void from_right(std::size_t timestep, int data)
200✔
71
    {
72
        right_buffer_.store_received(timestep, std::move(data));
200✔
73
    }
200✔
74
    HPX_DEFINE_COMPONENT_ACTION(partition_server, from_right, from_right_action)
75

76
    // Explicitly release dependencies to avoid circular dependencies in the
77
    // reference counting chain.
78
    void release_dependencies()
2✔
79
    {
80
        left_.free();
81
    }
2✔
82
    HPX_DEFINE_COMPONENT_ACTION(
83
        partition_server, release_dependencies, release_dependencies_action)
84

85
public:
86
    // Other helper functions
87

88
    // Helper function to send our boundary elements to the left neighbor.
89
    void send_left(std::size_t timestep, int data) const
200✔
90
    {
91
        hpx::post(from_right_action(), left_, timestep, data);
92
    }
200✔
93

94
    // Helper function to receive the boundary element from the right neighbor.
95
    hpx::future<int> receive_right(std::size_t timestep)
96
    {
97
        return right_buffer_.receive(timestep);
200✔
98
    }
99

100
private:
101
    // Data stored in this partition.
102
    std::deque<int> data_;
103

104
    // The id held by the future represents the neighboring partition (the one
105
    // where the next element should be sent to).
106
    hpx::components::client<partition_server> left_;
107

108
    // The receive buffers represents one single int to be received from the
109
    // corresponding neighbor.
110
    hpx::lcos::local::receive_buffer<int> right_buffer_;
111
};
112

113
// The macros below are necessary to generate the code required for exposing
114
// our partition type remotely.
115
//
116
// HPX_REGISTER_COMPONENT() exposes the component creation through hpx::new_<>().
117
typedef hpx::components::component<partition_server> partition_server_type;
118
HPX_REGISTER_COMPONENT(partition_server_type, partition_server)
8✔
119

120
// HPX_REGISTER_ACTION() exposes the component member function for remote
121
// invocation.
122
typedef partition_server::from_right_action from_right_action;
123
HPX_REGISTER_ACTION(from_right_action)
×
124

125
typedef partition_server::do_work_action do_work_action;
126
HPX_REGISTER_ACTION(do_work_action)
×
127

128
typedef partition_server::release_dependencies_action
129
    release_dependencies_action;
130
HPX_REGISTER_ACTION(release_dependencies_action)
×
131

132
///////////////////////////////////////////////////////////////////////////////
133
struct partition : hpx::components::client_base<partition, partition_server>
134
{
135
    typedef hpx::components::client_base<partition, partition_server> base_type;
136

137
    partition(hpx::id_type const& locality, std::size_t partition_num,
2✔
138
        std::size_t num_elements)
139
      : base_type(
2✔
140
            hpx::new_<partition_server>(locality, partition_num, num_elements))
4✔
141
      , partition_num_(partition_num)
2✔
142
      , registered_name_(true)
2✔
143
    {
144
        // Register this partition with the runtime so that its neighbor can
145
        // find it.
146
        hpx::register_with_basename(partition_basename, *this, partition_num)
2✔
147
            .get();
2✔
148
    }
2✔
149

150
    partition(hpx::future<hpx::id_type>&& id)
151
      : base_type(std::move(id))
2✔
152
      , partition_num_(0)
2✔
153
      , registered_name_(false)
2✔
154
    {
155
    }
156

157
    ~partition()
4✔
158
    {
2✔
159
        if (!registered_name_)
4✔
160
            return;
2✔
161

162
        // break cyclic dependencies
163
        hpx::future<void> f1 = hpx::async(release_dependencies_action(), *this);
164

165
        // release the reference held by AGAS
166
        hpx::future<void> f2 =
167
            hpx::unregister_with_basename(partition_basename, partition_num_);
4✔
168

169
        hpx::wait_all(f1, f2);    // ignore exceptions
170
    }
4✔
171

172
    hpx::future<void> do_work(std::size_t nt)
2✔
173
    {
174
        return hpx::async(do_work_action(), *this, nt);
2✔
175
    }
176

177
private:
178
    std::size_t partition_num_;
179
    bool registered_name_;
180
};
181

182
///////////////////////////////////////////////////////////////////////////////
183
// This is the implementation of the time step loop
184
hpx::future<void> partition_server::do_work(std::size_t nt)
2✔
185
{
186
    // send initial values to neighbors
187
    if (nt != 0)
2✔
188
    {
189
        // send left-most element
190
        send_left(0, data_[0]);
2✔
191

192
        // rotate left by one element
193
        std::rotate(data_.begin(), data_.begin() + 1, data_.end());
2✔
194
    }
195

196
    hpx::future<void> result = hpx::make_ready_future();
197
    for (std::size_t t = 0; t != nt; ++t)
202✔
198
    {
199
        // Receive element from the right, replace last local element with the
200
        // received value.
201
        //
202
        // Each timestep depends on a) the previous timestep and b) the
203
        // received value for the current timestep.
204
        result = hpx::dataflow(
200✔
205
            [this, t, nt](hpx::future<void> result, hpx::future<int> f) {
798✔
206
                result.get();    // propagate exceptions
200✔
207

208
                // replace right-most element with received value
209
                data_[data_.size() - 1] = f.get();
200✔
210

211
                // if not last time step, send left-most and rotate left
212
                // by one element
213
                if (t != nt - 1)
200✔
214
                {
215
                    send_left(t + 1, data_[0]);
198✔
216
                    std::rotate(data_.begin(), data_.begin() + 1, data_.end());
198✔
217
                }
218
            },
200✔
219
            result, receive_right(t));
200✔
220
    }
221
    return result;
2✔
222
}
223

224
///////////////////////////////////////////////////////////////////////////////
225
int main()
1✔
226
{
227
    // Initial conditions: f(0, i) = i
228
    hpx::id_type here = hpx::find_here();
1✔
229

230
    // create partitions and launch work
231
    partition p0(here, 0, 1000);
1✔
232
    partition p1(here, 1, 1000);
1✔
233

234
    hpx::future<void> f0 = p0.do_work(100);
1✔
235
    hpx::future<void> f1 = p1.do_work(100);
1✔
236

237
    // wait for both partitions to be finished
238
    hpx::wait_all(f0, f1);
239

240
    return 0;
241
}
1✔
242

243
#endif
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