/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.contains(tag) == false) { HICR_THROW_LOGIC("Requesting a global memory slot for a tag (%lu) that has not been registered.", tag); }
107 if (_globalMemorySlotTagKeyMap.at(tag).contains(globalKey) == false)
108 {
109 for (const auto &elem : _globalMemorySlotTagKeyMap.at(tag)) { printf("For Tag %lu: Key %lu\n", tag, elem.first); }
110 printf("But tag %lu does not contain globalKey = %lu\n", tag, globalKey);
111 HICR_THROW_LOGIC("Requesting a global memory slot for a global key (%lu) not registered within the tag (%lu).", globalKey, tag);
112 }
113
114 // Getting requested memory slot
115 auto value = _globalMemorySlotTagKeyMap.at(tag).at(globalKey);
116
117 // Returning value
118 return value;
119 }
120 }
121
131 virtual uint8_t *serializeGlobalMemorySlot(const std::shared_ptr<HiCR::GlobalMemorySlot> &globalSlot) const
132 {
133 HICR_THROW_LOGIC("Trying to serialize a global memory slot; this is not supported in this backend\n");
134 return nullptr;
135 }
136
144 virtual std::shared_ptr<GlobalMemorySlot> deserializeGlobalMemorySlot(uint8_t *buffer, GlobalMemorySlot::tag_t tag)
145 {
146 HICR_THROW_LOGIC("Trying to deserialize a global memory slot; this is not supported in this backend\n");
147 return nullptr;
148 }
149
160 virtual std::shared_ptr<GlobalMemorySlot> promoteLocalMemorySlot(const std::shared_ptr<LocalMemorySlot> &localMemorySlot, GlobalMemorySlot::tag_t tag)
161 {
162 HICR_THROW_LOGIC("This backend does not support one-sided promotion of local memory slots to global");
163 return nullptr;
164 }
165
175 __INLINE__ void deregisterGlobalMemorySlot(const std::shared_ptr<GlobalMemorySlot> &memorySlot)
176 {
177 // Getting memory slot global information
178 const auto memorySlotTag = memorySlot->getGlobalTag();
179 const auto memorySlotGlobalKey = memorySlot->getGlobalKey();
180
181 // Checking whether the memory slot is correctly registered as global
182 if (_globalMemorySlotTagKeyMap.contains(memorySlotTag) == false)
183 {
184 HICR_THROW_LOGIC("Attempting to de-register a global memory slot but its tag/key pair is not registered in this backend");
185 }
186
187 // Removing memory slot from the global memory slot map
188 _globalMemorySlotTagKeyMap.at(memorySlotTag).erase(memorySlotGlobalKey);
190 }
191
204 __INLINE__ void destroyGlobalMemorySlot(const std::shared_ptr<GlobalMemorySlot> &memorySlot)
205 {
206 auto tag = memorySlot->getGlobalTag();
207 // Implicit creation of the tag entry if it doesn't exist is desired here
208 _globalMemorySlotsToDestroyPerTag[tag].push_back(memorySlot);
209 }
210
219 virtual void destroyPromotedGlobalMemorySlot(const std::shared_ptr<GlobalMemorySlot> &memorySlot)
220 {
221 HICR_THROW_LOGIC("This backend does not support promoted global memory slots.");
222 }
223
231 __INLINE__ void queryMemorySlotUpdates(std::shared_ptr<LocalMemorySlot> memorySlot)
232 {
233 // Getting value by copy
234 queryMemorySlotUpdatesImpl(std::move(memorySlot));
235 }
236
250 __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)
251 {
252 // Getting slot sizes. This operation is thread-safe
253 const auto srcSize = source->getSize();
254 const auto dstSize = destination->getSize();
255
256 // Making sure the memory slots exist and is not null
257 const auto actualSrcSize = size + src_offset;
258 const auto actualDstSize = size + dst_offset;
259
260 // Checking size doesn't exceed slot size
261 if (actualSrcSize > srcSize)
262 HICR_THROW_RUNTIME("Memcpy size (%lu) + offset (%lu) = (%lu) exceeds source slot (%p) capacity (%lu).", size, src_offset, actualSrcSize, source->getPointer(), srcSize);
263
264 // Checking size doesn't exceed slot size
265 if (actualDstSize > dstSize)
267 "Memcpy size (%lu) + offset (%lu) = (%lu) exceeds destination slot (%p) capacity (%lu).", size, dst_offset, actualDstSize, destination->getPointer(), dstSize);
268
269 // To enable concurrent memcpy operations, the implementation is executed outside the mutex zone
270 // This means that the developer needs to make sure that the implementation is concurrency-safe,
271 // and try not to access any of the internal Backend class fields without proper mutex locking
272
273 // Now calling internal memcpy function to give us a function that satisfies the operation
274 memcpyImpl(destination, dst_offset, source, src_offset, size);
275 }
276
290 __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)
291 {
292 // Getting slot sizes. This operation is thread-safe
293 const auto srcSize = source->getSize();
294
295 // Making sure the memory slots exist and is not null
296 const auto actualSrcSize = size + src_offset;
297
298 // Checking size doesn't exceed slot size
299 if (actualSrcSize > srcSize)
300 HICR_THROW_RUNTIME("Memcpy size (%lu) + offset (%lu) = (%lu) exceeds source slot (%p) capacity (%lu).", size, src_offset, actualSrcSize, source->getPointer(), srcSize);
301
302 // Now calling internal memcpy function to give us a function that satisfies the operation
303 memcpyImpl(destination, dst_offset, source, src_offset, size);
304 }
305
319 __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)
320 {
321 // Getting slot sizes. This operation is thread-safe
322 const auto dstSize = destination->getSize();
323
324 // Making sure the memory slots exist and is not null
325 const auto actualDstSize = size + dst_offset;
326
327 // Checking size doesn't exceed slot size
328 if (actualDstSize > dstSize)
330 "Memcpy size (%lu) + offset (%lu) = (%lu) exceeds destination slot (%p) capacity (%lu).", size, dst_offset, actualDstSize, destination->getPointer(), dstSize);
331
332 // Now calling internal memcpy function to give us a function that satisfies the operation
333 memcpyImpl(destination, dst_offset, source, src_offset, size);
334 }
335
360 __INLINE__ void fence(GlobalMemorySlot::tag_t tag)
361 {
362 // Now call the proper fence, as implemented by the backend
363 fenceImpl(tag);
364
365 // Clear the memory slots to destroy
366 _globalMemorySlotsToDestroyPerTag[tag].clear();
367 _globalMemorySlotsToDestroyPerTag.erase(tag);
368 }
369
381 __INLINE__ void fence(const std::shared_ptr<LocalMemorySlot> &slot, size_t expectedSent, size_t expectedRecvd)
382 {
383 // To enable concurrent fence operations, the implementation is executed outside the mutex zone
384 // This means that the developer needs to make sure that the implementation is concurrency-safe,
385 // and try not to access any of the internal Backend class fields without proper mutex locking
386
387 // Now call the proper fence, as implemented by the backend
388 fenceImpl(slot, expectedSent, expectedRecvd);
389 }
390
402 __INLINE__ void fence(const std::shared_ptr<GlobalMemorySlot> &slot, size_t expectedSent, size_t expectedRecvd)
403 {
404 // To enable concurrent fence operations, the implementation is executed outside the mutex zone
405 // This means that the developer needs to make sure that the implementation is concurrency-safe,
406 // and try not to access any of the internal Backend class fields without proper mutex locking
407
408 // Now call the proper fence, as implemented by the backend
409 fenceImpl(slot, expectedSent, expectedRecvd);
410 }
411
420 __INLINE__ bool acquireGlobalLock(const std::shared_ptr<GlobalMemorySlot> &memorySlot)
421 {
422 // Getting memory slot global information
423 const auto memorySlotTag = memorySlot->getGlobalTag();
424 const auto memorySlotGlobalKey = memorySlot->getGlobalKey();
425
426 // Checking whether the memory slot is correctly registered as global
427 if (_globalMemorySlotTagKeyMap.contains(memorySlotTag) == false)
428 HICR_THROW_LOGIC("Attempting to lock a global memory slot but its tag/key pair is not registered in this backend");
429
430 // Checking whether the memory slot is correctly registered as global
431 if (_globalMemorySlotTagKeyMap.at(memorySlotTag).contains(memorySlotGlobalKey) == false)
432 HICR_THROW_LOGIC("Attempting to lock a global memory slot but its tag/key pair is not registered in this backend");
433
434 // Calling internal implementation
435 return acquireGlobalLockImpl(memorySlot);
436 }
437
443 __INLINE__ void releaseGlobalLock(const std::shared_ptr<GlobalMemorySlot> &memorySlot)
444 {
445 // Getting memory slot global information
446 const auto memorySlotTag = memorySlot->getGlobalTag();
447 const auto memorySlotGlobalKey = memorySlot->getGlobalKey();
448
449 // Checking whether the memory slot is correctly registered as global
450 if (_globalMemorySlotTagKeyMap.contains(memorySlotTag) == false)
451 {
452 HICR_THROW_LOGIC("Attempting to release a global memory slot but its tag/key pair is not registered in this backend");
453 }
454
455 // Checking whether the memory slot is correctly registered as global
456 if (_globalMemorySlotTagKeyMap.at(memorySlotTag).contains(memorySlotGlobalKey) == false)
457 {
458 HICR_THROW_LOGIC("Attempting to release a global memory slot but its tag/key pair is not registered in this backend");
459 }
460
461 // Calling internal implementation
462 releaseGlobalLockImpl(memorySlot);
463 }
464
468 __INLINE__ virtual void flushSent() {}
469
473 __INLINE__ virtual void flushReceived() {}
474
479 [[nodiscard]] __INLINE__ auto &getGlobalMemorySlotTagKeyMap() { return _globalMemorySlotTagKeyMap; }
480
486 {
487 _globalMemorySlotTagKeyMap = globalMemorySlotTagKeyMap;
488 }
489
490 protected:
491
499 __INLINE__ void registerGlobalMemorySlot(const std::shared_ptr<GlobalMemorySlot> &memorySlot)
500 {
501 // Getting memory slot information
502 const auto tag = memorySlot->getGlobalTag();
503 const auto globalKey = memorySlot->getGlobalKey();
504
505 // Adding memory slot to the global map (based on tag and key)
506 _globalMemorySlotTagKeyMap[tag][globalKey] = memorySlot;
507 }
508
518 virtual std::shared_ptr<GlobalMemorySlot> getGlobalMemorySlotImpl(GlobalMemorySlot::tag_t tag, GlobalMemorySlot::globalKey_t globalKey) = 0;
519
526 virtual void exchangeGlobalMemorySlotsImpl(GlobalMemorySlot::tag_t tag, const std::vector<globalKeyMemorySlotPair_t> &memorySlots) = 0;
527
533 virtual void queryMemorySlotUpdatesImpl(std::shared_ptr<LocalMemorySlot> memorySlot) = 0;
534
540 virtual void deregisterGlobalMemorySlotImpl(const std::shared_ptr<GlobalMemorySlot> &memorySlot) {};
541
548 virtual void destroyGlobalMemorySlotImpl(std::shared_ptr<GlobalMemorySlot> memorySlot) = 0;
549
559 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)
560 {
561 HICR_THROW_LOGIC("Local->Local memcpy operations are unsupported by the given backend");
562 };
563
573 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)
574 {
575 HICR_THROW_LOGIC("Local->Global memcpy operations are unsupported by the given backend");
576 };
577
587 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)
588 {
589 HICR_THROW_LOGIC("Global->Local memcpy operations are unsupported by the given backend");
590 };
591
599 virtual void fenceImpl(const std::shared_ptr<LocalMemorySlot> &slot, size_t expectedSent, size_t expectedRcvd) {}
607 virtual void fenceImpl(const std::shared_ptr<GlobalMemorySlot> &slot, size_t expectedSent, size_t expectedRcvd) {}
614 virtual void fenceImpl(GlobalMemorySlot::tag_t tag) = 0;
615
621 virtual bool acquireGlobalLockImpl(std::shared_ptr<GlobalMemorySlot> memorySlot) = 0;
622
627 virtual void releaseGlobalLockImpl(std::shared_ptr<GlobalMemorySlot> memorySlot) = 0;
628
633 [[nodiscard]] __INLINE__ auto &getGlobalMemorySlotsToDestroyPerTag() { return _globalMemorySlotsToDestroyPerTag; }
634
640 __INLINE__ void increaseMessageRecvCounter(HiCR::LocalMemorySlot &memorySlot) noexcept { memorySlot.increaseMessagesRecv(); }
641
647 __INLINE__ void increaseMessageSentCounter(HiCR::LocalMemorySlot &memorySlot) noexcept { memorySlot.increaseMessagesSent(); }
648
655 __INLINE__ void setMessagesRecv(HiCR::LocalMemorySlot &memorySlot, const size_t count) noexcept { memorySlot.setMessagesRecv(count); }
656
663 __INLINE__ void setMessagesSent(HiCR::LocalMemorySlot &memorySlot, const size_t count) noexcept { memorySlot.setMessagesSent(count); }
664
665 private:
666
670 globalMemorySlotTagKeyMap_t _globalMemorySlotTagKeyMap;
671
675 std::map<GlobalMemorySlot::tag_t, std::vector<std::shared_ptr<GlobalMemorySlot>>> _globalMemorySlotsToDestroyPerTag;
676};
677
678} // 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:160
virtual uint8_t * serializeGlobalMemorySlot(const std::shared_ptr< HiCR::GlobalMemorySlot > &globalSlot) const
Definition communicationManager.hpp:131
__INLINE__ auto & getGlobalMemorySlotTagKeyMap()
Definition communicationManager.hpp:479
__INLINE__ void setMessagesSent(HiCR::LocalMemorySlot &memorySlot, const size_t count) noexcept
Definition communicationManager.hpp:663
__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:559
virtual __INLINE__ void flushReceived()
Definition communicationManager.hpp:473
__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:250
virtual void fenceImpl(const std::shared_ptr< LocalMemorySlot > &slot, size_t expectedSent, size_t expectedRcvd)
Definition communicationManager.hpp:599
virtual ~CommunicationManager()=default
__INLINE__ void releaseGlobalLock(const std::shared_ptr< GlobalMemorySlot > &memorySlot)
Definition communicationManager.hpp:443
virtual void fenceImpl(const std::shared_ptr< GlobalMemorySlot > &slot, size_t expectedSent, size_t expectedRcvd)
Definition communicationManager.hpp:607
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:360
__INLINE__ void setGlobalMemorySlotTagKeyMap(const HiCR::CommunicationManager::globalMemorySlotTagKeyMap_t &globalMemorySlotTagKeyMap)
Definition communicationManager.hpp:485
virtual __INLINE__ void flushSent()
Definition communicationManager.hpp:468
__INLINE__ void deregisterGlobalMemorySlot(const std::shared_ptr< GlobalMemorySlot > &memorySlot)
Definition communicationManager.hpp:175
__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:290
__INLINE__ void registerGlobalMemorySlot(const std::shared_ptr< GlobalMemorySlot > &memorySlot)
Definition communicationManager.hpp:499
__INLINE__ bool acquireGlobalLock(const std::shared_ptr< GlobalMemorySlot > &memorySlot)
Definition communicationManager.hpp:420
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:587
__INLINE__ void destroyGlobalMemorySlot(const std::shared_ptr< GlobalMemorySlot > &memorySlot)
Definition communicationManager.hpp:204
virtual std::shared_ptr< GlobalMemorySlot > deserializeGlobalMemorySlot(uint8_t *buffer, GlobalMemorySlot::tag_t tag)
Definition communicationManager.hpp:144
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:231
virtual void deregisterGlobalMemorySlotImpl(const std::shared_ptr< GlobalMemorySlot > &memorySlot)
Definition communicationManager.hpp:540
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:402
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:640
__INLINE__ auto & getGlobalMemorySlotsToDestroyPerTag()
Definition communicationManager.hpp:633
__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:319
__INLINE__ void setMessagesRecv(HiCR::LocalMemorySlot &memorySlot, const size_t count) noexcept
Definition communicationManager.hpp:655
virtual void destroyPromotedGlobalMemorySlot(const std::shared_ptr< GlobalMemorySlot > &memorySlot)
Definition communicationManager.hpp:219
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:573
__INLINE__ void increaseMessageSentCounter(HiCR::LocalMemorySlot &memorySlot) noexcept
Definition communicationManager.hpp:647
__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:381
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