• 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

81.71
/libs/full/components_base/src/server/wrapper_heap.cpp
1
//  Copyright (c) 1998-2023 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/server/wrapper_heap.hpp>
12
#include <hpx/modules/itt_notify.hpp>
13
#include <hpx/modules/logging.hpp>
14
#include <hpx/naming_base/id_type.hpp>
15
#include <hpx/synchronization/spinlock.hpp>
16
#include <hpx/thread_support/unlock_guard.hpp>
17

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

29
///////////////////////////////////////////////////////////////////////////////
30
namespace hpx::components::detail {
31

32
    namespace one_size_heap_allocators {
33

34
        util::internal_allocator<char> fixed_mallocator::alloc_;
1,162✔
35
    }
36

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

40
    namespace debug {
41

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

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

68
    ///////////////////////////////////////////////////////////////////////////
69
    wrapper_heap::wrapper_heap(char const* class_name,
2,874✔
70
        [[maybe_unused]] std::size_t count, heap_parameters parameters)
71
      : pool_(nullptr)
2,874✔
72
      , first_free_(nullptr)
2,874✔
73
      , parameters_(parameters)
2,874✔
74
      , free_size_(0)
2,874✔
75
      , base_gid_(naming::invalid_gid)
2,874✔
76
      , class_name_(class_name)
2,874✔
77
#if defined(HPX_DEBUG)
78
      , alloc_count_(0)
2,874✔
79
      , free_count_(0)
2,874✔
80
      , heap_count_(count)
2,874✔
81
#endif
82
      , heap_alloc_function_("wrapper_heap::alloc", class_name)
2,874✔
83
      , heap_free_function_("wrapper_heap::free", class_name)
2,874✔
84
    {
5,748✔
85
        [[maybe_unused]] util::itt::heap_internal_access hia;
86

87
        if (!init_pool())
2,874✔
88
        {
89
            throw std::bad_alloc();
×
90
        }
91
    }
2,874✔
92

93
    wrapper_heap::wrapper_heap()
×
94
      : pool_(nullptr)
×
95
      , first_free_(nullptr)
×
96
      , parameters_({0, 0, 0})
×
97
      , free_size_(0)
×
98
      , base_gid_(naming::invalid_gid)
×
99
#if defined(HPX_DEBUG)
100
      , alloc_count_(0)
×
101
      , free_count_(0)
×
102
      , heap_count_(0)
×
103
#endif
104
      , heap_alloc_function_("wrapper_heap::alloc", "<unknown>")
×
105
      , heap_free_function_("wrapper_heap::free", "<unknown>")
×
106
    {
×
107
        HPX_ASSERT(false);    // shouldn't ever be called
×
108
    }
×
109

110
    wrapper_heap::~wrapper_heap()
2,858✔
111
    {
2,858✔
112
        [[maybe_unused]] util::itt::heap_internal_access hia;
113

114
        tidy();
2,858✔
115
    }
2,858✔
116

117
    std::size_t wrapper_heap::size() const
8,915✔
118
    {
119
        [[maybe_unused]] util::itt::heap_internal_access hia;
120

121
        return parameters_.capacity - free_size_;
8,915✔
122
    }
123

124
    std::size_t wrapper_heap::free_size() const
5,478✔
125
    {
126
        [[maybe_unused]] util::itt::heap_internal_access hia;
127

128
        return free_size_;
5,478✔
129
    }
130

131
    bool wrapper_heap::is_empty() const
×
132
    {
133
        [[maybe_unused]] util::itt::heap_internal_access hia;
134

135
        return nullptr == pool_;
×
136
    }
137

138
    bool wrapper_heap::has_allocatable_slots() const
×
139
    {
140
        [[maybe_unused]] util::itt::heap_internal_access hia;
141

142
        std::size_t const num_bytes =
×
143
            parameters_.capacity * parameters_.element_size;
×
144
        return first_free_ < pool_ + num_bytes;
×
145
    }
146

147
    bool wrapper_heap::alloc(void** result, std::size_t count)
818,387✔
148
    {
149
        util::itt::heap_allocate heap_allocate(heap_alloc_function_, result,
1,636,774✔
150
            count * parameters_.element_size,
818,386✔
151
            HPX_WRAPPER_HEAP_INITIALIZED_MEMORY);
152

153
        std::unique_lock l(mtx_);
818,386✔
154

155
        if (!ensure_pool(count))
818,387✔
156
            return false;
5,478✔
157

158
#if defined(HPX_DEBUG)
159
        alloc_count_ += count;
812,908✔
160
#endif
161

162
        void* p = first_free_;
812,908✔
163
        HPX_ASSERT(p != nullptr);
812,908✔
164

165
        first_free_ = first_free_ + count * parameters_.element_size;
812,908✔
166

167
        HPX_ASSERT(free_size_ >= count);
812,908✔
168
        free_size_ -= count;
812,908✔
169

170
#if HPX_DEBUG_WRAPPER_HEAP != 0
171
        // init memory blocks
172
        debug::fill_bytes(p, initial_value, count * parameters_.element_size);
173
#endif
174

175
        *result = p;
812,908✔
176
        return true;
812,908✔
177
    }
818,386✔
178

179
    void wrapper_heap::free([[maybe_unused]] void* p, std::size_t count)
803,793✔
180
    {
181
        util::itt::heap_free heap_free(heap_free_function_, p);
803,791✔
182

183
#if HPX_DEBUG_WRAPPER_HEAP != 0
184
        HPX_ASSERT(did_alloc(p));
185
#endif
186
        std::unique_lock l(mtx_);
803,791✔
187

188
#if HPX_DEBUG_WRAPPER_HEAP != 0
189
        char* p1 = p;
190
        std::size_t const total_num_bytes =
191
            parameters_.capacity * parameters_.element_size;
192
        std::size_t const num_bytes = count * parameters_.element_size;
193

194
        HPX_ASSERT(nullptr != pool_ && p1 >= pool_);
195
        HPX_ASSERT(
196
            nullptr != pool_ && p1 + num_bytes <= pool_ + total_num_bytes);
197
        HPX_ASSERT(first_free_ == nullptr || p1 != first_free_);
198
        HPX_ASSERT(free_size_ + count <= parameters_.capacity);
199
        // make sure this has not been freed yet
200
        HPX_ASSERT(!debug::test_fill_bytes(p1, freed_value, num_bytes));
201

202
        // give memory back to pool
203
        debug::fill_bytes(p1, freed_value, num_bytes);
204
#endif
205

206
#if defined(HPX_DEBUG)
207
        free_count_ += count;
803,791✔
208
#endif
209
        free_size_ += count;
803,791✔
210

211
        // release the pool if this one was the last allocated item
212
        test_release(l);
803,791✔
213
    }
803,791✔
214

215
    bool wrapper_heap::did_alloc(void* p) const
2,454,231✔
216
    {
217
        // no lock is necessary here as all involved variables are immutable
218
        [[maybe_unused]] util::itt::heap_internal_access hia;
219

220
        if (nullptr == pool_)
2,454,232✔
221
            return false;
1,643✔
222
        if (nullptr == p)
2,452,584✔
223
            return false;
×
224

225
        std::size_t const total_num_bytes =
2,452,586✔
226
            parameters_.capacity * parameters_.element_size;
2,452,586✔
227
        return p >= pool_ && static_cast<char*>(p) < pool_ + total_num_bytes;
2,452,584✔
228
    }
2,454,228✔
229

230
    naming::gid_type wrapper_heap::get_gid(
804,517✔
231
        void* p, components::component_type type)
232
    {
233
        [[maybe_unused]] util::itt::heap_internal_access hia;
234

235
        HPX_ASSERT(did_alloc(p));
804,517✔
236

237
        {
238
            std::unique_lock l(mtx_);
804,516✔
239
            if (!base_gid_)
804,516✔
240
            {
241
                // use the pool's base address as the first gid, this will also
242
                // allow for the ids to be locally resolvable
243
                base_gid_ = naming::replace_locality_id(
2,737✔
244
                    naming::replace_component_type(
2,737✔
245
                        naming::gid_type(pool_), type),
2,737✔
246
                    agas::get_locality_id());
2,737✔
247

248
                naming::detail::set_credit_for_gid(
2,737✔
249
                    base_gid_, std::int64_t(HPX_GLOBALCREDIT_INITIAL));
2,737✔
250
            }
2,737✔
251
        }
804,516✔
252

253
        naming::gid_type result = base_gid_;
804,516✔
254
        result.set_lsb(p);
804,516✔
255

256
        // We have to assume this credit was split as otherwise the gid returned
257
        // at this point will control the lifetime of the component.
258
        naming::detail::set_credit_split_mask_for_gid(result);
804,516✔
259

260
        return result;
804,516✔
261
    }
×
262

263
    void wrapper_heap::set_gid(naming::gid_type const& g)
×
264
    {
265
        [[maybe_unused]] util::itt::heap_internal_access hia;
266

267
        std::unique_lock l(mtx_);
×
268
        base_gid_ = g;
×
269
    }
×
270

271
    bool wrapper_heap::test_release(std::unique_lock<mutex_type>& lk)
803,791✔
272
    {
273
        if (pool_ == nullptr)
803,791✔
274
        {
275
            return false;
×
276
        }
277

278
        std::size_t const total_num_bytes =
803,792✔
279
            parameters_.capacity * parameters_.element_size;
803,792✔
280

281
        if (first_free_ < pool_ + total_num_bytes ||
803,791✔
282
            free_size_ < parameters_.capacity)
22,757✔
283
        {
284
            return false;
803,622✔
285
        }
286

287
        HPX_ASSERT(free_size_ == parameters_.capacity);
169✔
288
        HPX_ASSERT(first_free_ == pool_ + total_num_bytes);
169✔
289

290
        // unbind in AGAS service
291
        if (base_gid_)
169✔
292
        {
293
            naming::gid_type base_gid = base_gid_;
169✔
294
            base_gid_ = naming::invalid_gid;
169✔
295

296
            unlock_guard ull(lk);
169✔
297
            agas::unbind_range_local(base_gid, parameters_.capacity);
169✔
298
        }
169✔
299

300
        tidy();
169✔
301
        return true;
169✔
302
    }
803,791✔
303

304
    bool wrapper_heap::ensure_pool(std::size_t count)
818,386✔
305
    {
306
        if (nullptr == pool_)
818,386✔
307
        {
308
            return false;
1,262✔
309
        }
310

311
        std::size_t const num_bytes = count * parameters_.element_size;
817,124✔
312
        std::size_t const total_num_bytes =
817,124✔
313
            parameters_.capacity * parameters_.element_size;
817,124✔
314

315
        if (first_free_ + num_bytes > pool_ + total_num_bytes)
817,124✔
316
        {
317
            return false;
4,216✔
318
        }
319
        return true;
812,908✔
320
    }
818,386✔
321

322
    bool wrapper_heap::init_pool()
2,874✔
323
    {
324
        HPX_ASSERT(first_free_ == nullptr);
2,874✔
325

326
        std::size_t const total_num_bytes =
2,874✔
327
            parameters_.capacity * parameters_.element_size;
2,874✔
328
        pool_ = static_cast<char*>(allocator_type::alloc(total_num_bytes));
2,874✔
329
        if (nullptr == pool_)
2,874✔
330
        {
331
            return false;
×
332
        }
333

334
        first_free_ = (reinterpret_cast<std::size_t>(pool_) %
8,622✔
335
                              parameters_.element_alignment ==
5,748✔
336
                          0) ?
337
            pool_ :
2,874✔
338
            pool_ + parameters_.element_alignment;
×
339

340
        free_size_ = parameters_.capacity;
2,874✔
341

342
        LOSH_(info).format("wrapper_heap ({}): init_pool ({}) size: {}.",
5,701✔
343
            !class_name_.empty() ? class_name_.c_str() : "<Unknown>",
2,827✔
344
            static_cast<void*>(pool_), total_num_bytes);
2,827✔
345

346
        return true;
2,874✔
347
    }
2,874✔
348

349
    void wrapper_heap::tidy()
3,027✔
350
    {
351
        if (pool_ != nullptr)
3,027✔
352
        {
353
            LOSH_(debug)
5,669✔
354
                    .format("wrapper_heap ({})",
5,622✔
355
                        !class_name_.empty() ? class_name_.c_str() :
2,811✔
356
                                               "<Unknown>")
357
#if defined(HPX_DEBUG)
358
                    .format(": releasing heap: alloc count: {}, free "
5,622✔
359
                            "count: {}",
360
                        alloc_count_, free_count_)
2,811✔
361
#endif
362
                << ".";
2,811✔
363

364
            if (size() > 0
2,858✔
365
#if defined(HPX_DEBUG)
366
                || alloc_count_ != free_count_
2,858✔
367
#endif
368
            )
369
            {
370
                LOSH_(warning).format("wrapper_heap ({}): releasing heap ({}) "
1,172✔
371
                                      "with {} allocated object(s)!",
372
                    !class_name_.empty() ? class_name_.c_str() : "<Unknown>",
579✔
373
                    static_cast<void*>(pool_), size());
579✔
374
            }
593✔
375

376
            std::size_t const total_num_bytes =
2,858✔
377
                parameters_.capacity * parameters_.element_size;
2,858✔
378
            allocator_type::free(pool_, total_num_bytes);
2,858✔
379
            pool_ = first_free_ = nullptr;
2,858✔
380
            free_size_ = 0;
2,858✔
381
        }
2,858✔
382
    }
3,027✔
383
}    // 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