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

STEllAR-GROUP / hpx / #874

25 Jan 2023 02:55PM UTC coverage: 85.911% (+0.03%) from 85.883%
#874

push

StellarBot
Merge #6153

6153: Assign global ids to managed component instances that are locally resolvable r=hkaiser a=hkaiser

This will reduce contention while resolving global ids.

Co-authored-by: Hartmut Kaiser <hartmut.kaiser@gmail.com>

61 of 61 new or added lines in 5 files covered. (100.0%)

173513 of 201968 relevant lines covered (85.91%)

2065249.0 hits per line

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

79.27
/libs/full/runtime_components/tests/unit/components/migrate_polymorphic_component.cpp
1
//  Copyright (c) 2019 Maximilian Bremer
2
//  Copyright (c) 2019 Hartmut Kaiser
3
//
4
//  SPDX-License-Identifier: BSL-1.0
5
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
6
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7

8
#include <hpx/config.hpp>
9
#if !defined(HPX_COMPUTE_DEVICE_CODE)
10
#include <hpx/hpx_main.hpp>
11
#include <hpx/include/actions.hpp>
12
#include <hpx/include/components.hpp>
13
#include <hpx/include/lcos.hpp>
14
#include <hpx/include/runtime.hpp>
15
#include <hpx/include/serialization.hpp>
16
#include <hpx/iostream.hpp>
17
#include <hpx/modules/testing.hpp>
18

19
#include <cstddef>
20
#include <cstdint>
21
#include <type_traits>
22
#include <utility>
23
#include <vector>
24

25
///////////////////////////////////////////////////////////////////////////////
26
struct test_server_base
27
  : hpx::components::abstract_base_migration_support<
28
        hpx::components::abstract_component_base<test_server_base>>
29
{
30
    test_server_base(int base_data = 0)
286✔
31
      : base_data_(base_data)
286✔
32
    {
572✔
33
    }
286✔
34
    virtual ~test_server_base() = default;
286✔
35

36
    hpx::id_type call() const
439✔
37
    {
38
        return hpx::find_here();
439✔
39
    }
40
    HPX_DEFINE_COMPONENT_ACTION(test_server_base, call, call_action)
41

42
    void busy_work() const
1✔
43
    {
44
        HPX_TEST_NEQ(pin_count(), std::uint32_t(0));
1✔
45
        hpx::this_thread::sleep_for(std::chrono::seconds(1));
1✔
46
        HPX_TEST_NEQ(pin_count(), std::uint32_t(0));
1✔
47
    }
1✔
48
    HPX_DEFINE_COMPONENT_ACTION(test_server_base, busy_work, busy_work_action)
49

50
    hpx::future<void> lazy_busy_work() const
1✔
51
    {
52
        HPX_TEST_NEQ(pin_count(), std::uint32_t(0));
1✔
53

54
        auto f = hpx::make_ready_future_after(std::chrono::seconds(1));
1✔
55

56
        return f.then([this](hpx::future<void>&& f) -> void {
2✔
57
            HPX_TEST_NEQ(pin_count(), std::uint32_t(0));
1✔
58
            f.get();
1✔
59
            HPX_TEST_NEQ(pin_count(), std::uint32_t(0));
1✔
60
        });
1✔
61
    }
1✔
62
    HPX_DEFINE_COMPONENT_ACTION(
63
        test_server_base, lazy_busy_work, lazy_busy_work_action)
64

65
    int get_base_data() const
541✔
66
    {
67
        HPX_TEST_NEQ(pin_count(), std::uint32_t(0));
541✔
68
        return base_data_;
541✔
69
    }
70
    HPX_DEFINE_COMPONENT_ACTION(
71
        test_server_base, get_base_data, get_base_data_action)
72

73
    hpx::future<int> lazy_get_base_data() const
221✔
74
    {
75
        HPX_TEST_NEQ(pin_count(), std::uint32_t(0));
221✔
76

77
        auto f = hpx::make_ready_future(base_data_);
221✔
78

79
        return f.then([this](hpx::future<int>&& f) -> int {
442✔
80
            HPX_TEST_NEQ(pin_count(), std::uint32_t(0));
221✔
81
            auto result = f.get();
221✔
82
            HPX_TEST_NEQ(pin_count(), std::uint32_t(0));
221✔
83
            return result;
221✔
84
        });
85
    }
221✔
86
    HPX_DEFINE_COMPONENT_ACTION(
87
        test_server_base, lazy_get_base_data, lazy_get_base_data_action)
88

89
    virtual int get_data() const
×
90
    {
91
        return get_base_data();
×
92
    }
93
    int get_data_nonvirt() const
558✔
94
    {
95
        return get_data();
558✔
96
    }
97
    HPX_DEFINE_COMPONENT_ACTION(
98
        test_server_base, get_data_nonvirt, get_data_action)
99

100
    virtual hpx::future<int> lazy_get_data() const
×
101
    {
102
        return lazy_get_base_data();
×
103
    }
104
    hpx::future<int> lazy_get_data_nonvirt() const
253✔
105
    {
106
        return lazy_get_data();
253✔
107
    }
108
    HPX_DEFINE_COMPONENT_ACTION(
109
        test_server_base, lazy_get_data_nonvirt, lazy_get_data_action)
110

111
    // Components which should be migrated using hpx::migrate<> need to
112
    // be Serializable and CopyConstructable. Components can be
113
    // MoveConstructable in which case the serialized data is moved into the
114
    // component's constructor.
115
    test_server_base(test_server_base&& rhs)
279✔
116
      : base_data_(std::move(rhs.base_data_))
279✔
117
    {
558✔
118
    }
279✔
119

120
    test_server_base& operator=(test_server_base&& rhs)
121
    {
122
        base_data_ = std::move(rhs.base_data_);
123
        return *this;
124
    }
125

126
    template <typename Archive>
127
    void serialize(Archive& ar, unsigned)
1,116✔
128
    {
129
        // clang-format off
130
        ar & base_data_;
1,116✔
131
        // clang-format on
132
    }
1,116✔
133

134
    hpx::naming::address get_current_address() const override
×
135
    {
136
        return hpx::naming::address(
×
137
            hpx::naming::get_gid_from_locality_id(hpx::get_locality_id()),
×
138
            hpx::components::get_component_type<test_server_base>(),
×
139
            const_cast<test_server_base*>(this));
×
140
    }
141

142
private:
143
    int base_data_;
144
};
145

