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

STEllAR-GROUP / hpx / #851

16 Dec 2022 12:27PM CUT coverage: 86.568% (+0.2%) from 86.404%
#851

push

StellarBot
Merge #6104

6104: Adding parameters API: measure_iteration r=hkaiser a=hkaiser

- split `get_chunk_size` CP into `measure_iteration` and modified `get_chunk_size`
- introducing a breaking change to `get_chunk_size` and `processing_units_count` customization point, those now expect the time for one iteration

The new APIs are:
```
    template <typename Target, typename F>
    hpx::chrono::steady_duration measure_iteration(
        Target&&, F&&, std::size_t num_tasks);

    template <typename Target>
    std::size_t processing_units_count(
        Target&&, hpx::chrono::steady_duration const&, std::size_t num_tasks);

    template <typename Target>
    std::size_t get_chunk_size(Target&&,
        hpx::chrono::steady_duration const&, std::size_t num_cores,
        std::size_t num_tasks);
```
This also moves all executor parameter objects to `namespace hpx::execution::experimental`. 

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

209 of 209 new or added lines in 34 files covered. (100.0%)

174475 of 201546 relevant lines covered (86.57%)

1888115.1 hits per line

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

80.11
/libs/full/components_base/src/server/wrapper_heap.cpp
1
//  Copyright (c) 1998-2021 Hartmut Kaiser
2
//  Copyright (c)      2011 Bryce Lelbach
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
#include <hpx/assert.hpp>
10
#include <hpx/components_base/agas_interface.hpp>
11
#include <hpx/components_base/generate_unique_ids.hpp>
12
#include <hpx/components_base/server/wrapper_heap.hpp>
13
#include <hpx/modules/itt_notify.hpp>
14
#include <hpx/modules/logging.hpp>
15
#include <hpx/naming_base/id_type.hpp>
16
#include <hpx/synchronization/spinlock.hpp>
17
#include <hpx/thread_support/unlock_guard.hpp>
18

19
#include <cstddef>
20
#include <cstdint>
21
#if HPX_DEBUG_WRAPPER_HEAP != 0
22
#include <cstring>
23
#endif
24
#include <memory>
25
#include <mutex>
26
#include <new>
27
#include <string>
28
#include <type_traits>
29

