/home/runner/work/HiCR/HiCR/include/hicr/core/communicationManager.hpp Source File

HiCR: /home/runner/work/HiCR/HiCR/include/hicr/core/communicationManager.hpp Source File
HiCR
communicationManager.hpp
Go to the documentation of this file.
1/*
2 * Copyright 2025 Huawei Technologies Co., Ltd.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * Copyright Huawei Technologies Switzerland AG
19 * All rights reserved.
20 */
21
29#pragma once
30
31#include <map>
32#include <memory>
33#include <mutex>
34#include <utility>
35#include <vector>
39#include <hicr/core/definitions.hpp>
41
42namespace HiCR
43{
44
54{
55 public:
56
60 using globalKeyMemorySlotPair_t = std::pair<GlobalMemorySlot::globalKey_t, std::shared_ptr<LocalMemorySlot>>;
61
65 using globalKeyToMemorySlotMap_t = std::map<GlobalMemorySlot::globalKey_t, std::shared_ptr<GlobalMemorySlot>>;
66
70 using globalMemorySlotTagKeyMap_t = std::map<GlobalMemorySlot::tag_t, globalKeyToMemorySlotMap_t>;
71
75 virtual ~CommunicationManager() = default;
76
83 __INLINE__ void exchangeGlobalMemorySlots(GlobalMemorySlot::tag_t tag, const std::vector<globalKeyMemorySlotPair_t> &memorySlots)
84 {
85 // Calling internal implementation of this function
86 exchangeGlobalMemorySlotsImpl(tag, memorySlots);
87 }
88
98 __INLINE__ std::shared_ptr<GlobalMemorySlot> getGlobalMemorySlot(GlobalMemorySlot::tag_t tag, GlobalMemorySlot::globalKey_t globalKey)
99 {
100 auto globalSlotImpl = getGlobalMemorySlotImpl(tag, globalKey);
101
102 if (globalSlotImpl != nullptr) { return globalSlotImpl; }
103 else
104 {
105 // If the requested tag and key are not found, return empty storage
106 if (_globalMemorySlotTagKeyMap.find(tag) == _globalMemorySlotTagKeyMap.end())
107 HICR_THROW_LOGIC("Requesting a global memory slot with key %lu for a tag (%lu) that has not been registered.", globalKey, tag);
108
109 const auto &keyMap = _globalMemorySlotTagKeyMap.at(tag);
110 if (keyMap.find(globalKey) == keyMap.end()) HICR_THROW_LOGIC("Requesting a global memory slot for a global key (%lu) not registered within the tag (%lu).", globalKey, tag);
111
112 // Getting requested memory slot
113 auto value = keyMap.at(globalKey);
114
115 // Returning value
116 return value;
117 }
118 }
119
129 virtual uint8_t *serializeGlobalMemorySlot(const std::shared_ptr<HiCR::GlobalMemorySlot> &globalSlot) const
130 {
131 HICR_THROW_LOGIC("Trying to serialize a global memory slot; this is not supported in this backend\n");
132 return nullptr;
133 }
134
142 virtual std::shared_ptr<GlobalMemorySlot> deserializeGlobalMemorySlot(uint8_t *buffer, GlobalMemorySlot::tag_t tag)
143 {
144 HICR_THROW_LOGIC("Trying to deserialize a global memory slot; this is not supported in this backend\n");
145 return nullptr;
146 }
147
158 virtual std::shared_ptr<GlobalMemorySlot> promoteLocalMemorySlot(const std::shared_ptr<LocalMemorySlot> &localMemorySlot, GlobalMemorySlot::tag_t tag)
159 {
160 HICR_THROW_LOGIC("This backend does not support one-sided promotion of local memory slots to global");
161 return nullptr;
162 }
163
173 __INLINE__ void deregisterGlobalMemorySlot(const std::shared_ptr<GlobalMemorySlot> &memorySlot)
174 {
175 // Getting memory slot global information
176 const auto memorySlotTag = memorySlot->getGlobalTag();
177 const auto memorySlotGlobalKey = memorySlot->getGlobalKey();
178
179 // Checking whether the memory slot is correctly registered as global
180 if (_globalMemorySlotTagKeyMap.find(memorySlotTag) == _globalMemorySlotTagKeyMap.end())
181 {
182 HICR_THROW_LOGIC("Attempting to de-register a global memory slot but its tag/key pair is not registered in this backend");
183 }
184
185 // Removing memory slot from the global memory slot map
186 _globalMemorySlotTagKeyMap.at(memorySlotTag).erase(memorySlotGlobalKey);
188 }
189
202 __INLINE__ void destroyGlobalMemorySlot(const std::shared_ptr<GlobalMemorySlot> &memorySlot)
203 {
204 auto tag = memorySlot->getGlobalTag();
205 // Implicit creation of the tag entry if it doesn't exist is desired here
206 _globalMemorySlotsToDestroyPerTag[tag].push_back(memorySlot);
207 }
208
217 virtual void destroyPromotedGlobalMemorySlot(const std::shared_ptr<GlobalMemorySlot> &memorySlot)
218 {
219 HICR_THROW_LOGIC("This backend does not support promoted global memory slots.");
220 }
221
229 __INLINE__ void queryMemorySlotUpdates(std::shared_ptr<LocalMemorySlot> memorySlot)
230 {
231 // Getting value by copy
232 queryMemorySlotUpdatesImpl(std::move(memorySlot));
233 }
234
248 __INLINE__ void memcpy(const std::shared_ptr<LocalMemorySlot> &destination, size_t dst_offset, const std::shared_ptr<LocalMemorySlot> &source, size_t src_offset, size_t size)
249 {
250 // Getting slot sizes. This operation is thread-safe
251 const auto srcSize = source->getSize();
252 const auto dstSize = destination->getSize();
253
254 // Making sure the memory slots exist and is not null
255 const auto actualSrcSize = size + src_offset;
256 const auto actualDstSize = size + dst_offset;
257
258 // Checking size doesn't exceed slot size
259 if (actualSrcSize > srcSize)
260 HICR_THROW_RUNTIME("Memcpy size (%lu) + offset (%lu) = (%lu) exceeds source slot (%p) capacity (%lu).", size, src_offset, actualSrcSize, source->getPointer(), srcSize);
261
262 // Checking size doesn't exceed slot size
263 if (actualDstSize > dstSize)
265 "Memcpy size (%lu) + offset (%lu) = (%lu) exceeds destination slot (%p) capacity (%lu).", size, dst_offset, actualDstSize, destination->getPointer(), dstSize);
266
267 // To enable concurrent memcpy operations, the implementation is executed outside the mutex zone
268 // This means that the developer needs to make sure that the implementation is concurrency-safe,
269 // and try not to access any of the internal Backend class fields without proper mutex locking
270
271 // Now calling internal memcpy function to give us a function that satisfies the operation
272 memcpyImpl(destination, dst_offset, source, src_offset, size);
273 }
274
288 __INLINE__ void memcpy(const std::shared_ptr<GlobalMemorySlot> &destination, size_t dst_offset, const std::shared_ptr<LocalMemorySlot> &source, size_t src_offset, size_t size)
289 {
290 // Getting slot sizes. This operation is thread-safe
291 const auto srcSize = source->getSize();
292
293 // Making sure the memory slots exist and is not null
294 const auto actualSrcSize = size + src_offset;
295
296 // Checking size doesn't exceed slot size
297 if (actualSrcSize > srcSize)
298 HICR_THROW_RUNTIME("Memcpy size (%lu) + offset (%lu) = (%lu) exceeds source slot (%p) capacity (%lu).", size, src_offset, actualSrcSize, source->getPointer(), srcSize);
299
300 // Now calling internal memcpy function to give us a function that satisfies the operation
301 memcpyImpl(destination, dst_offset, source, src_offset, size);
302 }
303
317 __INLINE__ void memcpy(const std::shared_ptr<LocalMemorySlot> &destination, size_t dst_offset, const std::shared_ptr<GlobalMemorySlot> &source, size_t src_offset, size_t size)
318 {
319 // Getting slot sizes. This operation is thread-safe
320 const auto dstSize = destination->getSize();
321
322 // Making sure the memory slots exist and is not null
323 const auto actualDstSize = size + dst_offset;
324
325 // Checking size doesn't exceed slot size
326 if (actualDstSize > dstSize)
328 "Memcpy size (%lu) + offset (%lu) = (%lu) exceeds destination slot (%p) capacity (%lu).", size, dst_offset, actualDstSize, destination->getPointer(), dstSize);
329
330 // Now calling internal memcpy function to give us a function that satisfies the operation
331 memcpyImpl(destination, dst_offset, source, src_offset, size);
332 }
333
358 __INLINE__ void fence(GlobalMemorySlot::tag_t tag)
359 {
360 // Now call the proper fence, as implemented by the backend
361 fenceImpl(tag);
362
363 // Clear the memory slots to destroy
364 _globalMemorySlotsToDestroyPerTag[tag].clear();
365 _globalMemorySlotsToDestroyPerTag.erase(tag);
366 }
367
379 __INLINE__ void fence(const std::shared_ptr<LocalMemorySlot> &slot, size_t expectedSent, size_t expectedRecvd)
380 {
381 // To enable concurrent fence operations, the implementation is executed outside the mutex zone
382 // This means that the developer needs to make sure that the implementation is concurrency-safe,
383 // and try not to access any of the internal Backend class fields without proper mutex locking
384
385 // Now call the proper fence, as implemented by the backend
386 fenceImpl(slot, expectedSent, expectedRecvd);
387 }
388
400 __INLINE__ void fence(const std::shared_ptr<GlobalMemorySlot> &slot, size_t expectedSent, size_t expectedRecvd)
401 {
402 // To enable concurrent fence operations, the implementation is executed outside the mutex zone
403 // This means that the developer needs to make sure that the implementation is concurrency-safe,
404 // and try not to access any of the internal Backend class fields without proper mutex locking
405
406 // Now call the proper fence, as implemented by the backend
407 fenceImpl(slot, expectedSent, expectedRecvd);
408 }
409
418 __INLINE__ bool acquireGlobalLock(const std::shared_ptr<GlobalMemorySlot> &memorySlot)
419 {
420 // Getting memory slot global information
421 const auto memorySlotTag = memorySlot->getGlobalTag();
422 const auto memorySlotGlobalKey = memorySlot->getGlobalKey();
423
424 // Checking whether the memory slot is correctly registered as global
425 if (_globalMemorySlotTagKeyMap.find(memorySlotTag) == _globalMemorySlotTagKeyMap.end())
426 HICR_THROW_LOGIC("Attempting to lock a global memory slot but its tag/key pair is not registered in this backend");
427
428 // Checking whether the memory slot is correctly registered as global
429 const auto &keyMap = _globalMemorySlotTagKeyMap.at(memorySlotTag);
430 if (keyMap.find(memorySlotGlobalKey) == keyMap.end()) HICR_THROW_LOGIC("Attempting to lock a global memory slot but its tag/key pair is not registered in this backend");
431
432 // Calling internal implementation
433 return acquireGlobalLockImpl(memorySlot);
434 }
435
441 __INLINE__ void releaseGlobalLock(const std::shared_ptr<GlobalMemorySlot> &memorySlot)
442 {
443 // Getting memory slot global information
444 const auto memorySlotTag = memorySlot->getGlobalTag();
445 const auto memorySlotGlobalKey = memorySlot->getGlobalKey();
446
447 // Checking whether the memory slot is correctly registered as global
448 if (_globalMemorySlotTagKeyMap.find(memorySlotTag) == _globalMemorySlotTagKeyMap.end())
449 {
450 HICR_THROW_LOGIC("Attempting to release a global memory slot but its tag/key pair is not registered in this backend");
451 }
452
453 // Checking whether the memory slot is correctly registered as global
454 const auto &keyMap = _globalMemorySlotTagKeyMap.at(memorySlotTag);
455 if (keyMap.find(memorySlotGlobalKey) == keyMap.end()) { HICR_THROW_LOGIC("Attempting to release a global memory slot but its tag/key pair is not registered in this backend"); }
456
457 // Calling internal implementation
458 releaseGlobalLockImpl(memorySlot);
459 }
460
464 __INLINE__ virtual void flushSent() {}
465
469 __INLINE__ virtual void flushReceived() {}
470
475 [[nodiscard]] __INLINE__ auto &getGlobalMemorySlotTagKeyMap() { return _globalMemorySlotTagKeyMap; }
476
482 {
483 _globalMemorySlotTagKeyMap = globalMemorySlotTagKeyMap;
484 }
485
486 protected:
487
495 __INLINE__ void registerGlobalMemorySlot(const std::shared_ptr<GlobalMemorySlot> &memorySlot)
496 {
497 // Getting memory slot information
498 const auto tag = memorySlot->getGlobalTag();
499 const auto globalKey = memorySlot->getGlobalKey();
500
501 // Adding memory slot to the global map (based on tag and key)
502 _globalMemorySlotTagKeyMap[tag][globalKey] = memorySlot;
503 }
504
514 virtual std::shared_ptr<GlobalMemorySlot> getGlobalMemorySlotImpl(GlobalMemorySlot::tag_t tag, GlobalMemorySlot::globalKey_t globalKey) = 0;
515
522 virtual void exchangeGlobalMemorySlotsImpl(GlobalMemorySlot::tag_t tag, const std::vector<globalKeyMemorySlotPair_t> &memorySlots) = 0;
523
529 virtual void queryMemorySlotUpdatesImpl(std::shared_ptr<LocalMemorySlot> memorySlot) = 0;
530
536 virtual void deregisterGlobalMemorySlotImpl(const std::shared_ptr<GlobalMemorySlot> &memorySlot) {};
537
544 virtual void destroyGlobalMemorySlotImpl(std::shared_ptr<GlobalMemorySlot> memorySlot) = 0;
545
555 virtual void memcpyImpl(const std::shared_ptr<LocalMemorySlot> &destination, size_t dst_offset, const std::shared_ptr<LocalMemorySlot> &source, size_t src_offset, size_t size)
556 {
557 HICR_THROW_LOGIC("Local->Local memcpy operations are unsupported by the given backend");
558 };
559
569 virtual void memcpyImpl(const std::shared_ptr<GlobalMemorySlot> &destination, size_t dst_offset, const std::shared_ptr<LocalMemorySlot> &source, size_t src_offset, size_t size)
570 {
571 HICR_THROW_LOGIC("Local->Global memcpy operations are unsupported by the given backend");
572 };
573
583 virtual void memcpyImpl(const std::shared_ptr<LocalMemorySlot> &destination, size_t dst_offset, const std::shared_ptr<GlobalMemorySlot> &source, size_t src_offset, size_t size)
584 {
585 HICR_THROW_LOGIC("Global->Local memcpy operations are unsupported by the given backend");
586 };
587
595 virtual void fenceImpl(const std::shared_ptr<LocalMemorySlot> &slot, size_t expectedSent, size_t expectedRcvd) {}
603 virtual void fenceImpl(const std::shared_ptr<GlobalMemorySlot> &slot, size_t expectedSent, size_t expectedRcvd) {}
610 virtual void fenceImpl(GlobalMemorySlot::tag_t tag) = 0;
611
617 virtual bool acquireGlobalLockImpl(std::shared_ptr<GlobalMemorySlot> memorySlot) = 0;
618
623 virtual void releaseGlobalLockImpl(std::shared_ptr<GlobalMemorySlot> memorySlot) = 0;
624
629 [[nodiscard]] __INLINE__ auto &getGlobalMemorySlotsToDestroyPerTag() { return _globalMemorySlotsToDestroyPerTag; }
630
636 __INLINE__ void increaseMessageRecvCounter(HiCR::LocalMemorySlot &memorySlot) noexcept { memorySlot.increaseMessagesRecv(); }
637
643 __INLINE__ void increaseMessageSentCounter(HiCR::LocalMemorySlot &memorySlot) noexcept { memorySlot.increaseMessagesSent(); }
644
651 __INLINE__ void setMessagesRecv(HiCR::LocalMemorySlot &memorySlot, const size_t count) noexcept { memorySlot.setMessagesRecv(count); }
652
659 __INLINE__ void setMessagesSent(HiCR::LocalMemorySlot &memorySlot, const size_t count) noexcept { memorySlot.setMessagesSent(count); }
660
661 private:
662
666 globalMemorySlotTagKeyMap_t _globalMemorySlotTagKeyMap;
667
671 std::map<GlobalMemorySlot::tag_t, std::vector<std::shared_ptr<GlobalMemorySlot>>> _globalMemorySlotsToDestroyPerTag;
672};
673
674} // namespace HiCR
Definition communicationManager.hpp:54
std::map< GlobalMemorySlot::tag_t, globalKeyToMemorySlotMap_t > globalMemorySlotTagKeyMap_t
Definition communicationManager.hpp:70
virtual std::shared_ptr< GlobalMemorySlot > promoteLocalMemorySlot(const std::shared_ptr< LocalMemorySlot > &localMemorySlot, GlobalMemorySlot::tag_t tag)
Definition communicationManager.hpp:158
virtual uint8_t * serializeGlobalMemorySlot(const std::shared_ptr< HiCR::GlobalMemorySlot > &globalSlot) const
Definition communicationManager.hpp:129
__INLINE__ auto & getGlobalMemorySlotTagKeyMap()
Definition communicationManager.hpp:475
__INLINE__ void setMessagesSent(HiCR::LocalMemorySlot &memorySlot, const size_t count) noexcept
Definition communicationManager.hpp:659
__INLINE__ std::shared_ptr< GlobalMemorySlot > getGlobalMemorySlot(GlobalMemorySlot::tag_t tag, GlobalMemorySlot::globalKey_t globalKey)
Definition communicationManager.hpp:98
virtual void memcpyImpl(const std::shared_ptr< LocalMemorySlot > &destination, size_t dst_offset, const std::shared_ptr< LocalMemorySlot > &source, size_t src_offset, size_t size)
Definition communicationManager.hpp:555
virtual __INLINE__ void flushReceived()
Definition communicationManager.hpp:469
__INLINE__ void memcpy(const std::shared_ptr< LocalMemorySlot > &destination, size_t dst_offset, const std::shared_ptr< LocalMemorySlot > &source, size_t src_offset, size_t size)
Definition communicationManager.hpp:248
virtual void fenceImpl(const std::shared_ptr< LocalMemorySlot > &slot, size_t expectedSent, size_t expectedRcvd)
Definition communicationManager.hpp:595
virtual ~CommunicationManager()=default
__INLINE__ void releaseGlobalLock(const std::shared_ptr< GlobalMemorySlot > &memorySlot)
Definition communicationManager.hpp:441
virtual void fenceImpl(const std::shared_ptr< GlobalMemorySlot > &slot, size_t expectedSent, size_t expectedRcvd)
Definition communicationManager.hpp:603
virtual void releaseGlobalLockImpl(std::shared_ptr< GlobalMemorySlot > memorySlot)=0
virtual std::shared_ptr< GlobalMemorySlot > getGlobalMemorySlotImpl(GlobalMemorySlot::tag_t tag, GlobalMemorySlot::globalKey_t globalKey)=0
__INLINE__ void fence(GlobalMemorySlot::tag_t tag)
Definition communicationManager.hpp:358
__INLINE__ void setGlobalMemorySlotTagKeyMap(const HiCR::CommunicationManager::globalMemorySlotTagKeyMap_t &globalMemorySlotTagKeyMap)
Definition communicationManager.hpp:481
virtual __INLINE__ void flushSent()
Definition communicationManager.hpp:464
__INLINE__ void deregisterGlobalMemorySlot(const std::shared_ptr< GlobalMemorySlot > &memorySlot)
Definition communicationManager.hpp:173
__INLINE__ void memcpy(const std::shared_ptr< GlobalMemorySlot > &destination, size_t dst_offset, const std::shared_ptr< LocalMemorySlot > &source, size_t src_offset, size_t size)
Definition communicationManager.hpp:288
__INLINE__ void registerGlobalMemorySlot(const std::shared_ptr< GlobalMemorySlot > &memorySlot)
Definition communicationManager.hpp:495
__INLINE__ bool acquireGlobalLock(const std::shared_ptr< GlobalMemorySlot > &memorySlot)
Definition communicationManager.hpp:418
virtual bool acquireGlobalLockImpl(std::shared_ptr< GlobalMemorySlot > memorySlot)=0
virtual void memcpyImpl(const std::shared_ptr< LocalMemorySlot > &destination, size_t dst_offset, const std::shared_ptr< GlobalMemorySlot > &source, size_t src_offset, size_t size)
Definition communicationManager.hpp:583
__INLINE__ void destroyGlobalMemorySlot(const std::shared_ptr< GlobalMemorySlot > &memorySlot)
Definition communicationManager.hpp:202
virtual std::shared_ptr< GlobalMemorySlot > deserializeGlobalMemorySlot(uint8_t *buffer, GlobalMemorySlot::tag_t tag)
Definition communicationManager.hpp:142
virtual void fenceImpl(GlobalMemorySlot::tag_t tag)=0
virtual void queryMemorySlotUpdatesImpl(std::shared_ptr< LocalMemorySlot > memorySlot)=0
__INLINE__ void queryMemorySlotUpdates(std::shared_ptr< LocalMemorySlot > memorySlot)
Definition communicationManager.hpp:229
virtual void deregisterGlobalMemorySlotImpl(const std::shared_ptr< GlobalMemorySlot > &memorySlot)
Definition communicationManager.hpp:536
virtual void destroyGlobalMemorySlotImpl(std::shared_ptr< GlobalMemorySlot > memorySlot)=0
std::pair< GlobalMemorySlot::globalKey_t, std::shared_ptr< LocalMemorySlot > > globalKeyMemorySlotPair_t
Definition communicationManager.hpp:60
virtual void exchangeGlobalMemorySlotsImpl(GlobalMemorySlot::tag_t tag, const std::vector< globalKeyMemorySlotPair_t > &memorySlots)=0
__INLINE__ void fence(const std::shared_ptr< GlobalMemorySlot > &slot, size_t expectedSent, size_t expectedRecvd)
Definition communicationManager.hpp:400
std::map< GlobalMemorySlot::globalKey_t, std::shared_ptr< GlobalMemorySlot > > globalKeyToMemorySlotMap_t
Definition communicationManager.hpp:65
__INLINE__ void increaseMessageRecvCounter(HiCR::LocalMemorySlot &memorySlot) noexcept
Definition communicationManager.hpp:636
__INLINE__ auto & getGlobalMemorySlotsToDestroyPerTag()
Definition communicationManager.hpp:629
__INLINE__ void memcpy(const std::shared_ptr< LocalMemorySlot > &destination, size_t dst_offset, const std::shared_ptr< GlobalMemorySlot > &source, size_t src_offset, size_t size)
Definition communicationManager.hpp:317
__INLINE__ void setMessagesRecv(HiCR::LocalMemorySlot &memorySlot, const size_t count) noexcept
Definition communicationManager.hpp:651
virtual void destroyPromotedGlobalMemorySlot(const std::shared_ptr< GlobalMemorySlot > &memorySlot)
Definition communicationManager.hpp:217
virtual void memcpyImpl(const std::shared_ptr< GlobalMemorySlot > &destination, size_t dst_offset, const std::shared_ptr< LocalMemorySlot > &source, size_t src_offset, size_t size)
Definition communicationManager.hpp:569
__INLINE__ void increaseMessageSentCounter(HiCR::LocalMemorySlot &memorySlot) noexcept
Definition communicationManager.hpp:643
__INLINE__ void exchangeGlobalMemorySlots(GlobalMemorySlot::tag_t tag, const std::vector< globalKeyMemorySlotPair_t > &memorySlots)
Definition communicationManager.hpp:83
__INLINE__ void fence(const std::shared_ptr< LocalMemorySlot > &slot, size_t expectedSent, size_t expectedRecvd)
Definition communicationManager.hpp:379
uint64_t tag_t
Definition globalMemorySlot.hpp:49
uint64_t globalKey_t
Definition globalMemorySlot.hpp:44
Definition localMemorySlot.hpp:44
Provides a definition for a HiCR Global Memory Slot class.
Provides a definition for a HiCR Local Memory Slot class.
Provides a base definition for a HiCR MemorySpace class.
Provides a failure model and corresponding exception classes.
#define HICR_THROW_RUNTIME(...)
Definition exceptions.hpp:74
#define HICR_THROW_LOGIC(...)
Definition exceptions.hpp:67