146
HPX_DEFINE_GET_COMPONENT_TYPE(test_server_base)
4,787✔
147

148
typedef test_server_base::call_action call_action;
149
HPX_REGISTER_ACTION_DECLARATION(call_action)
150
HPX_REGISTER_ACTION(call_action)
2,584✔
151

152
typedef test_server_base::busy_work_action busy_work_action;
153
HPX_REGISTER_ACTION_DECLARATION(busy_work_action)
154
HPX_REGISTER_ACTION(busy_work_action)
9✔
155

156
typedef test_server_base::lazy_busy_work_action lazy_busy_work_action;
157
HPX_REGISTER_ACTION_DECLARATION(lazy_busy_work_action)
158
HPX_REGISTER_ACTION(lazy_busy_work_action)
9✔
159

160
typedef test_server_base::get_base_data_action get_base_data_action;
161
HPX_REGISTER_ACTION_DECLARATION(get_base_data_action)
162
HPX_REGISTER_ACTION(get_base_data_action)
3,096✔
163

164
typedef test_server_base::lazy_get_base_data_action lazy_get_base_data_action;
165
HPX_REGISTER_ACTION_DECLARATION(lazy_get_base_data_action)
166
HPX_REGISTER_ACTION(lazy_get_base_data_action)
1,289✔
167

168
typedef test_server_base::get_data_action get_data_action;
169
HPX_REGISTER_ACTION_DECLARATION(get_data_action)
170
HPX_REGISTER_ACTION(get_data_action)
3,039✔
171

172
typedef test_server_base::lazy_get_data_action lazy_get_data_action;
173
HPX_REGISTER_ACTION_DECLARATION(lazy_get_data_action)
174
HPX_REGISTER_ACTION(lazy_get_data_action)
1,285✔
175

176
///////////////////////////////////////////////////////////////////////////////
177
struct test_server
565✔
178
  : hpx::components::abstract_migration_support<
179
        hpx::components::component_base<test_server>, test_server_base>
