SST 16.0.0
Structural Simulation Toolkit
link.h
1// Copyright 2009-2026 NTESS. Under the terms
2// of Contract DE-NA0003525 with NTESS, the U.S.
3// Government retains certain rights in this software.
4//
5// Copyright (c) 2009-2026, NTESS
6// All rights reserved.
7//
8// This file is part of the SST software package. For license
9// information, see the LICENSE file in the top level directory of the
10// distribution.
11
12#ifndef SST_CORE_LINK_H
13#define SST_CORE_LINK_H
14
15#include "sst/core/event.h"
16#include "sst/core/rankInfo.h"
17#include "sst/core/serialization/serialize_impl_fwd.h"
18#include "sst/core/sst_types.h"
19#include "sst/core/timeConverter.h"
20
21#include <cstdint>
22#include <string>
23#include <vector>
24
25namespace SST {
26
27#define _LINK_DBG(fmt, args...) __DBG(DBG_LINK, Link, fmt, ##args)
28
29class ActivityQueue;
30class BaseComponent;
31class TimeConverter;
32class LinkPair;
33class Simulation;
34
35class UnitAlgebra;
36
37namespace Profile {
39}
40
41class Link;
42
43template <>
45{
46 // Function implemented in link.cc
47 void operator()(Link*& s, SST::Core::Serialization::serializer& ser, ser_opt_t options);
48 void serialize_events(
49 SST::Core::Serialization::serializer& ser, uintptr_t delivery_info, ActivityQueue* queue = nullptr);
50
51 SST_FRIEND_SERIALIZE();
52};
53
54
55/** Link between two components. Carries events */
56class alignas(64) Link
57{
58 enum Type_t : uint16_t { POLL, HANDLER, SYNC, UNINITIALIZED };
59 enum Mode_t : uint8_t { INIT, RUN, COMPLETE };
60
62
63public:
64 /**
65 Attach point for inspecting, modifying or dropping events
66 sent on the Link.
67
68 NOTE: Using the Link::AttachPoint will noticeably affect the
69 performance of sending events on Links and it is recommended
70 that, if possible, Event::HandlerBase::AttachPoint or
71 Event::HandlerBase::InterceptPoint be used instead.
72 */
74 {
75 public:
76 /**
77 Function that will be called when an attach point is
78 registered with the tool implementing the attach point.
79 The metadata passed in will be dependent on what type of
80 tool this is attached to. The uintptr_t returned from this
81 function will be passed into the eventSent() function.
82
83 @param mdata Metadata to be passed into the tool
84
85 @return Opaque key that will be passed back into
86 eventSent() to identify the source of the call
87 */
88 virtual uintptr_t registerLinkAttachTool(const AttachPointMetaData& mdata) = 0;
89
90 /**
91 Function that will be called when an event is sent on a
92 Link with registered attach points. If ev is set to
93 nullptr, then the event will not be delivered and the tool
94 should delete the original event.
95
96 @param key Opaque key returned from registerLinkAttachTool()
97 */
98 virtual void eventSent(uintptr_t key, Event*& ev) = 0;
99
100 /**
101 Function that will be called to handle the key returned
102 from registerLinkAttachTool, if the AttachPoint tool is
103 serializable. This is needed because the key is opaque to
104 the Link, so it doesn't know how to handle it during
105 serialization. During SIZE and PACK phases of
106 serialization, the tool needs to store out any information
107 that will be needed to recreate data that is reliant on the
108 key. On UNPACK, the function needs to recreate any state
109 and reinitialize the passed in key reference to the proper
110 state to continue to make valid calls to eventSent().
111
112 Since not all tools will be serializable, there is a
113 default, empty implementation.
114
115 @param ser Serializer to use for serialization
116
117 @param key Key that would be passed into the eventSent() function.
118 */
120
121 virtual ~AttachPoint() = default;
122 };
123
124 friend class LinkPair;
125 friend class RankSync;
126 friend class ThreadSync;
127 friend class Simulation;
128 friend class SyncManager;
129 friend class ComponentInfo;
130 friend class BaseComponent;
131
132 ~Link();
133
134 /**
135 Set additional Latency to be added to events being sent out of this Link
136
137 @param cycles Number of cycles to be added
138
139 @param timebase Base units of cycles
140 */
141 void addSendLatency(int cycles, const std::string& timebase);
142
143 /**
144 Set additional Latency to be added to events being sent out of this Link
145
146 @param cycles Number of cycles to be added
147
148 @param timebase Base units of cycles
149 */
150 void addSendLatency(SimTime_t cycles, TimeConverter timebase);
151
152 /**
153 Set additional latency to be added on to events coming in on this Link.
154
155 @param cycles Number of cycles to be added
156
157 @param timebase Base units of cycles
158 */
159 void addRecvLatency(int cycles, const std::string& timebase);
160
161 /**
162 Set additional latency to be added on to events coming in on this Link.
163
164 @param cycles Number of cycles to be added
165
166 @param timebase Base units of cycles
167 */
168 void addRecvLatency(SimTime_t cycles, TimeConverter timebase);
169
170 /**
171 Set the callback function to be called when a message is delivered. Not available for Polling Links.
172
173 @param functor Functor to call when message is delivered
174 */
175 void setFunctor(Event::HandlerBase* functor);
176
177 /**
178 Replace the callback function to be called when a message is delivered. Any previous handler will be deleted.
179 Not available for Polling Links.
180
181 @param functor Functor to call when message is delivered
182 */
183 void replaceFunctor(Event::HandlerBase* functor);
184
185 /**
186 Get the callback function to be called when a message is delivered. Polling Links will return nullptr.
187
188 @return Functor used for event delivery
189 */
191
192 /**
193 Sends an Event over a Link with an additional delay specified with a TimeConverter. I.e. the total delay is the
194 Link's delay + the additional specified delay.
195
196 @param delay Additional delay
197
198 @param tc TimeConverter to specify timebase for the additional delay
199
200 @param event Event to send
201 */
202 inline void send(SimTime_t delay, TimeConverter tc, Event* event) { send_impl(tc.convertToCoreTime(delay), event); }
203
204
205 /**
206 Sends an event over a Link with additional delay specified by the Link's
207 default timebase.
208
209 @param delay The additional delay, in units of the Link's default timebase
210
211 @param event Event to send
212 */
213 inline void send(SimTime_t delay, Event* event) { send_impl(delay * defaultTimeBase, event); }
214
215 /**
216 Send an Event with no additional delay
217
218 @param event Event to send
219 */
220 inline void send(Event* event) { send_impl(0, event); }
221
222
223 /**
224 Retrieve a pending Event from the Link. For Links which do not have a set event handler, they can be polled with
225 this function. Returns nullptr if there is no pending Event. Not available for HANDLER-type Links.
226
227 @return Event if one is available, nullptr if no Event is available
228 */
229 Event* recv();
230
231 /**
232 Manually set the default defaultTimeBase
233
234 @param tc TimeConverter object for the timebase
235 */
237
238 /**
239 Return the default timebase for this Link
240
241 @return the default timebase for this Link
242 */
244
245 /**
246 Return the ID of this Link
247
248 @return the unique ID for this Link
249 */
250 LinkId_t getId()
251 {
252 if ( has_tool_list )
253 return (*attached_tools)[0].second;
254 else
255 return id;
256 }
257
258 /**
259 Send data during the init() or complete() phase.
260
261 @param Data event to send
262 */
263 void sendUntimedData(Event* data);
264
265 /**
266 Receive an Event (if any) during the init() or complete() phase.
267
268 @return Event if one is available, nullptr if no Event is available
269 */
271
272 /**
273 Return whether Link has been configured
274
275 @return True if Link has been configured, false otherwise
276 */
277 bool isConfigured() { return type != UNINITIALIZED; }
278
279
280#ifdef __SST_DEBUG_EVENT_TRACKING__
281 void setSendingComponentInfo(const std::string& comp_in, const std::string& type_in, const std::string& port_in)
282 {
283 comp = comp_in;
284 ctype = type_in;
285 port = port_in;
286 }
287
288 const std::string& getSendingComponentName() { return comp; }
289 const std::string& getSendingComponentType() { return ctype; }
290 const std::string& getSendingPort() { return port; }
291
292#endif
293
294protected:
295 Link();
296
297 void setAsSyncLink() { type = SYNC; }
298
299 /**
300 Set the delivery_info for the Link
301 */
302 void setDeliveryInfo(uintptr_t info) { delivery_info = info; }
303
304 /**
305 Set the tag field for event link ordering
306
307 @param new_tag New order tag to use for the Link
308 */
309 void setTag(uint32_t new_tag)
310 {
311 if ( tag != bit_util::type_max<uint32_t> ) pair_link->tag = new_tag;
312
313 // Interleaved links
314 // pair_link->tag = new_tag;
315
316 // Ordered SelfLinks
317 // if ( tag != type_max<uint32_t> ) pair_link->tag = new_tag;
318 // else pair_link->tag = 0x80000000 | new_tag;
319 }
320
321 /**
322 Get the latency on the link in units of core atomic time base
323
324 NOTE: This is a core only API and not part of the public stable API
325 */
326 SimTime_t getLatency() { return latency; }
327
328 /**
329 Get the delivery_info for the link
330 */
331 uintptr_t getDeliveryInfo() { return delivery_info; }
332
333 /**
334 Get the pair_link
335 */
336 Link* getPairLink() { return pair_link; }
337
338 /**
339 Sends an Event over a Link with an additional delay specified with a TimeConverter. I.e. the total delay is the
340 Link's delay + the additional specified delay.
341
342 @param delay Additional total delay to add in units of the core timebase
343
344 @param event Event to send
345 */
346 void send_impl(SimTime_t delay, Event* event);
347
348 /**
349 Updates the delivery info in an event. This is used during a restart and is implemented here because Link is a
350 friend of Event.
351
352 @param event Event to update
353
354 @param delivery_info New delivery info (pointer to handler cast as uintptr_t)
355 */
356 static void updateEventDeliveryInfo(Event* event, uintptr_t delivery_info)
357 {
358 event->updateDeliveryInfo(delivery_info);
359 }
360
361 /**
362 Variable used by Link restarts to know whether stored rank data for remote links is still valid (i.e. did we
363 restart with the exact same rank/thread count or not).
364 */
366
367 // Since Links are found in pairs, I will keep all the information
368 // needed for me to send and deliver an event to the other side of
369 // the Link. That means, that I mostly keep my pair's
370 // information. The one consequence, is that polling Links will
371 // have to pull the data from the pair, but since this is a less
372 // common case, that's okay (this decision makes the common case
373 // faster and the less common case slower).
374
375 /**
376 Queue of events to be received by the owning component
377 */
379
380 /**
381 Holds the delivery information. This is stored as a uintptr_t, but is actually a pointer converted using
382 reinterpret_cast. For Links connected to a Component/SubComponent, this holds a pointer to the delivery functor.
383 For Links connected to a Sync object, this holds a pointer to the remote Link to send the event on after
384 synchronization.
385 */
386 uintptr_t delivery_info;
387
388 /**
389 Timebase used if no other timebase is specified. Used to specify the units for added delays when sending, such as
390 in Link::send(). Often set by the Component::registerClock() function if the regAll argument is true.
391 */
393
394 /**
395 Latency of the Link. It is used by the partitioner as the weight. This latency is added to the delay put on the
396 event by the component.
397 */
398 SimTime_t latency;
399
400 /**
401 Pointer to the opposite side of this Link
402 */
404
405private:
406 friend class BaseComponent;
407
408 SimTime_t& current_time;
409 Type_t type;
410 Mode_t mode;
411 bool has_tool_list = false;
412 uint32_t tag;
413
414 /**
415 Create a new Link with a given tag
416
417 The tag is used for two different things depending on where this Link sends data:
418
419 If it sends it to a Sync object, then it represents the remote_tag used to lookup the correct Link on the other
420 side.
421
422 If it sends to a TimeVortex (or DirectLinkQueue), it is the value used for enforce_link_order (if that feature is
423 enabled).
424 */
425 explicit Link(LinkId_t id);
426
427 /**
428 Specifies that this Link has no callback, and is poll-based only
429 */
430 void setPolling();
431
432 /**
433 Set minimum Link latency
434 */
435 void setLatency(Cycle_t lat);
436
437 void sendUntimedData_sync(Event* data);
438 void finalizeConfiguration();
439 void prepareForComplete();
440
441 std::string createUniqueGlobalLinkName(
442 RankInfo local_rank, uintptr_t local_ptr, RankInfo remote_rank, uintptr_t remote_ptr);
443
444
445 void attachTool(AttachPoint* tool, const AttachPointMetaData& mdata);
446 void detachTool(AttachPoint* tool);
447
448
449 using ToolList = std::vector<std::pair<AttachPoint*, uintptr_t>>;
450
451 /**
452 We need to keep the Link object to 64-bits so we need to keep the ID and the attached tools in the same 8-bytes.
453 This will normally hold the 64-bit id for the link, but if we have attached tools, then the id for the Link will
454 be stored in the first entry of the attached_tools list.
455
456 The has_tool_list member variable stores which data is currently stored in this union. If has_tool_list is true,
457 then the union's attached_tools variable is currently active. Otherwise, it is storing the Link id.
458 */
459 union {
460 /**
461 The Link id is a globally unique id. For serial loads, the ids start at 1 and increment for each new Link.
462
463 On a parallel load, the top 32-bits is filled with the MPI rank and the bottom 32-bits start at 1 and
464 increment for each new rank. The ids for links that cross a rank boundary need to be reconciled so that the
465 Link objects on both ranks agree on the ID. This is done by having the "lower" rank send the Link name and
466 it's id for the Link to the "higher" rank, which will then use that id for the Link. "Higher" and "lower" are
467 determined in a way that hopefully spreads out the MPI traffic across all the ranks and isn't just a direct
468 greater/less than comparison. It is determined as follows:
469
470 1 - A rank is lower than the N/2 ranks after it, wrapping around to 0 when needed.
471
472 2 - A rank is higher than the N/2 ranks before it, wrapping around to N-1 when needed.
473
474 The id is used in several places:
475 - When exchanging Link pointers to put in the delivery_info field
476 - As the global name for connecting links on a restart from checkpoint
477
478 */
479 LinkId_t id;
480
481 /**
482 This stores any tools connected to the Link::AttachPoint. The first entry in the list will always contain
483 the Link id since the pointer to the attached_tools list is now using that memory location.
484 */
485 ToolList* attached_tools;
486 };
487
488
489 /**
490 Manually set the default time base
491
492 @param factor SimTime_T defining the timebase factor
493 */
494 void setDefaultTimeBase(SimTime_t factor) { defaultTimeBase = factor; }
495
496 /**
497 Set the default time base for uninitialized
498 */
499 void resetDefaultTimeBase() { defaultTimeBase = 0; }
500
501
502#ifdef __SST_DEBUG_EVENT_TRACKING__
503 std::string comp;
504 std::string ctype;
505 std::string port;
506#endif
507};
508
509/**
510 Self Links are Links from a component to itself
511*/
512class SelfLink : public Link
513{
514public:
515 SelfLink() :
516 Link()
517 {
518 pair_link = this;
519 latency = 0;
520 }
521};
522
523
524} // namespace SST
525
526#endif // SST_CORE_LINK_H
Base Class for a queue of Activities.
Definition activityQueue.h:22
Main component object for the simulation.
Definition baseComponent.h:67
Base serialize class.
Definition serialize.h:132
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition serializer.h:43
Base class for Events - Items sent across links to communicate between components.
Definition event.h:41
SSTHandlerBase< void, Event * > HandlerBase
Base handler for event delivery.
Definition event.h:48
Defines a pair of links (to define a connected link).
Definition linkPair.h:24
Definition eventHandlerProfileTool.h:35
Definition rankInfo.h:24
Main control class for a SST Simulation.
Definition simulation.h:121
A class to convert between a component's view of time and the core's view of time.
Definition timeConverter.h:31
SimTime_t convertToCoreTime(SimTime_t time) const
Converts from the component's view to the core's view of time.
Definition timeConverter.h:79
Performs Unit math in full precision.
Definition unitAlgebra.h:107
Struct used as a base class for all AttachPoint metadata passed to registration functions.
Definition sst_types.h:201