30
///////////////////////////////////////////////////////////////////////////////
31
namespace hpx { namespace components { namespace detail {
32

33
    namespace one_size_heap_allocators {
34

35
        util::internal_allocator<char> fixed_mallocator::alloc_;
1,160✔
36
    }
37

38
#if HPX_DEBUG_WRAPPER_HEAP != 0
39
#define HPX_WRAPPER_HEAP_INITIALIZED_MEMORY 1
40

41
    namespace debug {
42

43
        ///////////////////////////////////////////////////////////////////////
44
        // Test memory area for being filled as expected
45
        inline bool test_fill_bytes(void* p, unsigned char c, std::size_t cnt)
46
        {
47
            unsigned char* uc = (unsigned char*) p;
48
            for (std::size_t i = 0; i < cnt; ++i)
49
            {
50
                if (*uc++ != c)
51
                {
52
                    return false;
53
                }
54
            }
55
            return true;
56
        }
57

58
        // Fill memory area
59
        inline void fill_bytes(void* p, unsigned char c, std::size_t cnt)
60
        {
61
            using namespace std;    // some systems have memset in namespace std
62
            memset(p, c, cnt);
63
        }
64
    }    // namespace debug
65
#else
66
#define HPX_WRAPPER_HEAP_INITIALIZED_MEMORY 0
67
#endif
68

69
    ///////////////////////////////////////////////////////////////////////////
70
    wrapper_heap::wrapper_heap(char const* class_name,
2,887✔
71
#if defined(HPX_DEBUG)
72
        std::size_t count,
73
#else
74
        std::size_t,
75
#endif
76
        heap_parameters parameters)
77
      : pool_(nullptr)
2,887✔
78
      , first_free_(nullptr)
2,887✔
79
      , parameters_(parameters)
2,887✔
80
      , free_size_(0)
2,887✔
81
      , base_gid_(naming::invalid_gid)
2,887✔
82
      , class_name_(class_name)
2,887✔
83
#if defined(HPX_DEBUG)
84
      , alloc_count_(0)
2,887✔
85
      , free_count_(0)
2,887✔
86
      , heap_count_(count)
2,887✔
87
#endif
88
      , heap_alloc_function_("wrapper_heap::alloc", class_name)
2,887✔
89
      , heap_free_function_("wrapper_heap::free", class_name)
2,887✔
90
    {
5,774✔
91
        util::itt::heap_internal_access hia;
92
        HPX_UNUSED(hia);
2,887✔
93

94
        if (!init_pool())
2,887✔
95
        {
96
            throw std::bad_alloc();
×
97
        }
98
    }
2,887✔
99

100
    wrapper_heap::wrapper_heap()
×
101
      : pool_(nullptr)
×
102
      , first_free_(nullptr)
×
103
      , parameters_({0, 0, 0})
×
104
      , free_size_(0)
×
105
      , base_gid_(naming::invalid_gid)
×
106
#if defined(HPX_DEBUG)
107
      , alloc_count_(0)
×
108
      , free_count_(0)
×
109
      , heap_count_(0)
×
110
#endif
111
      , heap_alloc_function_("wrapper_heap::alloc", "<unknown>")
×
112
      , heap_free_function_("wrapper_heap::free", "<unknown>")
×
113
    {
×
114
        HPX_ASSERT(false);    // shouldn't ever be called
×
115
    }
×
116

117
    wrapper_heap::~wrapper_heap()
2,884✔
118
    {
2,884✔
119
        util::itt::heap_internal_access hia;
120
        HPX_UNUSED(hia);
2,884✔
121

122
        tidy();
2,884✔
123
    }
2,884✔
124

125
    std::size_t wrapper_heap::size() const
10,070✔
126
    {
127
        util::itt::heap_internal_access hia;
128
        HPX_UNUSED(hia);
10,070✔
129

130
        return parameters_.capacity - free_size_;
10,070✔
131
    }
132

133
    std::size_t wrapper_heap::free_size() const
6,606✔
134
    {
135
        util::itt::heap_internal_access hia;
136
        HPX_UNUSED(hia);
6,606✔
137

138
        return free_size_;
6,606✔
139
    }
140

141
    bool wrapper_heap::is_empty() const
×
142
    {
143
        util::itt::heap_internal_access hia;
144
        HPX_UNUSED(hia);
×
145

146
        return nullptr == pool_;
×
147
    }
148

149
    bool wrapper_heap::has_allocatable_slots() const
×
150
    {
151
        util::itt::heap_internal_access hia;
152
        HPX_UNUSED(hia);
×
153

154
        std::size_t const num_bytes =
×
155
            parameters_.capacity * parameters_.element_size;
×
156
        return first_free_ < pool_ + num_bytes;
×
157
    }
158

159
    bool wrapper_heap::alloc(void** result, std::size_t count)
825,231✔
160
    {
161
        util::itt::heap_allocate heap_allocate(heap_alloc_function_, result,
1,650,462✔
162
            count * parameters_.element_size,
825,231✔
163
            HPX_WRAPPER_HEAP_INITIALIZED_MEMORY);
164

165
        std::unique_lock l(mtx_);
825,231✔
166

167
        if (!ensure_pool(count))
825,231✔
168
            return false;
6,606✔
169

170
#if defined(HPX_DEBUG)
171
        alloc_count_ += count;
818,625✔
172
#endif
173

174
        void* p = first_free_;
818,625✔
175
        HPX_ASSERT(p != nullptr);
818,625✔
176

177
        first_free_ = first_free_ + count * parameters_.element_size;
818,625✔
178

179
        HPX_ASSERT(free_size_ >= count);
818,625✔
180
        free_size_ -= count;
818,625✔
181

182
#if HPX_DEBUG_WRAPPER_HEAP != 0
183
        // init memory blocks
184
        debug::fill_bytes(p, initial_value, count * parameters_.element_size);
185
#endif
186

187
        *result = p;
818,625✔
188
        return true;
818,625✔
189
    }
825,231✔
190

191
    void wrapper_heap::free(void* p, std::size_t count)
809,514✔
192
    {
193
        util::itt::heap_free heap_free(heap_free_function_, p);
809,512✔
194

195
#if HPX_DEBUG_WRAPPER_HEAP != 0
196
        HPX_ASSERT(did_alloc(p));
197
#endif
198
        std::unique_lock l(mtx_);
809,512✔
199

200
#if HPX_DEBUG_WRAPPER_HEAP != 0
201
        char* p1 = p;
202
        std::size_t const total_num_bytes =
203
            parameters_.capacity * parameters_.element_size;
204
        std::size_t const num_bytes = count * parameters_.element_size;
205

206
        HPX_ASSERT(nullptr != pool_ && p1 >= pool_);
207
        HPX_ASSERT(
208
            nullptr != pool_ && p1 + num_bytes <= pool_ + total_num_bytes);
209
        HPX_ASSERT(first_free_ == nullptr || p1 != first_free_);
210
        HPX_ASSERT(free_size_ + count <= parameters_.capacity);
211
        // make sure this has not been freed yet
212
        HPX_ASSERT(!debug::test_fill_bytes(p1, freed_value, num_bytes));
213

214
        // give memory back to pool
215
        debug::fill_bytes(p1, freed_value, num_bytes);
216
#else
217
        HPX_UNUSED(p);
809,512✔
218
#endif
219

220
#if defined(HPX_DEBUG)
221
        free_count_ += count;
809,512✔
222
#endif
223
        free_size_ += count;
809,512✔
224

225
        // release the pool if this one was the last allocated item
226
        test_release(l);
809,512✔
227
    }
809,512✔
228

229
    bool wrapper_heap::did_alloc(void* p) const
2,471,805✔
230
    {
231
        // no lock is necessary here as all involved variables are immutable
232
        util::itt::heap_internal_access hia;
233
        HPX_UNUSED(hia);
2,471,796✔
234
        if (nullptr == pool_)
2,471,796✔
235
            return false;
9,090✔
236
        if (nullptr == p)
2,462,706✔
237
            return false;
×
238

239
        std::size_t const total_num_bytes =
2,462,707✔
240
            parameters_.capacity * parameters_.element_size;
2,462,707✔
241
        return p >= pool_ && static_cast<char*>(p) < pool_ + total_num_bytes;
2,462,706✔
242
    }
2,471,796✔
243

244
    naming::gid_type wrapper_heap::get_gid(
810,234✔
245
        util::unique_id_ranges& ids, void* p, components::component_type type)
246
    {
247
        util::itt::heap_internal_access hia;
248
        HPX_UNUSED(hia);
810,234✔
249

250
        HPX_ASSERT(did_alloc(p));
810,234✔
251

252
        std::unique_lock l(mtx_);
810,232✔
253

254
        if (!base_gid_)
810,232✔
255
        {
256
            naming::gid_type base_gid;
2,749✔
257

258
            {
259
                // this is the first call to get_gid() for this heap - allocate
260
                // a sufficiently large range of global ids
261
                unlock_guard ul(l);
2,749✔
262
                base_gid = ids.get_id(parameters_.capacity);
2,749✔
263

264
                // register the global ids and the base address of this heap
265
                // with the AGAS
266
                if (!agas::bind_range_local(base_gid, parameters_.capacity,
2,749✔
267
                        naming::address(naming::get_gid_from_locality_id(
5,498✔
268
                                            agas::get_locality_id()),
2,749✔
269
                            type, pool_),
2,749✔
270
                        parameters_.element_size))
2,749✔
271
                {
272
                    return naming::invalid_gid;
×
273
                }
274
            }
2,749✔
275

276
            // if some other thread has already set the base GID for this
277
            // heap, we ignore the result
278
            if (!base_gid_)
2,749✔
279
            {
280
                // this is the first thread succeeding in binding the new gid
281
                // range
282
                base_gid_ = base_gid;
2,749✔
283
            }
2,749✔
284
            else
285
            {
286
                // unbind the range which is not needed anymore
287
                unlock_guard ul(l);
×
288
                agas::unbind_range_local(base_gid, parameters_.capacity);
×
289
            }
×
290
        }
2,749✔
291

292
        std::uint64_t const distance = static_cast<char*>(p) - pool_;
810,233✔
293
        return base_gid_ + distance / parameters_.element_size;
810,233✔
294
    }
810,233✔
295

296
    void wrapper_heap::set_gid(naming::gid_type const& g)
×
297
    {
298
        util::itt::heap_internal_access hia;
299
        HPX_UNUSED(hia);
×
300

301
        std::unique_lock l(mtx_);
×
302
        base_gid_ = g;
×
303
    }
×
304

305
    bool wrapper_heap::test_release(std::unique_lock<mutex_type>& lk)
809,512✔
306
    {
307
        if (pool_ == nullptr)
809,512✔
308
        {
309
            return false;
×
310
        }
311

312
        std::size_t const total_num_bytes =
809,512✔
313
            parameters_.capacity * parameters_.element_size;
809,512✔
314

315
        if (first_free_ < pool_ + total_num_bytes ||
809,512✔
316
            free_size_ < parameters_.capacity)
21,889✔
317
        {
318
            return false;
809,343✔
319
        }
320

321
        HPX_ASSERT(free_size_ == parameters_.capacity);
169✔
322
        HPX_ASSERT(first_free_ == pool_ + total_num_bytes);
169✔
323

324
        // unbind in AGAS service
325
        if (base_gid_)
169✔
326
        {
327
            naming::gid_type base_gid = base_gid_;
169✔
328
            base_gid_ = naming::invalid_gid;
169✔
329

330
            unlock_guard ull(lk);
169✔
331
            agas::unbind_range_local(base_gid, parameters_.capacity);
169✔
332
        }
169✔
333

334
        tidy();
169✔
335
        return true;
169✔
336
    }
809,512✔
337

338
    bool wrapper_heap::ensure_pool(std::size_t count)
825,231✔
339
    {
340
        if (nullptr == pool_)
825,231✔
341
        {
342
            return false;
4,625✔
343
        }
344

345
        std::size_t const num_bytes = count * parameters_.element_size;
820,606✔
346
        std::size_t const total_num_bytes =
820,606✔
347
            parameters_.capacity * parameters_.element_size;
820,606✔
348

349
        if (first_free_ + num_bytes > pool_ + total_num_bytes)
820,606✔
350
        {
351
            return false;
1,981✔
352
        }
353
        return true;
818,625✔
354
    }
825,231✔
355

356
    bool wrapper_heap::init_pool()
2,887✔
357
    {
358
        HPX_ASSERT(first_free_ == nullptr);
2,887✔
359

360
        std::size_t const total_num_bytes =
2,887✔
361
            parameters_.capacity * parameters_.element_size;
2,887✔
362
        pool_ = static_cast<char*>(allocator_type::alloc(total_num_bytes));
2,887✔
363
        if (nullptr == pool_)
2,887✔
364
        {
365
            return false;
×
366
        }
367

368
        first_free_ = (reinterpret_cast<std::size_t>(pool_) %
8,661✔
369
                              parameters_.element_alignment ==
5,774✔
370
                          0) ?
371
            pool_ :
2,887✔
372
            pool_ + parameters_.element_alignment;
×
373

374
        free_size_ = parameters_.capacity;
2,887✔
375

376
        LOSH_(info).format("wrapper_heap ({}): init_pool ({}) size: {}.",
5,727✔
377
            !class_name_.empty() ? class_name_.c_str() : "<Unknown>",
2,840✔
378
            static_cast<void*>(pool_), total_num_bytes);
2,840✔
379

380
        return true;
2,887✔
381
    }
2,887✔
382

383
    void wrapper_heap::tidy()
3,053✔
384
    {
385
        if (pool_ != nullptr)
3,053✔
386
        {
387
            LOSH_(debug)
5,721✔
388
                    .format("wrapper_heap ({})",
5,674✔
389
                        !class_name_.empty() ? class_name_.c_str() :
2,837✔
390
                                               "<Unknown>")
391
#if defined(HPX_DEBUG)
392
                    .format(": releasing heap: alloc count: {}, free count: {}",
5,674✔
393
                        alloc_count_, free_count_)
2,837✔
394
#endif
395
                << ".";
2,837✔
396

397
            if (size() > 0
2,884✔
398
#if defined(HPX_DEBUG)
399
                || alloc_count_ != free_count_
2,884✔
400
#endif
401
            )
402
            {
403
                LOSH_(warning).format("wrapper_heap ({}): releasing heap ({}) "
1,174✔
404
                                      "with {} allocated object(s)!",
405
                    !class_name_.empty() ? class_name_.c_str() : "<Unknown>",
580✔
406
                    static_cast<void*>(pool_), size());
580✔
407
            }
594✔
408

409
            std::size_t const total_num_bytes =
2,884✔
410
                parameters_.capacity * parameters_.element_size;
2,884✔
411
            allocator_type::free(pool_, total_num_bytes);
2,884✔
412
            pool_ = first_free_ = nullptr;
2,884✔
413
            free_size_ = 0;
2,884✔
414
        }
2,884✔
415
    }
3,053✔
416
}}}    // namespace hpx::components::detail
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