180
{
181
    using base_type = hpx::components::abstract_migration_support<
182
        hpx::components::component_base<test_server>, test_server_base>;
183

184
    test_server(int base_data = 0, int data = 0)
286✔
185
      : base_type(base_data)
286✔
186
      , data_(data)
286✔
187
    {
572✔
188
    }
286✔
189

190
    int get_data() const override
558✔
191
    {
192
        HPX_TEST_NEQ(pin_count(), std::uint32_t(0));
558✔
193
        return data_;
558✔
194
    }
195

196
    hpx::future<int> lazy_get_data() const override
253✔
197
    {
198
        HPX_TEST_NEQ(pin_count(), std::uint32_t(0));
253✔
199

200
        auto f = hpx::make_ready_future(data_);
253✔
201

202
        return f.then([this](hpx::future<int>&& f) -> int {
506✔
203
            HPX_TEST_NEQ(pin_count(), std::uint32_t(0));
253✔
204
            auto result = f.get();
253✔
205
            HPX_TEST_NEQ(pin_count(), std::uint32_t(0));
253✔
206
            return result;
253✔
207
        });
208
    }
253✔
209

210
    // Components that should be migrated using hpx::migrate<> need to
211
    // be Serializable and CopyConstructable. Components can be
212
    // MoveConstructable in which case the serialized data is moved into the
213
    // component's constructor.
214
    test_server(test_server&& rhs)
279✔
215
      : base_type(std::move(rhs))
279✔
216
      , data_(rhs.data_)
279✔
217
    {
558✔
218
    }
279✔
219

220
    test_server& operator=(test_server&& rhs)
221
    {
222
        this->test_server_base::operator=(
223
            std::move(static_cast<test_server_base&>(rhs)));
224
        data_ = rhs.data_;
225
        return *this;
226
    }
227

228
    template <typename Archive>
229
    void serialize(Archive& ar, unsigned)
1,116✔
230
    {
231
        // clang-format off
232
        ar & hpx::serialization::base_object<test_server_base>(*this);
1,116✔
233
        ar & data_;
1,116✔
234
        // clang-format on
235
    }
1,116✔
236

237
    hpx::naming::address get_current_address() const override
286✔
238
    {
239
        return hpx::naming::address(
286✔
240
            hpx::naming::get_gid_from_locality_id(hpx::get_locality_id()),
286✔
241
            hpx::components::get_component_type<test_server>(),
286✔
242
            const_cast<test_server*>(this));
286✔
243
    }
244

245
private:
246
    int data_;
247
};
248

249
typedef hpx::components::component<test_server> server_type;
250
HPX_REGISTER_DERIVED_COMPONENT_FACTORY(
1,730✔
251
    server_type, test_server, "test_server_base")
252

253
///////////////////////////////////////////////////////////////////////////////
254
struct test_client : hpx::components::client_base<test_client, test_server_base>
592✔
255
{
256
    using base_type =
257
        hpx::components::client_base<test_client, test_server_base>;
258

259
    test_client() = default;
260
    test_client(hpx::shared_future<hpx::id_type> const& id)
572✔
261
      : base_type(id)
572✔
262
    {
572✔
263
    }
572✔
264
    test_client(hpx::id_type&& id)
265
      : base_type(std::move(id))
266
    {
267
    }
268

269
    hpx::id_type call() const
871✔
270
    {
271
        return call_action()(this->get_id());
871✔
272
    }
273

274
    hpx::future<void> busy_work() const
2✔
275
    {
276
        return hpx::async<busy_work_action>(this->get_id());
2✔
277
    }
278

279
    hpx::future<void> lazy_busy_work() const
2✔
280
    {
281
        return hpx::async<lazy_busy_work_action>(this->get_id());
2✔
282
    }
283

284
    int get_data() const
1,013✔
285
    {
286
        return get_data_action()(this->get_id());
1,013✔
287
    }
288

289
    int lazy_get_data() const
412✔
290
    {
291
        return lazy_get_data_action()(this->get_id()).get();
412✔
292
    }
×
293

294
    int get_base_data() const
1,013✔
295
    {
296
        return get_base_data_action()(this->get_id());
1,013✔
297
    }
298

299
    int lazy_get_base_data() const
412✔
300
    {
301
        return lazy_get_base_data_action()(this->get_id()).get();
412✔
302
    }
×
303
};
304

305
///////////////////////////////////////////////////////////////////////////////
306
bool test_migrate_polymorphic_component(
2✔
307
    hpx::id_type source, hpx::id_type target)
