Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
SharedMemoryParallelMng.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* SharedMemoryParallelMng.cc (C) 2000-2026 */
9/* */
10/* Implementation of messages in shared memory mode. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/parallel/thread/SharedMemoryParallelMng.h"
15
16#include "arcane/utils/NotImplementedException.h"
17#include "arcane/utils/NotSupportedException.h"
18#include "arcane/utils/PlatformUtils.h"
19#include "arcane/utils/TraceInfo.h"
20#include "arcane/utils/NumericTypes.h"
21#include "arcane/utils/ArgumentException.h"
22#include "arcane/utils/FatalErrorException.h"
23#include "arcane/utils/ITraceMng.h"
24
25#include "arcane/parallel/IStat.h"
26
27#include "arcane/parallel/thread/SharedMemoryParallelDispatch.h"
28#include "arcane/parallel/thread/ISharedMemoryMessageQueue.h"
29#include "arcane/parallel/thread/internal/SharedMemoryMachineShMemWinBaseInternalCreator.h"
30#include "arcane/parallel/thread/internal/SharedMemoryContigMachineShMemWinBaseInternal.h"
31#include "arcane/parallel/thread/internal/SharedMemoryMachineShMemWinBaseInternal.h"
32
33#include "arcane/core/Timer.h"
34#include "arcane/core/IIOMng.h"
35#include "arcane/core/ISerializeMessageList.h"
36#include "arcane/core/IItemFamily.h"
37#include "arcane/core/internal/SerializeMessage.h"
38#include "arcane/core/internal/ParallelMngInternal.h"
39#include "arcane/core/internal/MachineShMemWinMemoryAllocator.h"
40
41#include "arcane/impl/TimerMng.h"
42#include "arcane/impl/ParallelReplication.h"
43#include "arcane/impl/internal/ParallelMngUtilsFactoryBase.h"
44
45#include "arccore/message_passing/RequestListBase.h"
46#include "arccore/message_passing/internal/SerializeMessageList.h"
47
48#include <map>
49
50/*---------------------------------------------------------------------------*/
51/*---------------------------------------------------------------------------*/
52
53namespace Arcane
54{
55extern "C++" ARCANE_IMPL_EXPORT IIOMng*
56arcaneCreateIOMng(IParallelMng* psm);
57}
58
60{
61
62/*---------------------------------------------------------------------------*/
63/*---------------------------------------------------------------------------*/
64
70{
72
73 public:
74
75 explicit RequestList(SharedMemoryParallelMng* pm)
76 : m_parallel_mng(pm)
77 , m_message_queue(pm->m_message_queue)
78 , m_local_rank(m_parallel_mng->commRank())
79 {}
80
81 public:
82
83 void _wait(Parallel::eWaitType wait_type) override
84 {
85 switch (wait_type) {
86 case Parallel::WaitAll:
87 return m_message_queue->waitAll(_requests());
89 return m_message_queue->waitSome(m_local_rank, _requests(), _requestsDone(), false);
91 return m_message_queue->waitSome(m_local_rank, _requests(), _requestsDone(), true);
92 }
93 }
94
95 private:
96
97 SharedMemoryParallelMng* m_parallel_mng;
98 ISharedMemoryMessageQueue* m_message_queue;
99 Int32 m_local_rank;
100};
101
102/*---------------------------------------------------------------------------*/
103/*---------------------------------------------------------------------------*/
104
106: public ParallelMngInternal
107{
108 public:
109
110 explicit Impl(SharedMemoryParallelMng* pm, SharedMemoryMachineShMemWinBaseInternalCreator* window_creator)
111 : ParallelMngInternal(pm)
112 , m_parallel_mng(pm)
113 , m_window_creator(window_creator)
114 , m_alloc(makeRef(new MachineShMemWinMemoryAllocator(pm)))
115 {}
116
117 ~Impl() override = default;
118
119 public:
120
121 Int32 masterParallelIORank() const override { return 0; }
122 Int32 nbSendersToMasterParallelIO() const override { return m_parallel_mng->commSize(); }
123
124 void initializeWindowCreator() override {}
125
127 {
128 return true;
129 }
130
132 {
133 return makeRef(m_window_creator->createWindow(m_parallel_mng->commRank(), sizeof_segment, sizeof_type));
134 }
135
137 {
138 return makeRef(m_window_creator->createDynamicWindow(m_parallel_mng->commRank(), sizeof_segment, sizeof_type));
139 }
140
142 {
143 return MemoryAllocationOptions{ m_alloc.get() };
144 }
145
147 {
148 return m_window_creator->machineRanks();
149 }
150
151 void machineBarrier() override
152 {
153 m_window_creator->machineBarrier();
154 }
155
156 private:
157
158 SharedMemoryParallelMng* m_parallel_mng;
161};
162
163/*---------------------------------------------------------------------------*/
164/*---------------------------------------------------------------------------*/
165
166SharedMemoryParallelMng::
167SharedMemoryParallelMng(const SharedMemoryParallelMngBuildInfo& build_info)
168: ParallelMngDispatcher(ParallelMngDispatcherBuildInfo(build_info.rank, build_info.nb_rank))
169, m_trace(build_info.trace_mng)
170, m_thread_mng(build_info.thread_mng)
171, m_sequential_parallel_mng(build_info.sequential_parallel_mng)
172, m_timer_mng(nullptr)
173, m_replication(new ParallelReplication())
174, m_world_parallel_mng(build_info.world_parallel_mng)
175, m_io_mng(nullptr)
176, m_message_queue(build_info.message_queue)
177, m_is_parallel(build_info.nb_rank != 1)
178, m_rank(build_info.rank)
179, m_nb_rank(build_info.nb_rank)
180, m_is_initialized(false)
181, m_stat(Parallel::createDefaultStat())
182, m_thread_barrier(build_info.thread_barrier)
183, m_all_dispatchers(build_info.all_dispatchers)
184, m_sub_builder_factory(build_info.sub_builder_factory)
185, m_parent_container_ref(build_info.container)
186, m_mpi_communicator(build_info.communicator)
187, m_utils_factory(createRef<ParallelMngUtilsFactoryBase>())
188, m_parallel_mng_internal(new Impl(this, build_info.window_creator))
189{
190 if (!m_world_parallel_mng)
191 m_world_parallel_mng = this;
192}
193
194/*---------------------------------------------------------------------------*/
195/*---------------------------------------------------------------------------*/
196
197SharedMemoryParallelMng::
198~SharedMemoryParallelMng()
199{
200 delete m_parallel_mng_internal;
201 delete m_replication;
202 m_sequential_parallel_mng.reset();
203 delete m_io_mng;
204 delete m_timer_mng;
205 delete m_stat;
206}
207
208/*---------------------------------------------------------------------------*/
209/*---------------------------------------------------------------------------*/
210
211namespace
212{
213 // Class to create the different dispatchers
214 class DispatchCreator
215 {
216 public:
217
218 DispatchCreator(ITraceMng* tm, SharedMemoryParallelMng* mpm,
219 ISharedMemoryMessageQueue* message_queue,
220 SharedMemoryAllDispatcher* all_dispatchers)
221 : m_tm(tm)
222 , m_mpm(mpm)
223 , m_message_queue(message_queue)
224 , m_all_dispatchers(all_dispatchers)
225 {}
226
227 public:
228
229 template <typename DataType> SharedMemoryParallelDispatch<DataType>*
230 create()
231 {
232 ISharedMemoryMessageQueue* tmq = m_message_queue;
233 SharedMemoryAllDispatcher* ad = m_all_dispatchers;
234 auto& field = ad->instance((DataType*)nullptr);
235 return new SharedMemoryParallelDispatch<DataType>(m_tm, m_mpm, tmq, field);
236 }
237
238 ITraceMng* m_tm;
239 SharedMemoryParallelMng* m_mpm;
240 ISharedMemoryMessageQueue* m_message_queue;
241 SharedMemoryAllDispatcher* m_all_dispatchers;
242 };
243} // namespace
244
245/*---------------------------------------------------------------------------*/
246/*---------------------------------------------------------------------------*/
247
249build()
250{
251 m_message_queue->setTraceMng(m_rank, traceMng());
252 m_timer_mng = new TimerMng(traceMng());
253
254 DispatchCreator creator(m_trace.get(), this, m_message_queue, m_all_dispatchers);
255 this->createDispatchers(creator);
256
257 m_io_mng = arcaneCreateIOMng(this);
258}
259
260/*----------------------------------------------------------------------------*/
261/*---------------------------------------------------------------------------*/
262
265{
266 Trace::Setter mci(m_trace.get(), "Thread");
267 if (m_is_initialized) {
268 m_trace->warning() << "SharedMemoryParallelMng already initialized";
269 return;
270 }
271
272 m_is_initialized = true;
273}
274
275/*---------------------------------------------------------------------------*/
276/*---------------------------------------------------------------------------*/
277
280{
281 return m_utils_factory->createGetVariablesValuesOperation(this)._release();
282}
283
286{
287 return m_utils_factory->createTransferValuesOperation(this)._release();
288}
289
292{
293 return m_utils_factory->createExchanger(this)._release();
294}
295
296/*---------------------------------------------------------------------------*/
297/*---------------------------------------------------------------------------*/
298
299/*---------------------------------------------------------------------------*/
300/*---------------------------------------------------------------------------*/
301
302void SharedMemoryParallelMng::
303sendSerializer(ISerializer* values, Int32 dest_rank)
304{
305 auto p2p_message = buildMessage(dest_rank, Parallel::Blocking);
306 Request r = m_message_queue->addSend(p2p_message, SendBufferInfo(values));
307 m_message_queue->waitAll(ArrayView<Request>(1, &r));
308}
309
310/*---------------------------------------------------------------------------*/
311/*---------------------------------------------------------------------------*/
312
313Parallel::Request SharedMemoryParallelMng::
314sendSerializer(ISerializer* values, Int32 rank, ByteArray& bytes)
315{
316 ARCANE_UNUSED(bytes);
317 return m_message_queue->addSend(buildMessage(rank, Parallel::Blocking), SendBufferInfo(values));
318}
319
320/*---------------------------------------------------------------------------*/
321/*---------------------------------------------------------------------------*/
322
325{
326 return m_utils_factory->createSendSerializeMessage(this, rank)._release();
327}
328
329/*---------------------------------------------------------------------------*/
330/*---------------------------------------------------------------------------*/
331
332void SharedMemoryParallelMng::
333broadcastSerializer(ISerializer* values, Int32 rank)
334{
335 // Basic implementation for now.
336 // The rank that broadcasts sends the message to everyone.
337 if (m_rank == rank) {
339 for (Int32 i = 0; i < m_nb_rank; ++i) {
340 if (i != m_rank) {
341 requests.add(m_message_queue->addSend(buildMessage(i, Parallel::NonBlocking), SendBufferInfo(values)));
342 }
343 }
344 m_message_queue->waitAll(requests);
345 }
346 else {
347 recvSerializer(values, rank);
348 }
349}
350
351/*---------------------------------------------------------------------------*/
352/*---------------------------------------------------------------------------*/
353
354void SharedMemoryParallelMng::
355recvSerializer(ISerializer* values, Int32 rank)
356{
357 auto p2p_message = buildMessage(rank, Parallel::Blocking);
358 Request r = m_message_queue->addReceive(p2p_message, ReceiveBufferInfo(values));
359 m_message_queue->waitAll(ArrayView<Request>(1, &r));
360}
361
362/*---------------------------------------------------------------------------*/
363/*---------------------------------------------------------------------------*/
364
367{
368 return m_utils_factory->createReceiveSerializeMessage(this, rank)._release();
369}
370
371/*---------------------------------------------------------------------------*/
372/*---------------------------------------------------------------------------*/
373
376{
377 ARCANE_UNUSED(requests);
378 throw NotImplementedException(A_FUNCINFO);
379}
380
381/*---------------------------------------------------------------------------*/
382/*---------------------------------------------------------------------------*/
383
386{
387 if (m_stat)
388 m_stat->print(m_trace.get());
389}
390
391/*---------------------------------------------------------------------------*/
392/*---------------------------------------------------------------------------*/
393
395barrier()
396{
397 m_thread_barrier->wait();
398}
399
400/*---------------------------------------------------------------------------*/
401/*---------------------------------------------------------------------------*/
402
405{
406 Real begin_time = platform::getRealTime();
407 m_message_queue->waitAll(requests);
408 Real end_time = platform::getRealTime();
409 m_stat->add("WaitAll", (end_time - begin_time), 0);
410}
411
412/*---------------------------------------------------------------------------*/
413/*---------------------------------------------------------------------------*/
414
415ISerializeMessageList* SharedMemoryParallelMng::
416_createSerializeMessageList()
417{
418 return new MP::internal::SerializeMessageList(messagePassingMng());
419}
420
421/*---------------------------------------------------------------------------*/
422/*---------------------------------------------------------------------------*/
423
425probe(const PointToPointMessageInfo& message)
426{
427 PointToPointMessageInfo p2p_message(message);
428 p2p_message.setEmiterRank(MessageRank(m_rank));
429 return m_message_queue->probe(p2p_message);
430}
431
432/*---------------------------------------------------------------------------*/
433/*---------------------------------------------------------------------------*/
434
437{
438 PointToPointMessageInfo p2p_message(message);
439 p2p_message.setEmiterRank(MessageRank(m_rank));
440 return m_message_queue->legacyProbe(p2p_message);
441}
442
443/*---------------------------------------------------------------------------*/
444/*---------------------------------------------------------------------------*/
445
446auto SharedMemoryParallelMng::
447sendSerializer(const ISerializer* values, const PointToPointMessageInfo& message) -> Request
448{
449 auto p2p_message = buildMessage(message);
450 return m_message_queue->addSend(p2p_message, SendBufferInfo(values));
451}
452
453/*---------------------------------------------------------------------------*/
454/*---------------------------------------------------------------------------*/
455
456auto SharedMemoryParallelMng::
457receiveSerializer(ISerializer* values, const PointToPointMessageInfo& message) -> Request
458{
459 auto p2p_message = buildMessage(message);
460 return m_message_queue->addReceive(p2p_message, ReceiveBufferInfo(values));
461}
462
463/*---------------------------------------------------------------------------*/
464/*---------------------------------------------------------------------------*/
465
468{
469 return m_utils_factory->createSynchronizer(this, family)._release();
470}
471
472/*---------------------------------------------------------------------------*/
473/*---------------------------------------------------------------------------*/
474
476createSynchronizer(const ItemGroup& group)
477{
478 return m_utils_factory->createSynchronizer(this, group)._release();
479}
480
481/*---------------------------------------------------------------------------*/
482/*---------------------------------------------------------------------------*/
483
486{
487 return m_utils_factory->createTopology(this)._release();
488}
489
490/*---------------------------------------------------------------------------*/
491/*---------------------------------------------------------------------------*/
492
494replication() const
495{
496 return m_replication;
497}
498
499/*---------------------------------------------------------------------------*/
500/*---------------------------------------------------------------------------*/
501
504{
505 delete m_replication;
506 m_replication = v;
507}
508
509/*---------------------------------------------------------------------------*/
510/*---------------------------------------------------------------------------*/
511
512IParallelMng* SharedMemoryParallelMng::
513_createSubParallelMng(Int32ConstArrayView kept_ranks)
514{
515 ARCANE_UNUSED(kept_ranks);
516 // We cannot implement this method because we go through
517 // IParallelMngContainer::_createParallelMng() which obligatorily
518 // creates
519 // a 'Ref<IParallelMng>'.
520 ARCANE_THROW(NotSupportedException, "Use createSubParallelMngRef() instead");
521}
522
523/*---------------------------------------------------------------------------*/
524/*---------------------------------------------------------------------------*/
525
528{
529 if (kept_ranks.empty())
530 ARCANE_FATAL("kept_ranks is empty");
531 ARCANE_CHECK_POINTER(m_sub_builder_factory);
532
534 Int32 nb_rank = kept_ranks.size();
535
536 // Check if I am in the list of kept ranks and if so
537 // determine my rank in the created IParallelMng
538 Int32 my_new_rank = (-1);
539 for (Integer i = 0; i < nb_rank; ++i)
540 if (kept_ranks[i] == m_rank) {
541 my_new_rank = i;
542 break;
543 }
544
545 barrier();
546 // Rank 0 creates the builder
547 if (m_rank == 0) {
548 builder = m_sub_builder_factory->_createParallelMngBuilder(nb_rank, m_mpi_communicator, m_mpi_communicator);
549 // Positions the builder for everyone
550 m_all_dispatchers->m_create_sub_parallel_mng_info.m_builder = builder;
551 }
552 barrier();
553
554 builder = m_all_dispatchers->m_create_sub_parallel_mng_info.m_builder;
555 ARCANE_CHECK_POINTER(builder.get());
556
557 Ref<IParallelMng> new_parallel_mng;
558 if (my_new_rank >= 0) {
559 new_parallel_mng = builder->_createParallelMng(my_new_rank, traceMng());
560 //auto* new_sm = dynamic_cast<SharedMemoryParallelMng*>(new_parallel_mng.get());
561 //if (new_sm)
562 //new_sm->m_mpi_communicator = m_mpi_communicator;
563 }
564 barrier();
565 // Here, everyone has created their IParallelMng. We can therefore
566 // delete the reference to the builder.
567 // TODO: a reference counter must be added to the builder
568 // otherwise it will never be destroyed.
569 if (m_rank == 0) {
570 m_all_dispatchers->m_create_sub_parallel_mng_info.m_builder.reset();
571 }
572 barrier();
573
574 return new_parallel_mng;
575}
576
577/*---------------------------------------------------------------------------*/
578/*---------------------------------------------------------------------------*/
579
586
587/*---------------------------------------------------------------------------*/
588/*---------------------------------------------------------------------------*/
589
590Ref<IParallelMng> SharedMemoryParallelMng::
591sequentialParallelMngRef()
592{
593 return m_sequential_parallel_mng;
594}
595
598{
599 return m_sequential_parallel_mng.get();
600}
601
602/*---------------------------------------------------------------------------*/
603/*---------------------------------------------------------------------------*/
604
606buildMessage(const PointToPointMessageInfo& orig_message)
607{
608 PointToPointMessageInfo p2p_message{ orig_message };
609 p2p_message.setEmiterRank(MessageRank(m_rank));
610 return p2p_message;
611}
612
613/*---------------------------------------------------------------------------*/
614/*---------------------------------------------------------------------------*/
615
616PointToPointMessageInfo SharedMemoryParallelMng::
617buildMessage(Int32 dest, Parallel::eBlockingType blocking_mode)
618{
619 return buildMessage({ MessageRank(dest), blocking_mode });
620}
621
622/*---------------------------------------------------------------------------*/
623/*---------------------------------------------------------------------------*/
624
630
631/*---------------------------------------------------------------------------*/
632/*---------------------------------------------------------------------------*/
633
634} // End namespace Arcane::MessagePassing
635
636/*---------------------------------------------------------------------------*/
637/*---------------------------------------------------------------------------*/
#define ARCANE_CHECK_POINTER(ptr)
Macro returning the pointer ptr if it is not null or throwing an exception if it is null.
#define ARCANE_THROW(exception_class,...)
Macro for throwing an exception with formatting.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Modifiable view of an array of type T.
void add(ConstReferenceType val)
Adds element val to the end of the array.
Constant view of an array of type T.
constexpr Integer size() const noexcept
Number of elements in the array.
constexpr bool empty() const noexcept
true if the array is empty (size()==0)
Operations to access variable values from another subdomain.
Interface of the input/output manager.
Definition IIOMng.h:37
Interface of an entity family.
Definition IItemFamily.h:83
Information exchange between processors.
Interface of the parallelism manager for a subdomain.
Brief information on parallel subdomain replication.
Information on the computing core allocation topology.
Sends values across different processors.
Interface of a variable synchronization service.
Mesh entity group.
Definition ItemGroup.h:51
Information about the source of a message.
Information for sending/receiving a point-to-point message.
void setEmiterRank(MessageRank rank)
Positions the message sender rank.
bool isMachineShMemWinAvailable() override
Method allowing to know if shared memory mode is supported.
MemoryAllocationOptions machineShMemWinMemoryAllocator() override
Method allowing retrieval of a shared memory allocator.
void initializeWindowCreator() override
Method allowing the initialization of the windowCreator specific to the implementation.
Ref< IMachineShMemWinBaseInternal > createMachineShMemWinBase(Int64 sizeof_segment, Int32 sizeof_type) override
Method allowing the creation of a dynamic memory window on the node.
ConstArrayView< Int32 > machineRanks() override
Method allowing retrieval of the ranks of the sub-domains of the computing node.
Ref< IContigMachineShMemWinBaseInternal > createContigMachineShMemWinBase(Int64 sizeof_segment, Int32 sizeof_type) override
Method allowing the creation of a memory window on the node.
void machineBarrier() override
Method allowing a barrier for the sub-domains of the computing node.
Implementation of IRequestList for SharedMemoryParallelMng.
void _wait(Parallel::eWaitType wait_type) override
Performs the wait or test.
IParallelTopology * createTopology() override
Creates an instance containing information about the rank topology of this manager.
IGetVariablesValuesParallelOperation * createGetVariablesValuesOperation() override
Returns an operation to retrieve the values of a variable on the entities of another subdomain.
Ref< Parallel::IRequestList > createRequestListRef() override
Creates a request list for this manager.
void build() override
Constructs the instance.
void printStats() override
Prints statistics related to this parallelism manager.
void initialize() override
Initializes the parallelism manager.
void setReplication(IParallelReplication *v) override
Sets the Replication Information.
PointToPointMessageInfo buildMessage(Int32 dest, MP::eBlockingType is_blocking)
Constructs a message with destination dest.
void waitAllRequests(ArrayView< Request > requests) override
Blocks while waiting for the rvalues requests to complete.
Ref< IParallelMngUtilsFactory > _internalUtilsFactory() const override
Factory for utility functions.
IVariableSynchronizer * createSynchronizer(IItemFamily *family) override
Returns an interface for synchronizing variables on the group of the family.
MessageId probe(const PointToPointMessageInfo &message) override
Probes if messages are available.
ISerializeMessage * createSendSerializer(Int32 rank) override
Creates a non-blocking message to send serialized data to rank rank.
ITraceMng * traceMng() const override
Trace manager.
IParallelMng * sequentialParallelMng() override
Returns a sequential parallelism manager.
IParallelExchanger * createExchanger() override
Returns an interface for transferring messages between processors.
void freeRequests(ArrayView< Parallel::Request > requests) override
Frees the requests.
ISerializeMessage * createReceiveSerializer(Int32 rank) override
Creates a non-blocking message to receive serialized data from rank rank.
Ref< IParallelMng > createSubParallelMngRef(Int32ConstArrayView kept_ranks) override
Creates a new parallelism manager for a subset of ranks.
ITransferValuesParallelOperation * createTransferValuesOperation() override
Returns an operation to transfer values between subdomains.
MessageSourceInfo legacyProbe(const PointToPointMessageInfo &message) override
Probes if messages are available.
IParallelReplication * replication() const override
Replication information.
Redirects the message management of sub-domains according to the argument type.
IMessagePassingMng * messagePassingMng() const override
Associated Arccore message passing manager.
Base class of a factory for IParallelMng utility functions.
Brief information on parallel subdomain replication.
InstanceType * get() const
Associated instance or nullptr if none.
Reference to an instance.
Timer manager.
Definition TimerMng.h:40
1D data vector with value semantics (STL style).
Declarations of types and methods used by message exchange mechanisms.
@ WaitSome
Wait until all messages in the list are processed.
eBlockingType
Type indicating whether a message is blocking or not.
Concurrency implementation.
Real getRealTime()
Real time used in seconds.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Ref< TrueType > createRef(Args &&... args)
Creates an instance of type TrueType with arguments Args and returns a reference to it.
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
Array< Byte > ByteArray
Dynamic one-dimensional array of characters.
Definition UtilsTypes.h:121
ConstArrayView< Int32 > Int32ConstArrayView
C equivalent of a 1D array of 32-bit integers.
Definition UtilsTypes.h:482
double Real
Type representing a real number.
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Creates a reference on a pointer.
std::int32_t Int32
Signed integer type of 32 bits.