308
{
309
    // create component on given locality
310
    test_client t1(hpx::new_<test_server>(source, 7, 42));
2✔
311
    HPX_TEST_NEQ(hpx::invalid_id, t1.get_id());
2✔
312

313
    // the new object should live on the source locality
314
    HPX_TEST_EQ(t1.call(), source);
2✔
315
    HPX_TEST_EQ(t1.get_data(), 42);
2✔
316
    HPX_TEST_EQ(t1.get_base_data(), 7);
2✔
317

318
    try
319
    {
320
        hpx::cout << "Migrating..." << std::endl;
2✔
321
        // migrate t1 to the target
322
        test_client t2(hpx::components::migrate<test_server>(t1, target));
2✔
323

324
        // wait for migration to be done
325
        HPX_TEST_NEQ(hpx::invalid_id, t2.get_id());
2✔
326
        hpx::cout << "...completed migrating..." << std::endl;
2✔
327

328
        // the migrated object should have the same id as before
329
        HPX_TEST_EQ(t1.get_id(), t2.get_id());
2✔
330

331
        // the migrated object should live on the target now
332
        HPX_TEST_EQ(t2.call(), target);
2✔
333
        HPX_TEST_EQ(t2.get_data(), 42);
2✔
334
        HPX_TEST_EQ(t2.get_base_data(), 7);
2✔
335

336
        hpx::cout << "...pass all tests!" << std::endl;
2✔
337
    }
2✔
338
    catch (hpx::exception const& e)
339
    {
340
        hpx::cout << hpx::get_error_what(e) << std::endl;
×
341
        return false;
×
342
    }
×
343

344
    return true;
2✔
345
}
2✔
346

347
///////////////////////////////////////////////////////////////////////////////
348
bool test_migrate_lazy_polymorphic_component(
2✔
349
    hpx::id_type source, hpx::id_type target)
350
{
351
    // create component on given locality
352
    test_client t1(hpx::new_<test_server>(source, 7, 42));
2✔
353
    HPX_TEST_NEQ(hpx::invalid_id, t1.get_id());
2✔
354

355
    // the new object should live on the source locality
356
    HPX_TEST_EQ(t1.call(), source);
2✔
357
    HPX_TEST_EQ(t1.lazy_get_data(), 42);
2✔
358
    HPX_TEST_EQ(t1.lazy_get_base_data(), 7);
2✔
359

360
    try
361
    {
362
        // migrate t1 to the target
363
        test_client t2(hpx::components::migrate<test_server>(t1, target));
2✔
364

365
        // wait for migration to be done
366
        HPX_TEST_NEQ(hpx::invalid_id, t2.get_id());
2✔
367

368
        // the migrated object should have the same id as before
369
        HPX_TEST_EQ(t1.get_id(), t2.get_id());
2✔
370

371
        // the migrated object should live on the target now
372
        HPX_TEST_EQ(t2.call(), target);
2✔
373
        HPX_TEST_EQ(t2.lazy_get_data(), 42);
2✔
374
        HPX_TEST_EQ(t2.lazy_get_base_data(), 7);
2✔
375
    }
2✔
376
    catch (hpx::exception const& e)
377
    {
378
        hpx::cout << hpx::get_error_what(e) << std::endl;
×
379
        return false;
×
380
    }
×
381

382
    return true;
2✔
383
}
2✔
384

385
///////////////////////////////////////////////////////////////////////////////
386
bool test_migrate_busy_polymorphic_component(
2✔
387
    hpx::id_type source, hpx::id_type target)
388
{
389
    // create component on given locality
390
    test_client t1(hpx::new_<test_server>(source, 7, 42));
2✔
391
    HPX_TEST_NEQ(hpx::invalid_id, t1.get_id());
2✔
392

393
    // the new object should live on the source locality
394
    HPX_TEST_EQ(t1.call(), source);
2✔
395
    HPX_TEST_EQ(t1.get_data(), 42);
2✔
396
    HPX_TEST_EQ(t1.get_base_data(), 7);
2✔
397

398
    // add some concurrent busy work
399
    hpx::future<void> busy_work = t1.busy_work();
2✔
400

401
    try
402
    {
403
        // migrate t1 to the target
404
        test_client t2(hpx::components::migrate<test_server>(t1, target));
2✔
405

406
        HPX_TEST_EQ(t1.get_data(), 42);
2✔
407
        HPX_TEST_EQ(t1.get_base_data(), 7);
2✔
408

409
        // wait for migration to be done
410
        HPX_TEST_NEQ(hpx::invalid_id, t2.get_id());
2✔
411

412
        // the migrated object should have the same id as before
413
        HPX_TEST_EQ(t1.get_id(), t2.get_id());
2✔
414

415
        // the migrated object should live on the target now
416
        HPX_TEST_EQ(t2.call(), target);
2✔
417
        HPX_TEST_EQ(t2.get_data(), 42);
2✔
418
        HPX_TEST_EQ(t2.get_base_data(), 7);
2✔
419
    }
2✔
420
    catch (hpx::exception const& e)
421
    {
422
        hpx::cout << hpx::get_error_what(e) << std::endl;
×
423
        return false;
×
424
    }
×
425

426
    // the busy work should be finished by now, wait anyways
427
    busy_work.wait();
2✔
428

429
    return true;
2✔
430
}
2✔
431

432
///////////////////////////////////////////////////////////////////////////////
433
bool test_migrate_lazy_busy_polymorphic_component(
2✔
434
    hpx::id_type source, hpx::id_type target)
435
{
436
    // create component on given locality
437
    test_client t1(hpx::new_<test_server>(source, 7, 42));
2✔
438
    HPX_TEST_NEQ(hpx::invalid_id, t1.get_id());
2✔
439

440
    // the new object should live on the source locality
441
    HPX_TEST_EQ(t1.call(), source);
2✔
442
    HPX_TEST_EQ(t1.lazy_get_data(), 42);
2✔
443
    HPX_TEST_EQ(t1.lazy_get_base_data(), 7);
2✔
444

445
    // add some concurrent busy work
446
    hpx::future<void> lazy_busy_work = t1.lazy_busy_work();
2✔
447

448
    try
449
    {
450
        // migrate t1 to the target
451
        test_client t2(hpx::components::migrate<test_server>(t1, target));
2✔
452

453
        HPX_TEST_EQ(t1.lazy_get_data(), 42);
2✔
454
        HPX_TEST_EQ(t1.lazy_get_base_data(), 7);
2✔
455

456
        // wait for migration to be done
457
        HPX_TEST_NEQ(hpx::invalid_id, t2.get_id());
2✔
458

459
        // the migrated object should have the same id as before
460
        HPX_TEST_EQ(t1.get_id(), t2.get_id());
2✔
461

462
        // the migrated object should live on the target now
463
        HPX_TEST_EQ(t2.call(), target);
2✔
464
        HPX_TEST_EQ(t2.lazy_get_data(), 42);
2✔
465
        HPX_TEST_EQ(t2.lazy_get_base_data(), 7);
2✔
466
    }
2✔
467
    catch (hpx::exception const& e)
468
    {
469
        hpx::cout << hpx::get_error_what(e) << std::endl;
×
470
        return false;
×
471
    }
×
472

473
    // the busy work should be finished by now, wait anyways
474
    lazy_busy_work.wait();
2✔
475

476
    return true;
2✔
477
}
2✔
478

479
///////////////////////////////////////////////////////////////////////////////
480
bool test_migrate_polymorphic_component2(
2✔
481
    hpx::id_type source, hpx::id_type target)
482
{
483
    test_client t1(hpx::new_<test_server>(source, 7, 42));
2✔
484
    HPX_TEST_NEQ(hpx::invalid_id, t1.get_id());
2✔
485

486
    // the new object should live on the source locality
487
    HPX_TEST_EQ(t1.call(), source);
2✔
488
    HPX_TEST_EQ(t1.get_data(), 42);
2✔
489
    HPX_TEST_EQ(t1.get_base_data(), 7);
2✔
490

491
    std::size_t N = 100;
2✔
492

493
    try
494
    {
495
        // migrate an object back and forth between 2 localities a couple of
496
        // times
497
        for (std::size_t i = 0; i < N; ++i)
202✔
498
        {
499
            // migrate t1 to the target (loc2)
500
            test_client t2(hpx::components::migrate<test_server>(t1, target));
200✔
501

502
            HPX_TEST_EQ(t1.get_data(), 42);
200✔
503
            HPX_TEST_EQ(t1.get_base_data(), 7);
200✔
504

505
            // wait for migration to be done
506
            HPX_TEST_NEQ(hpx::invalid_id, t2.get_id());
200✔
507

508
            // the migrated object should have the same id as before
509
            HPX_TEST_EQ(t1.get_id(), t2.get_id());
200✔
510

511
            // the migrated object should live on the target now
512
            HPX_TEST_EQ(t2.call(), target);
200✔
513
            HPX_TEST_EQ(t2.get_data(), 42);
200✔
514
            HPX_TEST_EQ(t2.get_base_data(), 7);
200✔
515

516
            hpx::cout << "." << std::flush;
200✔
517

518
            std::swap(source, target);
200✔
519
        }
200✔
520

521
        hpx::cout << std::endl;
2✔
522
    }
2✔
523
    catch (hpx::exception const& e)
524
    {
525
        hpx::cout << hpx::get_error_what(e) << std::endl;
×
526
        return false;
×
527
    }
×
528

529
    return true;
2✔
530
}
2✔
531

532
bool test_migrate_lazy_polymorphic_component2(
2✔
533
    hpx::id_type source, hpx::id_type target)
534
{
535
    test_client t1(hpx::new_<test_server>(source, 7, 42));
2✔
536
    HPX_TEST_NEQ(hpx::invalid_id, t1.get_id());
2✔
537

538
    // the new object should live on the source locality
539
    HPX_TEST_EQ(t1.call(), source);
2✔
540
    HPX_TEST_EQ(t1.lazy_get_data(), 42);
2✔
541
    HPX_TEST_EQ(t1.lazy_get_base_data(), 7);
2✔
542

543
    std::size_t N = 100;
2✔
544

545
    try
546
    {
547
        // migrate an object back and forth between 2 localities a couple of
548
        // times
549
        for (std::size_t i = 0; i < N; ++i)
202✔
550
        {
551
            // migrate t1 to the target (loc2)
552
            test_client t2(hpx::components::migrate<test_server>(t1, target));
200✔
553

554
            HPX_TEST_EQ(t1.lazy_get_data(), 42);
200✔
555
            HPX_TEST_EQ(t1.lazy_get_base_data(), 7);
200✔
556

557
            // wait for migration to be done
558
            HPX_TEST_NEQ(hpx::invalid_id, t2.get_id());
200✔
559

560
            // the migrated object should have the same id as before
561
            HPX_TEST_EQ(t1.get_id(), t2.get_id());
200✔
562

563
            // the migrated object should live on the target now
564
            HPX_TEST_EQ(t2.call(), target);
200✔
565
            HPX_TEST_EQ(t2.lazy_get_data(), 42);
200✔
566
            HPX_TEST_EQ(t2.lazy_get_base_data(), 7);
200✔
567

568
            hpx::cout << "." << std::flush;
200✔
569

570
            std::swap(source, target);
200✔
571
        }
200✔
572

573
        hpx::cout << std::endl;
2✔
574
    }
2✔
575
    catch (hpx::exception const& e)
576
    {
577
        hpx::cout << hpx::get_error_what(e) << std::endl;
×
578
        return false;
×
579
    }
×
580

581
    return true;
2✔
582
}
2✔
583

584
///////////////////////////////////////////////////////////////////////////////
585
bool test_migrate_busy_polymorphic_component2(
2✔
586
    hpx::id_type source, hpx::id_type target)
587
{
588
    test_client t1(hpx::new_<test_server>(source, 7, 42));
2✔
589
    HPX_TEST_NEQ(hpx::invalid_id, t1.get_id());
2✔
590

591
    // the new object should live on the source locality
592
    HPX_TEST_EQ(t1.call(), source);
2✔
593
    HPX_TEST_EQ(t1.get_data(), 42);
2✔
594
    HPX_TEST_EQ(t1.get_base_data(), 7);
2✔
595

596
    std::size_t N = 100;
2✔
597

598
    // First, spawn a thread (locally) that will migrate the object between
599
    // source and target a few times
600
    hpx::future<void> migrate_future = hpx::async([source, target, t1,
15✔
601
                                                      N]() mutable {
2✔
602
        for (std::size_t i = 0; i < N; ++i)
151✔
603
        {
604
            // migrate t1 to the target (loc2)
605
            test_client t2(hpx::components::migrate<test_server>(t1, target));
150✔
606

607
            HPX_TEST_EQ(t1.get_data(), 42);
150✔
608
            HPX_TEST_EQ(t1.get_base_data(), 7);
150✔
609

610
            // wait for migration to be done
611
            HPX_TEST_NEQ(hpx::invalid_id, t2.get_id());
150✔
612

613
            // the migrated object should have the same id as before
614
            HPX_TEST_EQ(t1.get_id(), t2.get_id());
149✔
615

616
            // the migrated object should live on the target now
617
            HPX_TEST_EQ(t2.call(), target);
149✔
618
            HPX_TEST_EQ(t2.get_data(), 42);
149✔
619
            HPX_TEST_EQ(t2.get_base_data(), 7);
149✔
620

621
            hpx::cout << "." << std::flush;
149✔
622

623
            std::swap(source, target);
149✔
624
        }
149✔
625

626
        hpx::cout << std::endl;
1✔
627
    });
1✔
628

629
    // Second, we generate tons of work which should automatically follow
630
    // the migration.
631
    hpx::future<void> create_work = hpx::async([t1, N]() {
13✔
632
        for (std::size_t i = 0; i < 2 * N; ++i)
301✔
633
        {
634
            hpx::cout << hpx::naming::get_locality_id_from_id(t1.call())
600✔
635
                      << std::flush;
300✔
636
            HPX_TEST_EQ(t1.get_data(), 42);
299✔
637
            HPX_TEST_EQ(t1.get_base_data(), 7);
299✔
638
        }
299✔
639
    });
1✔
640

641
    hpx::wait_all(migrate_future, create_work);
1✔
642

643
    // rethrow exceptions
644
    try
645
    {
646
        migrate_future.get();
1✔
647
        create_work.get();
1✔
648
    }
1✔
649
    catch (hpx::exception const& e)
650
    {
651
        hpx::cout << hpx::get_error_what(e) << std::endl;
×
652
        return false;
×
653
    }
×
654

655
    return true;
1✔
656
}
1✔
657

658
bool test_migrate_lazy_busy_polymorphic_component2(
×
659
    hpx::id_type source, hpx::id_type target)
660
{
661
    test_client t1(hpx::new_<test_server>(source, 7, 42));
×
662
    HPX_TEST_NEQ(hpx::invalid_id, t1.get_id());
×
663

664
    // the new object should live on the source locality
665
    HPX_TEST_EQ(t1.call(), source);
×
666
    HPX_TEST_EQ(t1.get_data(), 42);
×
667
    HPX_TEST_EQ(t1.get_base_data(), 7);
×
668

669
    std::size_t N = 100;
×
670

671
    // First, spawn a thread (locally) that will migrate the object between
672
    // source and target a few times
673
    hpx::future<void> migrate_future = hpx::async([source, target, t1,
×
674
                                                      N]() mutable {
×
675
        for (std::size_t i = 0; i < N; ++i)
×
676
        {
677
            // migrate t1 to the target (loc2)
678
            test_client t2(hpx::components::migrate<test_server>(t1, target));
×
679

680
            HPX_TEST_EQ(t1.lazy_get_data(), 42);
×
681
            HPX_TEST_EQ(t1.lazy_get_base_data(), 7);
×
682

683
            // wait for migration to be done
684
            HPX_TEST_NEQ(hpx::invalid_id, t2.get_id());
×
685

686
            // the migrated object should have the same id as before
687
            HPX_TEST_EQ(t1.get_id(), t2.get_id());
×
688

689
            // the migrated object should live on the target now
690
            HPX_TEST_EQ(t2.call(), target);
×
691
            HPX_TEST_EQ(t2.lazy_get_data(), 42);
×
692
            HPX_TEST_EQ(t2.lazy_get_base_data(), 7);
×
693

694
            hpx::cout << "." << std::flush;
×
695

696
            std::swap(source, target);
×
697
        }
×
698

699
        hpx::cout << std::endl;
×
700
    });
×
701

702
    // Second, we generate tons of work which should automatically follow
703
    // the migration.
704
    hpx::future<void> create_work = hpx::async([t1, N]() {
×
705
        for (std::size_t i = 0; i < 2 * N; ++i)
×
706
        {
707
            hpx::cout << hpx::naming::get_locality_id_from_id(t1.call())
×
708
                      << std::flush;
×
709
            HPX_TEST_EQ(t1.lazy_get_data(), 42);
×
710
            HPX_TEST_EQ(t1.lazy_get_base_data(), 7);
×
711
        }
×
712
    });
×
713

714
    hpx::wait_all(migrate_future, create_work);
×
715

716
    // rethrow exceptions
717
    try
718
    {
719
        migrate_future.get();
×
720
        create_work.get();
×
721
    }
×
722
    catch (hpx::exception const& e)
723
    {
724
        hpx::cout << hpx::get_error_what(e) << std::endl;
×
725
        return false;
×
726
    }
×
727

728
    return true;
×
729
}
×
730

731
///////////////////////////////////////////////////////////////////////////////
732
int main()
1✔
733
{
734
    std::vector<hpx::id_type> localities = hpx::find_remote_localities();
1✔
735

736
    for (hpx::id_type const& id : localities)
2✔
737
    {
738
        hpx::cout << "test migrate polymorphic component: ->" << id
1✔
739
                  << std::endl;
1✔
740
        HPX_TEST(test_migrate_polymorphic_component(hpx::find_here(), id));
1✔
741
        hpx::cout << "test migrate polymorphic component: <-" << id
1✔
742
                  << std::endl;
1✔
743
        HPX_TEST(test_migrate_polymorphic_component(id, hpx::find_here()));
1✔
744

745
        hpx::cout << "test migrate lazy polymorphic component: ->" << id
1✔
746
                  << std::endl;
1✔
747
        HPX_TEST(test_migrate_lazy_polymorphic_component(hpx::find_here(), id));
1✔
748
        hpx::cout << "test migrate lazy polymorphic component: <-" << id
1✔
749
                  << std::endl;
1✔
750
        HPX_TEST(test_migrate_lazy_polymorphic_component(id, hpx::find_here()));
1✔
751
    }
752

753
    for (hpx::id_type const& id : localities)
2✔
754
    {
755
        hpx::cout << "test migrate busy polymorphic component: ->" << id
1✔
756
                  << std::endl;
1✔
757
        HPX_TEST(test_migrate_busy_polymorphic_component(hpx::find_here(), id));
1✔
758
        hpx::cout << "test migrate busy polymorphic component: <-" << id
1✔
759
                  << std::endl;
1✔
760
        HPX_TEST(test_migrate_busy_polymorphic_component(id, hpx::find_here()));
1✔
761

762
        hpx::cout << "test migrate lazy busy polymorphic component: ->" << id
1✔
763
                  << std::endl;
1✔
764
        HPX_TEST(
1✔
765
            test_migrate_lazy_busy_polymorphic_component(hpx::find_here(), id));
766
        hpx::cout << "test migrate lazy busy polymorphic component: <-" << id
1✔
767
                  << std::endl;
1✔
768
        HPX_TEST(
1✔
769
            test_migrate_lazy_busy_polymorphic_component(id, hpx::find_here()));
770
    }
771

772
    for (hpx::id_type const& id : localities)
2✔
773
    {
774
        hpx::cout << "test migrate polymorphic component2: ->" << id
1✔
775
                  << std::endl;
1✔
776
        HPX_TEST(test_migrate_polymorphic_component2(hpx::find_here(), id));
1✔
777
        hpx::cout << "test migrate polymorphic component2: <-" << id
1✔
778
                  << std::endl;
1✔
779
        HPX_TEST(test_migrate_polymorphic_component2(id, hpx::find_here()));
1✔
780

781
        hpx::cout << "test migrate lazy polymorphic component2: ->" << id
1✔
782
                  << std::endl;
1✔
783
        HPX_TEST(
1✔
784
            test_migrate_lazy_polymorphic_component2(hpx::find_here(), id));
785
        hpx::cout << "test migrate lazy polymorphic component2: <-" << id
1✔
786
                  << std::endl;
1✔
787
        HPX_TEST(
1✔
788
            test_migrate_lazy_polymorphic_component2(id, hpx::find_here()));
789
    }
790

791
    for (hpx::id_type const& id : localities)
1✔
792
    {
793
        hpx::cout << "test migrate busy polymorphic component2: ->" << id
1✔
794
                  << std::endl;
1✔
795
        HPX_TEST(
1✔
796
            test_migrate_busy_polymorphic_component2(hpx::find_here(), id));
797
        hpx::cout << "test migrate busy polymorphic component2: <-" << id
1✔
798
                  << std::endl;
1✔
799
        HPX_TEST(
1✔
800
            test_migrate_busy_polymorphic_component2(id, hpx::find_here()));
801

802
        hpx::cout << "test migrate lazy busy polymorphic component2: ->" << id
×
803
                  << std::endl;
×
804
        HPX_TEST(test_migrate_lazy_busy_polymorphic_component2(
×
805
            hpx::find_here(), id));
806
        hpx::cout << "test migrate lazy busy polymorphic component2: <-" << id
×
807
                  << std::endl;
×
808
        HPX_TEST(test_migrate_lazy_busy_polymorphic_component2(
×
809
            id, hpx::find_here()));
810
    }
811

812
    return hpx::util::report_errors();
×
813
}
×
814
#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