Changes in / [e5d9274:015925a]


Ignore:
Files:
1 added
25 deleted
133 edited

Legend:

Unmodified
Added
Removed
  • benchmark/plot.py

    re5d9274 r015925a  
    2222
    2323class Field:
    24         def __init__(self, unit, _min, _log, _name=None):
     24        def __init__(self, unit, _min, _log):
    2525                self.unit = unit
    2626                self.min  = _min
    2727                self.log  = _log
    28                 self.name = _name
    2928
    3029field_names = {
     
    3332        "Ops per procs"         : Field('Ops'   , 0, False),
    3433        "Ops per threads"       : Field('Ops'   , 0, False),
    35         "ns per ops/procs"      : Field(''    , 0, False, _name = "Latency (ns $/$ (Processor $\\times$ Operation))" ),
     34        "ns per ops/procs"      : Field('ns'    , 0, False),
    3635        "Number of threads"     : Field(''      , 1, False),
    3736        "Total Operations(ops)" : Field('Ops'   , 0, False),
    3837        "Ops/sec/procs"         : Field('Ops'   , 0, False),
    3938        "Total blocks"          : Field('Blocks', 0, False),
    40         "Ops per second"        : Field(''   , 0, False),
     39        "Ops per second"        : Field('Ops'   , 0, False),
    4140        "Cycle size (# thrds)"  : Field('thrd'  , 1, False),
    4241        "Duration (ms)"         : Field('ms'    , 0, False),
     
    5251}
    5352
    54 def plot(in_data, x, y, options):
     53def plot(in_data, x, y, out):
    5554        fig, ax = plt.subplots()
    5655        colors = itertools.cycle(['#0095e3','#006cb4','#69df00','#0aa000','#fb0300','#e30002','#fd8f00','#ff7f00','#8f00d6','#4b009a','#ffff00','#b13f00'])
     
    110109        print("Finishing Plots")
    111110
    112         plt.ylabel(field_names[y].name if field_names[y].name else y)
     111        plt.ylabel(y)
    113112        # plt.xticks(range(1, math.ceil(mx) + 1))
    114         plt.xlabel(field_names[x].name if field_names[x].name else x)
     113        plt.xlabel(x)
    115114        plt.grid(b = True)
    116115        ax.xaxis.set_major_formatter( EngFormatter(unit=field_names[x].unit) )
    117         if options.logx:
    118                 ax.set_xscale('log')
    119         elif field_names[x].log:
     116        if field_names[x].log:
    120117                ax.set_xscale('log')
    121118        else:
     
    123120
    124121        ax.yaxis.set_major_formatter( EngFormatter(unit=field_names[y].unit) )
    125         if options.logy:
    126                 ax.set_yscale('log')
    127         elif field_names[y].log:
     122        if field_names[y].log:
    128123                ax.set_yscale('log')
    129124        else:
    130                 plt.ylim(field_names[y].min, options.MaxY if options.MaxY else my*1.2)
     125                plt.ylim(field_names[y].min, my*1.2)
    131126
    132127        plt.legend(loc='upper left')
    133128
    134129        print("Results Ready")
    135         if options.out:
    136                 plt.savefig(options.out, bbox_inches='tight')
     130        if out:
     131                plt.savefig(out)
    137132        else:
    138133                plt.show()
     
    147142        parser.add_argument('-y', nargs='?', type=str, default="", help="Which field to use as the Y axis")
    148143        parser.add_argument('-x', nargs='?', type=str, default="", help="Which field to use as the X axis")
    149         parser.add_argument('--logx', action='store_true', help="if set, makes the x-axis logscale")
    150         parser.add_argument('--logy', action='store_true', help="if set, makes the y-axis logscale")
    151         parser.add_argument('--MaxY', nargs='?', type=int, help="maximum value of the y-axis")
    152144
    153145        options =  parser.parse_args()
     
    193185
    194186
    195         plot(data, wantx, wanty, options)
     187        plot(data, wantx, wanty, options.out)
  • doc/theses/mubeen_zulfiqar_MMath/allocator.tex

    re5d9274 r015925a  
    2929llheap's design was reviewed and changed multiple times throughout the thesis.
    3030Some of the rejected designs are discussed because they show the path to the final design (see discussion in \VRef{s:MultipleHeaps}).
    31 Note, a few simple tests for a design choice were compared with the current best allocators to determine the viability of a design.
     31Note, a few simples tests for a design choice were compared with the current best allocators to determine the viability of a design.
    3232
    3333
     
    3737These designs look at the allocation/free \newterm{fastpath}, \ie when an allocation can immediately return free storage or returned storage is not coalesced.
    3838\paragraph{T:1 model}
    39 \VRef[Figure]{f:T1SharedBuckets} shows one heap accessed by multiple kernel threads (KTs) using a bucket array, where smaller bucket sizes are shared among N KTs.
    40 This design leverages the fact that usually the allocation requests are less than 1024 bytes and there are only a few different request sizes.
     39\VRef[Figure]{f:T1SharedBuckets} shows one heap accessed by multiple kernel threads (KTs) using a bucket array, where smaller bucket sizes are N-shared across KTs.
     40This design leverages the fact that 95\% of allocation requests are less than 1024 bytes and there are only 3--5 different request sizes.
    4141When KTs $\le$ N, the common bucket sizes are uncontented;
    4242when KTs $>$ N, the free buckets are contented and latency increases significantly.
     
    6464
    6565\paragraph{T:H model}
    66 \VRef[Figure]{f:THSharedHeaps} shows a fixed number of heaps (N), each a local free pool, where the heaps are sharded (distributed) across the KTs.
     66\VRef[Figure]{f:THSharedHeaps} shows a fixed number of heaps (N), each a local free pool, where the heaps are sharded across the KTs.
    6767A KT can point directly to its assigned heap or indirectly through the corresponding heap bucket.
    68 When KT $\le$ N, the heaps might be uncontented;
     68When KT $\le$ N, the heaps are uncontented;
    6969when KTs $>$ N, the heaps are contented.
    7070In all cases, a KT must acquire/release a lock, contented or uncontented along the fast allocation path because a heap is shared.
    71 By increasing N, this approach reduces contention but increases storage (time versus space);
     71By adjusting N upwards, this approach reduces contention but increases storage (time versus space);
    7272however, picking N is workload specific.
    7373
     
    109109Need to prevent preemption during a dynamic memory operation because of the \newterm{serially-reusable problem}.
    110110\begin{quote}
    111 A sequence of code that is guaranteed to run to completion before being invoked to accept another input is called serially-reusable code.~\cite{SeriallyReusable}\label{p:SeriallyReusable}
     111A sequence of code that is guaranteed to run to completion before being invoked to accept another input is called serially-reusable code.~\cite{SeriallyReusable}
    112112\end{quote}
    113113If a KT is preempted during an allocation operation, the operating system can schedule another KT on the same CPU, which can begin an allocation operation before the previous operation associated with this CPU has completed, invalidating heap correctness.
     
    138138(See \VRef[Figure]{f:THSharedHeaps} but with a heap bucket per KT and no bucket or local-pool lock.)
    139139Hence, immediately after a KT starts, its heap is created and just before a KT terminates, its heap is (logically) deleted.
    140 Heaps are uncontended for a KTs memory operations as every KT has its own thread-local heap, modulo operations on the global pool and ownership.
     140Heaps are uncontended for a KTs memory operations to its heap (modulo operations on the global pool and ownership).
    141141
    142142Problems:
    143143\begin{itemize}
    144144\item
    145 Need to know when a KT starts/terminates to create/delete its heap.
     145Need to know when a KT is starts/terminates to create/delete its heap.
    146146
    147147\noindent
     
    161161\noindent
    162162In many concurrent applications, good performance is achieved with the number of KTs proportional to the number of CPUs.
    163 Since the number of CPUs is relatively small, and a heap is also relatively small, $\approx$10K bytes (not including any associated freed storage), the worst-case external fragmentation is still small compared to the RAM available on large servers with many CPUs.
     163Since the number of CPUs is relatively small, >~1024, and a heap relatively small, $\approx$10K bytes (not including any associated freed storage), the worst-case external fragmentation is still small compared to the RAM available on large servers with many CPUs.
    164164\item
    165165There is the same serially-reusable problem with UTs migrating across KTs.
     
    171171\noindent
    172172The conclusion from this design exercise is: any atomic fence, atomic instruction (lock free), or lock along the allocation fastpath produces significant slowdown.
    173 For the T:1 and T:H models, locking must exist along the allocation fastpath because the buckets or heaps might be shared by multiple threads, even when KTs $\le$ N.
     173For the T:1 and T:H models, locking must exist along the allocation fastpath because the buckets or heaps maybe shared by multiple threads, even when KTs $\le$ N.
    174174For the T:H=CPU and 1:1 models, locking is eliminated along the allocation fastpath.
    175175However, T:H=CPU has poor operating-system support to determine the CPU id (heap id) and prevent the serially-reusable problem for KTs.
    176176More operating system support is required to make this model viable, but there is still the serially-reusable problem with user-level threading.
    177 So the 1:1 model had no atomic actions along the fastpath and no special operating-system support requirements.
     177Leaving the 1:1 model with no atomic actions along the fastpath and no special operating-system support required.
    178178The 1:1 model still has the serially-reusable problem with user-level threading, which is addressed in \VRef{s:UserlevelThreadingSupport}, and the greatest potential for heap blowup for certain allocation patterns.
    179179
     
    212212Ideally latency is $O(1)$ with a small constant.
    213213
    214 To obtain $O(1)$ internal latency means no searching on the allocation fastpath and largely prohibits coalescing, which leads to external fragmentation.
     214To obtain $O(1)$ internal latency means no searching on the allocation fastpath, largely prohibits coalescing, which leads to external fragmentation.
    215215The mitigating factor is that most programs have well behaved allocation patterns, where the majority of allocation operations can be $O(1)$, and heap blowup does not occur without coalescing (although the allocation footprint may be slightly larger).
    216216
     
    257257llheap starts by creating an array of $N$ global heaps from storage obtained using @mmap@, where $N$ is the number of computer cores, that persists for program duration.
    258258There is a global bump-pointer to the next free heap in the array.
    259 When this array is exhausted, another array of heaps is allocated.
    260 There is a global top pointer for a intrusive linked-list to chain free heaps from terminated threads.
    261 When statistics are turned on, there is a global top pointer for a intrusive linked-list to chain \emph{all} the heaps, which is traversed to accumulate statistics counters across heaps using @malloc_stats@.
     259When this array is exhausted, another array is allocated.
     260There is a global top pointer for a heap intrusive link to chain free heaps from terminated threads.
     261When statistics are turned on, there is a global top pointer for a heap intrusive link to chain \emph{all} the heaps, which is traversed to accumulate statistics counters across heaps using @malloc_stats@.
    262262
    263263When a KT starts, a heap is allocated from the current array for exclusive use by the KT.
    264 When a KT terminates, its heap is chained onto the heap free-list for reuse by a new KT, which prevents unbounded growth of number of heaps.
    265 The free heaps are stored on stack so hot storage is reused first.
    266 Preserving all heaps, created during the program lifetime, solves the storage lifetime problem when ownership is used.
     264When a KT terminates, its heap is chained onto the heap free-list for reuse by a new KT, which prevents unbounded growth of heaps.
     265The free heaps is a stack so hot storage is reused first.
     266Preserving all heaps created during the program lifetime, solves the storage lifetime problem, when ownership is used.
    267267This approach wastes storage if a large number of KTs are created/terminated at program start and then the program continues sequentially.
    268268llheap can be configured with object ownership, where an object is freed to the heap from which it is allocated, or object no-ownership, where an object is freed to the KT's current heap.
    269269
    270270Each heap uses segregated free-buckets that have free objects distributed across 91 different sizes from 16 to 4M.
    271 All objects in a bucket are of the same size.
    272271The number of buckets used is determined dynamically depending on the crossover point from @sbrk@ to @mmap@ allocation using @mallopt( M_MMAP_THRESHOLD )@, \ie small objects managed by the program and large objects managed by the operating system.
    273272Each free bucket of a specific size has the following two lists:
     
    287286Quantizing is performed using a binary search over the ordered bucket array.
    288287An optional optimization is fast lookup $O(1)$ for sizes < 64K from a 64K array of type @char@, where each element has an index to the corresponding bucket.
    289 The @char@ type restricts the number of bucket sizes to 256.
     288(Type @char@ restricts the number of bucket sizes to 256.)
    290289For $S$ > 64K, a binary search is used.
    291290Then, the allocation storage is obtained from the following locations (in order), with increasing latency.
     
    382381Then the corresponding bucket of the owner thread is computed for the deallocating thread, and the allocation is pushed onto the deallocating thread's bucket.
    383382
    384 Finally, the llheap design funnels \label{p:FunnelRoutine} all allocation/deallocation operations through the @malloc@ and @free@ routines, which are the only routines to directly access and manage the internal data structures of the heap.
     383Finally, the llheap design funnels \label{p:FunnelRoutine} all allocation/deallocation operations through routines @malloc@/@free@, which are the only routines to directly access and manage the internal data structures of the heap.
    385384Other allocation operations, \eg @calloc@, @memalign@, and @realloc@, are composed of calls to @malloc@ and possibly @free@, and may manipulate header information after storage is allocated.
    386385This design simplifies heap-management code during development and maintenance.
     
    389388\subsection{Alignment}
    390389
    391 Most dynamic memory allocations have a minimum storage alignment for the contained object(s).
     390All dynamic memory allocations must have a minimum storage alignment for the contained object(s).
    392391Often the minimum memory alignment, M, is the bus width (32 or 64-bit) or the largest register (double, long double) or largest atomic instruction (DCAS) or vector data (MMMX).
    393392In general, the minimum storage alignment is 8/16-byte boundary on 32/64-bit computers.
    394393For consistency, the object header is normally aligned at this same boundary.
    395 Larger alignments must be a power of 2, such as page alignment (4/8K).
     394Larger alignments must be a power of 2, such page alignment (4/8K).
    396395Any alignment request, N, $\le$ the minimum alignment is handled as a normal allocation with minimal alignment.
    397396
     
    401400\end{center}
    402401The storage between @E@ and @H@ is chained onto the appropriate free list for future allocations.
    403 The same approach is used for sufficiently large free blocks, where @E@ is the start of the free block, and any unused storage before @H@ or after the allocated object becomes free storage.
     402This approach is also valid within any sufficiently large free block, where @E@ is the start of the free block, and any unused storage before @H@ or after the allocated object becomes free storage.
    404403In this approach, the aligned address @A@ is the same as the allocated storage address @P@, \ie @P@ $=$ @A@ for all allocation routines, which simplifies deallocation.
    405404However, if there are a large number of aligned requests, this approach leads to memory fragmentation from the small free areas around the aligned object.
     
    408407Finally, this approach is incompatible with allocator designs that funnel allocation requests through @malloc@ as it directly manipulates management information within the allocator to optimize the space/time of a request.
    409408
    410 Instead, llheap alignment is accomplished by making a \emph{pessimistic} allocation request for sufficient storage to ensure that \emph{both} the alignment and size request are satisfied, \eg:
     409Instead, llheap alignment is accomplished by making a \emph{pessimistically} allocation request for sufficient storage to ensure that \emph{both} the alignment and size request are satisfied, \eg:
    411410\begin{center}
    412411\input{Alignment2}
     
    425424\input{Alignment2Impl}
    426425\end{center}
    427 Since @malloc@ has a minimum alignment of @M@, @P@ $\neq$ @A@ only holds for alignments greater than @M@.
     426Since @malloc@ has a minimum alignment of @M@, @P@ $\neq$ @A@ only holds for alignments of @M@ or greater.
    428427When @P@ $\neq$ @A@, the minimum distance between @P@ and @A@ is @M@ bytes, due to the pessimistic storage-allocation.
    429428Therefore, there is always room for an @M@-byte fake header before @A@.
     
    440439\label{s:ReallocStickyProperties}
    441440
    442 The allocation routine @realloc@ provides a memory-management pattern for shrinking/enlarging an existing allocation, while maintaining some or all of the object data, rather than performing the following steps manually.
     441Allocation routine @realloc@ provides a memory-management pattern for shrinking/enlarging an existing allocation, while maintaining some or all of the object data, rather than performing the following steps manually.
    443442\begin{flushleft}
    444443\begin{tabular}{ll}
     
    461460The realloc pattern leverages available storage at the end of an allocation due to bucket sizes, possibly eliminating a new allocation and copying.
    462461This pattern is not used enough to reduce storage management costs.
    463 In fact, if @oaddr@ is @nullptr@, @realloc@ does a @malloc@, so even the initial @malloc@ can be a @realloc@ for consistency in the allocation pattern.
     462In fact, if @oaddr@ is @nullptr@, @realloc@ does a @malloc@, so even the initial @malloc@ can be a @realloc@ for consistency in the pattern.
    464463
    465464The hidden problem for this pattern is the effect of zero fill and alignment with respect to reallocation.
    466465Are these properties transient or persistent (``sticky'')?
    467 For example, when memory is initially allocated by @calloc@ or @memalign@ with zero fill or alignment properties, respectively, what happens when those allocations are given to @realloc@ to change size?
    468 That is, if @realloc@ logically extends storage into unused bucket space or allocates new storage to satisfy a size change, are initial allocation properties preserved?
     466For example, when memory is initially allocated by @calloc@ or @memalign@ with zero fill or alignment properties, respectively, what happens when those allocations are given to @realloc@ to change size.
     467That is, if @realloc@ logically extends storage into unused bucket space or allocates new storage to satisfy a size change, are initial allocation properties preserve?
    469468Currently, allocation properties are not preserved, so subsequent use of @realloc@ storage may cause inefficient execution or errors due to lack of zero fill or alignment.
    470469This silent problem is unintuitive to programmers and difficult to locate because it is transient.
     
    476475
    477476To preserve allocation properties requires storing additional information with an allocation,
    478 The best available option is the header, where \VRef[Figure]{f:llheapNormalHeader} shows the llheap storage layout.
     477The only available location is the header, where \VRef[Figure]{f:llheapNormalHeader} shows the llheap storage layout.
    479478The header has two data field sized appropriately for 32/64-bit alignment requirements.
    480479The first field is a union of three values:
     
    488487\end{description}
    489488The second field remembers the request size versus the allocation (bucket) size, \eg request 42 bytes which is rounded up to 64 bytes.
    490 Since programmers think in request sizes rather than allocation sizes, the request size allows better generation of statistics or errors and also helps in memory management.
     489Since programmers think in request sizes rather than allocation sizes, the request size allows better generation of statistics or errors.
    491490
    492491\begin{figure}
     
    497496\end{figure}
    498497
    499 The low-order 3-bits of the first field are \emph{unused} for any stored values as these values are 16-byte aligned by default, whereas the second field may use all of its bits.
     498The low-order 3-bits of the first field are \emph{unused} for any stored values, whereas the second field may use all of its bits.
    500499The 3 unused bits are used to represent mapped allocation, zero filled, and alignment, respectively.
    501500Note, the alignment bit is not used in the normal header and the zero-filled/mapped bits are not used in the fake header.
     
    503502If no bits are on, it implies a basic allocation, which is handled quickly;
    504503otherwise, the bits are analysed and appropriate actions are taken for the complex cases.
    505 Since most allocations are basic, they will take significantly less time as the memory operations will be done along the allocation and free fastpath.
     504Since most allocations are basic, this implementation results in a significant performance gain along the allocation and free fastpath.
    506505
    507506
     
    515514To locate all statistic counters, heaps are linked together in statistics mode, and this list is locked and traversed to sum all counters across heaps.
    516515Note, the list is locked to prevent errors traversing an active list;
    517 the statistics counters are not locked and can flicker during accumulation.
     516the statistics counters are not locked and can flicker during accumulation, which is not an issue with atomic read/write.
    518517\VRef[Figure]{f:StatiticsOutput} shows an example of statistics output, which covers all allocation operations and information about deallocating storage not owned by a thread.
    519518No other memory allocator studied provides as comprehensive statistical information.
    520 Finally, these statistics were invaluable during the development of this thesis for debugging and verifying correctness and should be equally valuable to application developers.
     519Finally, these statistics were invaluable during the development of this thesis for debugging and verifying correctness, and hence, should be equally valuable to application developers.
    521520
    522521\begin{figure}
     
    548547Nevertheless, the checks detect many allocation problems.
    549548There is an unfortunate problem in detecting unfreed storage because some library routines assume their allocations have life-time duration, and hence, do not free their storage.
    550 For example, @printf@ allocates a 1024-byte buffer on the first call and never deletes this buffer.
     549For example, @printf@ allocates a 1024 buffer on first call and never deletes this buffer.
    551550To prevent a false positive for unfreed storage, it is possible to specify an amount of storage that is never freed (see @malloc_unfreed@ \VPageref{p:malloc_unfreed}), and it is subtracted from the total allocate/free difference.
    552551Determining the amount of never-freed storage is annoying, but once done, any warnings of unfreed storage are application related.
    553552
    554 Tests indicate only a 30\% performance decrease when statistics \emph{and} debugging are enabled, and the latency cost for accumulating statistic is mitigated by limited calls, often only one at the end of the program.
     553Tests indicate only a 30\% performance increase when statistics \emph{and} debugging are enabled, and the latency cost for accumulating statistic is mitigated by limited calls, often only one at the end of the program.
    555554
    556555
     
    558557\label{s:UserlevelThreadingSupport}
    559558
    560 The serially-reusable problem (see \VPageref{p:SeriallyReusable}) occurs for kernel threads in the ``T:H model, H = number of CPUs'' model and for user threads in the ``1:1'' model, where llheap uses the ``1:1'' model.
    561 The solution is to prevent interrupts that can result in a CPU or KT change during operations that are logically critical sections such as starting a memory operation on one KT and completing it on another.
     559The serially-reusable problem (see \VRef{s:AllocationFastpath}) occurs for kernel threads in the ``T:H model, H = number of CPUs'' model and for user threads in the ``1:1'' model, where llheap uses the ``1:1'' model.
     560The solution is to prevent interrupts that can result in CPU or KT change during operations that are logically critical sections.
    562561Locking these critical sections negates any attempt for a quick fastpath and results in high contention.
    563562For user-level threading, the serially-reusable problem appears with time slicing for preemptable scheduling, as the signal handler context switches to another user-level thread.
    564 Without time slicing, a user thread performing a long computation can prevent the execution of (starve) other threads.
    565 To prevent starvation for a memory-allocation-intensive thread, \ie the time slice always triggers in an allocation critical-section for one thread so the thread never gets time sliced, a thread-local \newterm{rollforward} flag is set in the signal handler when it aborts a time slice.
     563Without time slicing, a user thread performing a long computation can prevent execution (starve) other threads.
     564To prevent starvation for an allocation-active thread, \ie the time slice always triggers in an allocation critical-section for one thread, a thread-local \newterm{rollforward} flag is set in the signal handler when it aborts a time slice.
    566565The rollforward flag is tested at the end of each allocation funnel routine (see \VPageref{p:FunnelRoutine}), and if set, it is reset and a volunteer yield (context switch) is performed to allow other threads to execute.
    567566
    568 llheap uses two techniques to detect when execution is in an allocation operation or routine called from allocation operation, to abort any time slice during this period.
    569 On the slowpath when executing expensive operations, like @sbrk@ or @mmap@, interrupts are disabled/enabled by setting kernel-thread-local flags so the signal handler aborts immediately.
    570 On the fastpath, disabling/enabling interrupts is too expensive as accessing kernel-thread-local storage can be expensive and not user-thread-safe.
     567llheap uses two techniques to detect when execution is in a allocation operation or routine called from allocation operation, to abort any time slice during this period.
     568On the slowpath when executing expensive operations, like @sbrk@ or @mmap@, interrupts are disabled/enabled by setting thread-local flags so the signal handler aborts immediately.
     569On the fastpath, disabling/enabling interrupts is too expensive as accessing thread-local storage can be expensive and not thread-safe.
    571570For example, the ARM processor stores the thread-local pointer in a coprocessor register that cannot perform atomic base-displacement addressing.
    572 Hence, there is a window between loading the kernel-thread-local pointer from the coprocessor register into a normal register and adding the displacement when a time slice can move a thread.
    573 
    574 The fast technique (with lower run time cost) is to define a special code section and places all non-interruptible routines in this section.
     571Hence, there is a window between loading the thread-local pointer from the coprocessor register into a normal register and adding the displacement when a time slice can move a thread.
     572
     573The fast technique defines a special code section and places all non-interruptible routines in this section.
    575574The linker places all code in this section into a contiguous block of memory, but the order of routines within the block is unspecified.
    576575Then, the signal handler compares the program counter at the point of interrupt with the the start and end address of the non-interruptible section, and aborts if executing within this section and sets the rollforward flag.
     
    578577Hence, for correctness, this approach requires inspection of generated assembler code for routines placed in the non-interruptible section.
    579578This issue is mitigated by the llheap funnel design so only funnel routines and a few statistics routines are placed in the non-interruptible section and their assembler code examined.
    580 These techniques are used in both the \uC and \CFA versions of llheap as both of these systems have user-level threading.
     579These techniques are used in both the \uC and \CFA versions of llheap, where both of these systems have user-level threading.
    581580
    582581
     
    588587Programs can be statically or dynamically linked.
    589588\item
    590 The order in which the linker schedules startup code is poorly supported so it cannot be controlled entirely.
     589The order the linker schedules startup code is poorly supported.
    591590\item
    592591Knowing a KT's start and end independently from the KT code is difficult.
     
    601600Hence, some part of the @sbrk@ area may be used by the default allocator and statistics about allocation operations cannot be correct.
    602601Furthermore, dynamic linking goes through trampolines, so there is an additional cost along the allocator fastpath for all allocation operations.
    603 Testing showed up to a 5\% performance decrease with dynamic linking as compared to static linking, even when using @tls_model("initial-exec")@ so the dynamic loader can obtain tighter binding.
     602Testing showed up to a 5\% performance increase for dynamic linking over static linking, even when using @tls_model("initial-exec")@ so the dynamic loader can obtain tighter binding.
    604603
    605604All allocator libraries need to perform startup code to initialize data structures, such as the heap array for llheap.
    606 The problem is getting initialization done before the first allocator call.
     605The problem is getting initialized done before the first allocator call.
    607606However, there does not seem to be mechanism to tell either the static or dynamic loader to first perform initialization code before any calls to a loaded library.
    608 Also, initialization code of other libraries and the run-time environment may call memory allocation routines such as \lstinline{malloc}.
    609 This compounds the situation as there is no mechanism to tell either the static or dynamic loader to first perform the initialization code of the memory allocator before any other initialization that may involve a dynamic memory allocation call.
    610607As a result, calls to allocation routines occur without initialization.
    611608To deal with this problem, it is necessary to put a conditional initialization check along the allocation fastpath to trigger initialization (singleton pattern).
     
    644641Therefore, the constructor is useless for knowing when a KT starts because the KT must reference it, and the allocator does not control the application KT.
    645642Fortunately, the singleton pattern needed for initializing the program KT also triggers KT allocator initialization, which can then reference @pgm_thread@ to call @threadManager@'s constructor, otherwise its destructor is not called.
    646 Now when a KT terminates, @~ThreadManager@ is called to chain it onto the global-heap free-stack, where @pgm_thread@ is set to true only for the program KT.
     643Now when a KT terminates, @~ThreadManager@ is called to chained it onto the global-heap free-stack, where @pgm_thread@ is set to true only for the program KT.
    647644The conditional destructor call prevents closing down the program heap, which must remain available because epilogue code may free more storage.
    648645
     
    663660bool traceHeapOff();                    $\C{// stop printing allocation/free calls}$
    664661\end{lstlisting}
    665 This kind of API is necessary to allow concurrent runtime systems to interact with different memory allocators in a consistent way.
     662This kind of API is necessary to allow concurrent runtime systems to interact with difference memory allocators in a consistent way.
    666663
    667664%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     
    715712Most allocators use @nullptr@ to indicate an allocation failure, specifically out of memory;
    716713hence the need to return an alternate value for a zero-sized allocation.
    717 A different approach allowed by @C API@ is to abort a program when out of memory and return @nullptr@ for a zero-sized allocation.
     714A different approach allowed by the C API is to abort a program when out of memory and return @nullptr@ for a zero-sized allocation.
    718715In theory, notifying the programmer of memory failure allows recovery;
    719716in practice, it is almost impossible to gracefully recover when out of memory.
     
    739736\paragraph{\lstinline{void * aalloc( size_t dim, size_t elemSize )}}
    740737extends @calloc@ for allocating a dynamic array of objects without calculating the total size of array explicitly but \emph{without} zero-filling the memory.
    741 @aalloc@ is significantly faster than @calloc@, which is the only alternative given by the standard memory-allocation routines.
     738@aalloc@ is significantly faster than @calloc@, which is the only alternative.
    742739
    743740\noindent\textbf{Usage}
     
    828825\begin{itemize}
    829826\item
    830 @fd@: file descriptor.
     827@fd@: files description.
    831828\end{itemize}
    832829It returns the previous file descriptor.
     
    835832\label{p:malloc_expansion}
    836833set the amount (bytes) to extend the heap when there is insufficient free storage to service an allocation request.
    837 It returns the heap extension size used throughout a program when requesting more memory from the system using @sbrk@ system-call, \ie called once at heap initialization.
     834It returns the heap extension size used throughout a program, \ie called once at heap initialization.
    838835
    839836\paragraph{\lstinline{size_t malloc_mmap_start()}}
     
    918915\begin{itemize}
    919916\item
    920 naming: \CFA regular and @ttype@ polymorphism (@ttype@ polymorphism in \CFA is similar to \CC variadic templates) is used to encapsulate a wide range of allocation functionality into a single routine name, so programmers do not have to remember multiple routine names for different kinds of dynamic allocations.
    921 \item
    922 named arguments: individual allocation properties are specified using postfix function call, so the programmers do not have to remember parameter positions in allocation calls.
    923 \item
    924 object size: like the \CFA's C-interface, programmers do not have to specify object size or cast allocation results.
     917naming: \CFA regular and @ttype@ polymorphism is used to encapsulate a wide range of allocation functionality into a single routine name, so programmers do not have to remember multiple routine names for different kinds of dynamic allocations.
     918\item
     919named arguments: individual allocation properties are specified using postfix function call, so programmers do have to remember parameter positions in allocation calls.
     920\item
     921object size: like the \CFA C-style interface, programmers do not have to specify object size or cast allocation results.
    925922\end{itemize}
    926923Note, postfix function call is an alternative call syntax, using backtick @`@, where the argument appears before the function name, \eg
     
    931928duration dur = 3@`@h + 42@`@m + 17@`@s;
    932929\end{cfa}
     930@ttype@ polymorphism is similar to \CC variadic templates.
    933931
    934932\paragraph{\lstinline{T * alloc( ... )} or \lstinline{T * alloc( size_t dim, ... )}}
    935 is overloaded with a variable number of specific allocation operations, or an integer dimension parameter followed by a variable number of specific allocation operations.
    936 These allocation operations can be passed as named arguments when calling the \lstinline{alloc} routine.
     933is overloaded with a variable number of specific allocation routines, or an integer dimension parameter followed by a variable number specific allocation routines.
    937934A call without parameters returns a dynamically allocated object of type @T@ (@malloc@).
    938935A call with only the dimension (dim) parameter returns a dynamically allocated array of objects of type @T@ (@aalloc@).
     
    9839805 5 5 -555819298 -555819298  // two undefined values
    984981\end{lstlisting}
    985 Examples 1 to 3 fill an object with a value or characters.
    986 Examples 4 to 7 fill an array of objects with values, another array, or part of an array.
     982Examples 1 to 3, fill an object with a value or characters.
     983Examples 4 to 7, fill an array of objects with values, another array, or part of an array.
    987984
    988985\subparagraph{\lstinline{S_resize(T) ?`resize( void * oaddr )}}
     
    10181015\subparagraph{\lstinline{S_realloc(T) ?`realloc( T * a ))}}
    10191016used to resize, realign, and fill, where the old object data is copied to the new object.
    1020 The old object type must be the same as the new object type, since the value is used.
     1017The old object type must be the same as the new object type, since the values used.
    10211018Note, for @fill@, only the extra space after copying the data from the old object is filled with the given parameter.
    10221019For example:
     
    10321029\end{lstlisting}
    10331030Examples 2 to 3 change the alignment for the initial storage of @i@.
    1034 The @13`fill@ in example 3 does nothing because no extra space is added.
     1031The @13`fill@ for example 3 does nothing because no extra space is added.
    10351032
    10361033\begin{cfa}[numbers=left]
     
    10471044\end{lstlisting}
    10481045Examples 2 to 4 change the array size, alignment and fill for the initial storage of @ia@.
    1049 The @13`fill@ in example 3 does nothing because no extra space is added.
     1046The @13`fill@ for example 3 does nothing because no extra space is added.
    10501047
    10511048These \CFA allocation features are used extensively in the development of the \CFA runtime.
  • doc/theses/mubeen_zulfiqar_MMath/background.tex

    re5d9274 r015925a  
    3636The management data starts with fixed-sized information in the static-data memory that references components in the dynamic-allocation memory.
    3737The \newterm{storage data} is composed of allocated and freed objects, and \newterm{reserved memory}.
    38 Allocated objects (light grey) are variable sized, and are allocated and maintained by the program;
    39 \ie only the memory allocator knows the location of allocated storage, not the program.
     38Allocated objects (light grey) are variable sized, and allocated and maintained by the program;
     39\ie only the program knows the location of allocated storage, not the memory allocator.
    4040\begin{figure}[h]
    4141\centering
     
    4949if there are multiple reserved blocks, they are also chained together, usually internally.
    5050
    51 In some allocator designs, allocated and freed objects have additional management data embedded within them.
     51Allocated and freed objects typically have additional management data embedded within them.
    5252\VRef[Figure]{f:AllocatedObject} shows an allocated object with a header, trailer, and alignment padding and spacing around the object.
    5353The header contains information about the object, \eg size, type, etc.
     
    104104\VRef[Figure]{f:MemoryFragmentation} shows an example of how a small block of memory fragments as objects are allocated and deallocated over time.
    105105Blocks of free memory become smaller and non-contiguous making them less useful in serving allocation requests.
    106 Memory is highly fragmented when most free blocks are unusable because of their sizes.
     106Memory is highly fragmented when the sizes of most free blocks are unusable.
    107107For example, \VRef[Figure]{f:Contiguous} and \VRef[Figure]{f:HighlyFragmented} have the same quantity of external fragmentation, but \VRef[Figure]{f:HighlyFragmented} is highly fragmented.
    108108If there is a request to allocate a large object, \VRef[Figure]{f:Contiguous} is more likely to be able to satisfy it with existing free memory, while \VRef[Figure]{f:HighlyFragmented} likely has to request more memory from the operating system.
     
    137137The fewer bin-sizes, the fewer lists need to be searched and maintained;
    138138however, the bin sizes are less likely to closely fit the requested object size, leading to more internal fragmentation.
    139 The more bin sizes, the longer the search and the less likely free objects are to be reused, leading to more external fragmentation and potentially heap blowup.
     139The more bin-sizes, the longer the search and the less likely free objects are to be reused, leading to more external fragmentation and potentially heap blowup.
    140140A variation of the binning algorithm allows objects to be allocated to the requested size, but when an object is freed, it is placed on the free list of the next smallest or equal bin-size.
    141141For example, with bin sizes of 8 and 16 bytes, a request for 12 bytes allocates only 12 bytes, but when the object is freed, it is placed on the 8-byte bin-list.
     
    157157The principle of locality recognizes that programs tend to reference a small set of data, called a working set, for a certain period of time, where a working set is composed of temporal and spatial accesses~\cite{Denning05}.
    158158Temporal clustering implies a group of objects are accessed repeatedly within a short time period, while spatial clustering implies a group of objects physically close together (nearby addresses) are accessed repeatedly within a short time period.
    159 Temporal locality commonly occurs during an iterative computation with a fixed set of disjoint variables, while spatial locality commonly occurs when traversing an array.
     159Temporal locality commonly occurs during an iterative computation with a fix set of disjoint variables, while spatial locality commonly occurs when traversing an array.
    160160
    161161Hardware takes advantage of temporal and spatial locality through multiple levels of caching, \ie memory hierarchy.
     
    328328For example, multiple heaps are managed in a pool, starting with a single or a fixed number of heaps that increase\-/decrease depending on contention\-/space issues.
    329329At creation, a thread is associated with a heap from the pool.
    330 In some implementations of this model, when the thread attempts an allocation and its associated heap is locked (contention), it scans for an unlocked heap in the pool.
     330When the thread attempts an allocation and its associated heap is locked (contention), it scans for an unlocked heap in the pool.
    331331If an unlocked heap is found, the thread changes its association and uses that heap.
    332332If all heaps are locked, the thread may create a new heap, use it, and then place the new heap into the pool;
     
    347347The management information in the static zone must be able to locate all heaps in the dynamic zone.
    348348The management information for the heaps must reside in the dynamic-allocation zone if there are a variable number.
    349 Each heap in the dynamic zone is composed of a list of free objects and a pointer to its reserved memory.
     349Each heap in the dynamic zone is composed of a list of a free objects and a pointer to its reserved memory.
    350350An alternative implementation is for all heaps to share one reserved memory, which requires a separate lock for the reserved storage to ensure mutual exclusion when acquiring new memory.
    351351Because multiple threads can allocate/free/reallocate adjacent storage, all forms of false sharing may occur.
     
    361361Multiple heaps increase external fragmentation as the ratio of heaps to threads increases, which can lead to heap blowup.
    362362The external fragmentation experienced by a program with a single heap is now multiplied by the number of heaps, since each heap manages its own free storage and allocates its own reserved memory.
    363 Additionally, objects freed by one heap cannot be reused by other threads without increasing the cost of the memory operations, except indirectly by returning free memory to the operating system, which can be expensive.
    364 Depending on how the operating system provides dynamic storage to an application, returning storage may be difficult or impossible, \eg the contiguous @sbrk@ area in Unix.
     363Additionally, objects freed by one heap cannot be reused by other threads, except indirectly by returning free memory to the operating system, which can be expensive.
     364(Depending on how the operating system provides dynamic storage to an application, returning storage may be difficult or impossible, \eg the contiguous @sbrk@ area in Unix.)
    365365In the worst case, a program in which objects are allocated from one heap but deallocated to another heap means these freed objects are never reused.
    366366
     
    384384In contrast, the T:H model spreads each thread's objects over a larger area in different heaps.
    385385Thread heaps can also eliminate allocator-induced active false-sharing, if memory is acquired so it does not overlap at crucial boundaries with memory for another thread's heap.
    386 For example, assume page boundaries coincide with cache line boundaries, if a thread heap always acquires pages of memory then no two threads share a page or cache line unless pointers are passed among them.
     386For example, assume page boundaries coincide with cache line boundaries, then if a thread heap always acquires pages of memory, no two threads share a page or cache line unless pointers are passed among them.
    387387Hence, allocator-induced active false-sharing in \VRef[Figure]{f:AllocatorInducedActiveFalseSharing} cannot occur because the memory for thread heaps never overlaps.
    388388
    389 When a thread terminates, there are two options for handling its thread heap.
    390 First is to free all objects in the thread heap to the global heap and destroy the thread heap.
     389When a thread terminates, there are two options for handling its heap.
     390First is to free all objects in the heap to the global heap and destroy the thread heap.
    391391Second is to place the thread heap on a list of available heaps and reuse it for a new thread in the future.
    392392Destroying the thread heap immediately may reduce external fragmentation sooner, since all free objects are freed to the global heap and may be reused by other threads.
    393 Alternatively, reusing thread heaps may improve performance if the inheriting thread makes similar allocation requests as the thread that previously held the thread heap because any unfreed storage is immediately accessible.
     393Alternatively, reusing thread heaps may improve performance if the inheriting thread makes similar allocation requests as the thread that previously held the thread heap because any unfreed storage is immediately accessible..
    394394
    395395
     
    417417When the user thread continues on the new kernel thread, it may have pointers into the previous kernel-thread's heap and hold locks associated with it.
    418418To get the same kernel-thread safety, time slicing must be disabled/\-enabled around these operations, so the user thread cannot jump to another kernel thread.
    419 However, eagerly disabling/enabling time-slicing on the allocation/deallocation fast path is expensive, because preemption does not happen that frequently.
     419However, eagerly disabling/enabling time-slicing on the allocation/deallocation fast path is expensive, because preemption is rare (10--100 milliseconds).
    420420Instead, techniques exist to lazily detect this case in the interrupt handler, abort the preemption, and return to the operation so it can complete atomically.
    421421Occasionally ignoring a preemption should be benign, but a persistent lack of preemption can result in both short and long term starvation.
     422
     423
     424\begin{figure}
     425\centering
     426\subfigure[Ownership]{
     427        \input{MultipleHeapsOwnership}
     428} % subfigure
     429\hspace{0.25in}
     430\subfigure[No Ownership]{
     431        \input{MultipleHeapsNoOwnership}
     432} % subfigure
     433\caption{Heap Ownership}
     434\label{f:HeapsOwnership}
     435\end{figure}
    422436
    423437
     
    433447For the T:1/T:H models with or without ownership or the 1:1 model with ownership, a thread may free objects to different heaps, which makes each heap publicly accessible to all threads, called a \newterm{public heap}.
    434448
    435 \begin{figure}
    436 \centering
    437 \subfigure[Ownership]{
    438         \input{MultipleHeapsOwnership}
    439 } % subfigure
    440 \hspace{0.25in}
    441 \subfigure[No Ownership]{
    442         \input{MultipleHeapsNoOwnership}
    443 } % subfigure
    444 \caption{Heap Ownership}
    445 \label{f:HeapsOwnership}
    446 \end{figure}
    447 
    448449\VRef[Figure]{f:MultipleHeapStorageOwnership} shows the effect of ownership on storage layout.
    449 (For simplicity, assume the heaps all use the same size of reserves storage.)
     450(For simplicity assume the heaps all use the same size of reserves storage.)
    450451In contrast to \VRef[Figure]{f:MultipleHeapStorage}, each reserved area used by a heap only contains free storage for that particular heap because threads must return free objects back to the owner heap.
    451452Again, because multiple threads can allocate/free/reallocate adjacent storage in the same heap, all forms of false sharing may occur.
     
    472473While the returning thread can batch objects, batching across multiple heaps is complex and there is no obvious time when to push back to the owner heap.
    473474It is better for returning threads to immediately return to the receiving thread's batch list as the receiving thread has better knowledge when to incorporate the batch list into its free pool.
    474 Batching leverages the fact that most allocation patterns use the contention-free fast-path, so locking on the batch list is rare for both the returning and receiving threads.
    475 
    476 It is possible for heaps to steal objects rather than return them and then reallocate these objects again when storage runs out on a heap.
     475Batching leverages the fact that most allocation patterns use the contention-free fast-path so locking on the batch list is rare for both the returning and receiving threads.
     476
     477It is possible for heaps to steal objects rather than return them and reallocating these objects when storage runs out on a heap.
    477478However, stealing can result in passive false-sharing.
    478479For example, in \VRef[Figure]{f:AllocatorInducedPassiveFalseSharing}, Object$_2$ may be deallocated to Thread$_2$'s heap initially.
     
    484485
    485486Bracketing every allocation with headers/trailers can result in significant internal fragmentation, as shown in \VRef[Figure]{f:ObjectHeaders}.
    486 Especially if the headers contain redundant management information, then storing that information is a waste of storage, \eg object size may be the same for many objects because programs only allocate a small set of object sizes.
     487Especially if the headers contain redundant management information, \eg object size may be the same for many objects because programs only allocate a small set of object sizes.
    487488As well, it can result in poor cache usage, since only a portion of the cache line is holding useful information from the program's perspective.
    488489Spatial locality can also be negatively affected leading to poor cache locality~\cite{Feng05}:
     
    659660With local free-lists in containers, as in \VRef[Figure]{f:LocalFreeListWithinContainers}, the container is simply removed from one heap's free list and placed on the new heap's free list.
    660661Thus, when using local free-lists, the operation of moving containers is reduced from $O(N)$ to $O(1)$.
    661 However, there is the additional storage cost in the header, which increases the header size, and therefore internal fragmentation.
     662The cost is adding information to a header, which increases the header size, and therefore internal fragmentation.
    662663
    663664\begin{figure}
     
    688689The main goal of the hybrid approach is to eliminate locking on thread-local allocation/deallocation, while providing ownership to prevent heap blowup.
    689690In the hybrid approach, a thread first allocates from its private heap and second from its public heap if no free memory exists in the private heap.
    690 Similarly, a thread first deallocates an object to its private heap, and second to the public heap.
     691Similarly, a thread first deallocates an object its private heap, and second to the public heap.
    691692Both private and public heaps can allocate/deallocate to/from the global heap if there is no free memory or excess free memory, although an implementation may choose to funnel all interaction with the global heap through one of the heaps.
    692693Note, deallocation from the private to the public (dashed line) is unlikely because there is no obvious advantages unless the public heap provides the only interface to the global heap.
  • doc/theses/mubeen_zulfiqar_MMath/benchmarks.tex

    re5d9274 r015925a  
    1212\item[Benchmarks]
    1313are a suite of application programs (SPEC CPU/WEB) that are exercised in a common way (inputs) to find differences among underlying software implementations associated with an application (compiler, memory allocator, web server, \etc).
    14 The applications are supposed to represent common execution patterns that need to perform well with respect to an underlying software implementation.
     14The applications are suppose to represent common execution patterns that need to perform well with respect to an underlying software implementation.
    1515Benchmarks are often criticized for having overlapping patterns, insufficient patterns, or extraneous code that masks patterns.
    1616\item[Micro-Benchmarks]
     
    2626
    2727This thesis designs and examines a new set of micro-benchmarks for memory allocators that test a variety of allocation patterns, each with multiple tuning parameters.
    28 The aim of the micro-benchmark suite is to create a set of programs that can evaluate a memory allocator based on the key performance metrics such as speed, memory overhead, and cache performance.
     28The aim of the micro-benchmark suite is to create a set of programs that can evaluate a memory allocator based on the key performance matrices such as speed, memory overhead, and cache performance.
    2929% These programs can be taken as a standard to benchmark an allocator's basic goals.
    3030These programs give details of an allocator's memory overhead and speed under certain allocation patterns.
    31 The allocation patterns are configurable (adjustment knobs) to observe an allocator's performance across a spectrum allocation patterns, which is seldom possible with benchmark programs.
     31The allocation patterns are configurable (adjustment knobs) to observe an allocator's performance across a spectrum of events for a desired allocation pattern, which is seldom possible with benchmark programs.
    3232Each micro-benchmark program has multiple control knobs specified by command-line arguments.
    3333
    34 The new micro-benchmark suite measures performance by allocating dynamic objects and measuring specific metrics.
     34The new micro-benchmark suite measures performance by allocating dynamic objects and measuring specific matrices.
    3535An allocator's speed is benchmarked in different ways, as are issues like false sharing.
    3636
     
    4040Modern memory allocators, such as llheap, must handle multi-threaded programs at the KT and UT level.
    4141The following multi-threaded micro-benchmarks are presented to give a sense of prior work~\cite{Berger00} at the KT level.
    42 None of the prior work addresses multi-threading at the UT level.
     42None of the prior work address multi-threading at the UT level.
    4343
    4444
     
    4747This benchmark stresses the ability of the allocator to handle different threads allocating and deallocating independently.
    4848There is no interaction among threads, \ie no object sharing.
    49 Each thread repeatedly allocates 100,000 \emph{8-byte} objects then deallocates them in the order they were allocated.
    50 The execution time of the benchmark evaluates its efficiency.
     49Each thread repeatedly allocate 100,000 \emph{8-byte} objects then deallocates them in the order they were allocated.
     50Runtime of the benchmark evaluates its efficiency.
    5151
    5252
     
    6363Before the thread terminates, it passes its array of 10,000 objects to a new child thread to continue the process.
    6464The number of thread generations varies depending on the thread speed.
    65 It calculates memory operations per second as an indicator of the memory allocator's performance.
     65It calculates memory operations per second as an indicator of memory allocator's performance.
    6666
    6767
     
    7575\label{s:ChurnBenchmark}
    7676
    77 The churn benchmark measures the runtime speed of an allocator in a multi-threaded scenario, where each thread extensively allocates and frees dynamic memory.
     77The churn benchmark measures the runtime speed of an allocator in a multi-threaded scenerio, where each thread extensively allocates and frees dynamic memory.
    7878Only @malloc@ and @free@ are used to eliminate any extra cost, such as @memcpy@ in @calloc@ or @realloc@.
    79 Churn simulates a memory intensive program and can be tuned to create different scenarios.
     79Churn simulates a memory intensive program that can be tuned to create different scenarios.
    8080
    8181\VRef[Figure]{fig:ChurnBenchFig} shows the pseudo code for the churn micro-benchmark.
     
    133133When threads share a cache line, frequent reads/writes to their cache-line object causes cache misses, which cause escalating delays as cache distance increases.
    134134
    135 Cache thrash tries to create a scenario that leads to false sharing, if the underlying memory allocator is allocating dynamic memory to multiple threads on the same cache lines.
     135Cache thrash tries to create a scenerio that leads to false sharing, if the underlying memory allocator is allocating dynamic memory to multiple threads on the same cache lines.
    136136Ideally, a memory allocator should distance the dynamic memory region of one thread from another.
    137137Having multiple threads allocating small objects simultaneously can cause a memory allocator to allocate objects on the same cache line, if its not distancing the memory among different threads.
     
    141141Each worker thread allocates an object and intensively reads/writes it for M times to possible invalidate cache lines that may interfere with other threads sharing the same cache line.
    142142Each thread repeats this for N times.
    143 The main thread measures the total time taken for all worker threads to complete.
    144 Worker threads sharing cache lines with each other are expected to take longer.
     143The main thread measures the total time taken to for all worker threads to complete.
     144Worker threads sharing cache lines with each other will take longer.
    145145
    146146\begin{figure}
     
    156156        signal workers to free
    157157        ...
     158        print addresses from each $thread$
    158159Worker Thread$\(_1\)$
    159         warm up memory in chunks of 16 bytes
    160         ...
    161         For N
    162                 malloc an object
    163                 read/write the object M times
    164                 free the object
    165         ...
     160        allocate, write, read, free
     161        warmup memory in chunkc of 16 bytes
     162        ...
     163        malloc N objects
     164        ...
     165        free objects
     166        return object address to Main Thread
    166167Worker Thread$\(_2\)$
    167168        // same as Worker Thread$\(_1\)$
     
    190191
    191192The cache-scratch micro-benchmark measures allocator-induced passive false-sharing as illustrated in \VRef{s:AllocatorInducedPassiveFalseSharing}.
    192 As with cache thrash, if memory is allocated for multiple threads on the same cache line, this can significantly slow down program performance.
     193As for cache thrash, if memory is allocated for multiple threads on the same cache line, this can significantly slow down program performance.
    193194In this scenario, the false sharing is being caused by the memory allocator although it is started by the program sharing an object.
    194195
     
    201202Cache scratch tries to create a scenario that leads to false sharing and should make the memory allocator preserve the program-induced false sharing, if it does not return a freed object to its owner thread and, instead, re-uses it instantly.
    202203An allocator using object ownership, as described in section \VRef{s:Ownership}, is less susceptible to allocator-induced passive false-sharing.
    203 If the object is returned to the thread that owns it, then the new object that the thread gets is less likely to be on the same cache line.
     204If the object is returned to the thread who owns it, then the thread that gets a new object is less likely to be on the same cache line.
    204205
    205206\VRef[Figure]{fig:benchScratchFig} shows the pseudo code for the cache-scratch micro-benchmark.
     
    223224        signal workers to free
    224225        ...
     226        print addresses from each $thread$
    225227Worker Thread$\(_1\)$
    226         warmup memory in chunks of 16 bytes
    227         ...
    228         free the object passed by the Main Thread
    229         For N
     228        allocate, write, read, free
     229        warmup memory in chunkc of 16 bytes
     230        ...
     231        for ( N )
     232                free an object passed by Main Thread
    230233                malloc new object
    231                 read/write the object M times
    232                 free the object
    233         ...
     234        ...
     235        free objects
     236        return new object addresses to Main Thread
    234237Worker Thread$\(_2\)$
    235238        // same as Worker Thread$\(_1\)$
     
    245248
    246249Similar to benchmark cache thrash in section \VRef{sec:benchThrashSec}, different cache access scenarios can be created using the following command-line arguments.
    247 \begin{description}[topsep=0pt,itemsep=0pt,parsep=0pt]
     250\begin{description}[itemsep=0pt,parsep=0pt]
    248251\item[threads:]
    249252number of threads (K).
     
    259262\subsection{Speed Micro-Benchmark}
    260263\label{s:SpeedMicroBenchmark}
    261 \vspace*{-4pt}
    262264
    263265The speed benchmark measures the runtime speed of individual and sequences of memory allocation routines:
    264 \begin{enumerate}[topsep=-5pt,itemsep=0pt,parsep=0pt]
     266\begin{enumerate}[itemsep=0pt,parsep=0pt]
    265267\item malloc
    266268\item realloc
     
    330332\VRef[Figure]{fig:MemoryBenchFig} shows the pseudo code for the memory micro-benchmark.
    331333It creates a producer-consumer scenario with K producer threads and each producer has M consumer threads.
    332 A producer has a separate buffer for each consumer and allocates N objects of random sizes following a configurable distribution for each consumer.
     334A producer has a separate buffer for each consumer and allocates N objects of random sizes following a settable distribution for each consumer.
    333335A consumer frees these objects.
    334336After every memory operation, program memory usage is recorded throughout the runtime.
  • doc/theses/mubeen_zulfiqar_MMath/conclusion.tex

    re5d9274 r015925a  
    1717% ====================
    1818
    19 The goal of this thesis was to build a low-latency (or high bandwidth) memory allocator for both KT and UT multi-threading systems that is competitive with the best current memory allocators while extending the feature set of existing and new allocator routines.
     19The goal of this thesis was to build a low-latency memory allocator for both KT and UT multi-threads systems, which is competitive with the best current memory allocators, while extending the feature set of existing and new allocator routines.
    2020The new llheap memory-allocator achieves all of these goals, while maintaining and managing sticky allocation information without a performance loss.
    2121Hence, it becomes possible to use @realloc@ frequently as a safe operation, rather than just occasionally.
    2222Furthermore, the ability to query sticky properties and information allows programmers to write safer programs, as it is possible to dynamically match allocation styles from unknown library routines that return allocations.
    2323
    24 Extending the C allocation API with @resize@, advanced @realloc@, @aalloc@, @amemalign@, and @cmemalign@ means programmers do not have to do these useful allocation operations themselves.
     24Extending the C allocation API with @resize@, advanced @realloc@, @aalloc@, @amemalign@, and @cmemalign@ means programmers do not make mistakes writing theses useful allocation operations.
    2525The ability to use \CFA's advanced type-system (and possibly \CC's too) to have one allocation routine with completely orthogonal sticky properties shows how far the allocation API can be pushed, which increases safety and greatly simplifies programmer's use of dynamic allocation.
    2626
    2727Providing comprehensive statistics for all allocation operations is invaluable in understanding and debugging a program's dynamic behaviour.
    28 No other memory allocator provides such comprehensive statistics gathering.
     28No other memory allocator provides comprehensive statistics gathering.
    2929This capability was used extensively during the development of llheap to verify its behaviour.
    3030As well, providing a debugging mode where allocations are checked, along with internal pre/post conditions and invariants, is extremely useful, especially for students.
    31 While not as powerful as the @valgrind@ interpreter, a large number of allocation mistakes are detected.
     31While not as powerful as the @valgrind@ interpreter, a large number of allocations mistakes are detected.
    3232Finally, contention-free statistics gathering and debugging have a low enough cost to be used in production code.
    3333
     
    3636
    3737Starting a micro-benchmark test-suite for comparing allocators, rather than relying on a suite of arbitrary programs, has been an interesting challenge.
    38 The current micro-benchmarks allow some understanding of allocator implementation properties without actually looking at the implementation.
     38The current micro-benchmarks allow some understand of allocator implementation properties without actually looking at the implementation.
    3939For example, the memory micro-benchmark quickly identified how several of the allocators work at the global level.
    4040It was not possible to show how the micro-benchmarks adjustment knobs were used to tune to an interesting test point.
     
    4545
    4646A careful walk-though of the allocator fastpath should yield additional optimizations for a slight performance gain.
    47 In particular, analysing the implementation of rpmalloc, which is often the fastest allocator,
     47In particular, looking at the implementation of rpmalloc, which is often the fastest allocator,
    4848
    49 The micro-benchmark project requires more testing and analysis.
    50 Additional allocation patterns are needed to extract meaningful information about allocators, and within allocation patterns, what are the most useful tuning knobs.
     49The micro-benchmarks project requires more testing and analysis.
     50Additional allocations patterns are needed to extract meaningful information about allocators, and within allocation patterns, what are the best tuning knobs.
    5151Also, identifying ways to visualize the results of the micro-benchmarks is a work in progress.
    5252
    53 After llheap is made available on GitHub, interacting with its users to locate problems and improvements will make llbench a more robust memory allocator.
    54 As well, feedback from the \uC and \CFA projects, which have adopted llheap for their memory allocator, will provide additional information.
     53After llheap is made available on gitHub, interacting with its users to locate problems and improvements, will make llbench a more robust memory allocator.
     54As well, feedback from the \uC and \CFA projects, which have adopted llheap for their memory allocator, will provide additional feedback.
  • doc/theses/mubeen_zulfiqar_MMath/figures/Header.fig

    re5d9274 r015925a  
    20202 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
    2121         3300 1500 3300 2400
     222 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 3
     23        1 1 1.00 45.00 90.00
     24         4050 2625 3750 2625 3750 2400
     252 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 3
     26        1 1 1.00 45.00 90.00
     27         4050 2850 3450 2850 3450 2400
    22282 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    2329         4200 1800 6600 1800 6600 2100 4200 2100 4200 1800
    24 2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 3
    25         1 1 1.00 45.00 90.00
    26          4200 2775 3750 2775 3750 1725
    27 2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 3
    28         1 1 1.00 45.00 90.00
    29          4200 2550 4050 2550 4050 1725
    30 2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 3
    31         1 1 1.00 45.00 90.00
    32          4200 3000 3450 3000 3450 2025
    33304 0 0 50 -1 0 12 0.0000 2 180 1185 1875 1725 bucket pointer\001
    34314 0 0 50 -1 0 12 0.0000 2 180 1005 1875 2025 mapped size\001
    35324 0 0 50 -1 0 12 0.0000 2 135 1215 1875 2325 next free block\001
    36334 2 0 50 -1 0 12 0.0000 2 135 480 1725 2025 union\001
     344 1 0 50 -1 0 12 0.0000 2 135 270 3775 2325 0/1\001
     354 1 0 50 -1 0 12 0.0000 2 135 270 3475 2325 0/1\001
    37364 1 0 50 -1 0 12 0.0000 2 180 945 5400 2025 request size\001
    38374 1 0 50 -1 0 12 0.0000 2 180 765 5400 1425 4/8-bytes\001
    39384 1 0 50 -1 0 12 0.0000 2 180 765 3000 1425 4/8-bytes\001
    40 4 1 0 50 -1 0 12 0.0000 2 135 270 3475 2025 0/1\001
    41 4 1 0 50 -1 0 12 0.0000 2 135 270 3775 1725 0/1\001
    42 4 1 0 50 -1 0 12 0.0000 2 135 270 4075 1725 0/1\001
    43 4 0 0 50 -1 0 12 0.0000 2 180 1515 4275 3075 mapped allocation\001
    44 4 0 0 50 -1 0 12 0.0000 2 135 825 4275 2850 zero filled\001
    45 4 0 0 50 -1 0 12 0.0000 2 180 1920 4275 2625 alignment (fake header)\001
     394 0 0 50 -1 0 12 0.0000 2 135 825 4125 2700 zero filled\001
     404 0 0 50 -1 0 12 0.0000 2 180 1515 4125 2925 mapped allocation\001
  • doc/theses/mubeen_zulfiqar_MMath/figures/MultipleHeapsNoOwnership.fig

    re5d9274 r015925a  
    1 #FIG 3.2  Produced by xfig version 3.2.7b
     1#FIG 3.2  Produced by xfig version 3.2.5
    22Landscape
    33Center
    44Inches
    5 Letter
     5Letter 
    66100.00
    77Single
     
    11112 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    1212         1200 2100 1500 2100 1500 1800 1200 1800 1200 2100
    13 4 1 0 50 -1 0 11 0.0000 2 165 495 1350 2025 H$_1$\001
     134 1 0 50 -1 0 11 0.0000 2 195 495 1350 2025 H$_1$\001
    1414-6
    15156 1950 1800 2550 2100
    16162 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    1717         2100 2100 2400 2100 2400 1800 2100 1800 2100 2100
    18 4 1 0 50 -1 0 11 0.0000 2 165 495 2250 2025 H$_2$\001
     184 1 0 50 -1 0 11 0.0000 2 195 495 2250 2025 H$_2$\001
    1919-6
    20201 3 0 1 0 7 50 -1 -1 0.000 0 -0.0000 1350 1350 150 150 1350 1350 1500 1350
    21211 3 0 1 0 7 50 -1 -1 0.000 0 -0.0000 2250 1350 150 150 2250 1350 2400 1350
    22222 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    23         1 1 1.00 45.00 90.00
    24         1 1 1.00 45.00 90.00
     23        0 0 1.00 45.00 90.00
     24        0 0 1.00 45.00 90.00
    2525         1275 1800 1275 1500
    26 2 1 0 1 0 0 50 -1 -1 0.000 0 0 -1 1 0 2
    27         1 1 1.00 45.00 90.00
     262 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
     27        0 0 1.00 45.00 90.00
    2828         1425 1500 1425 1800
    29292 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 1 2
    30         1 1 1.00 45.00 90.00
     30        0 0 1.00 45.00 90.00
    3131         1425 1500 2175 1800
    32322 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 1 2
    33         1 1 1.00 45.00 90.00
     33        0 0 1.00 45.00 90.00
    3434         2175 1500 1425 1800
    35352 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    36         1 1 1.00 45.00 90.00
     36        0 0 1.00 45.00 90.00
    3737         2175 1500 2175 1800
    38382 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    39         1 1 1.00 45.00 90.00
    40         1 1 1.00 45.00 90.00
     39        0 0 1.00 45.00 90.00
     40        0 0 1.00 45.00 90.00
    4141         2325 1800 2325 1500
    42 4 1 0 50 -1 0 11 0.0000 2 165 465 1350 1425 T$_1$\001
    43 4 1 0 50 -1 0 11 0.0000 2 165 465 2250 1425 T$_2$\001
     424 1 0 50 -1 0 11 0.0000 2 195 465 1350 1425 T$_1$\001
     434 1 0 50 -1 0 11 0.0000 2 195 465 2250 1425 T$_2$\001
  • doc/theses/mubeen_zulfiqar_MMath/figures/MultipleHeapsOwnership.fig

    re5d9274 r015925a  
    1 #FIG 3.2  Produced by xfig version 3.2.7b
     1#FIG 3.2  Produced by xfig version 3.2.5
    22Landscape
    33Center
    44Inches
    5 Letter
     5Letter 
    66100.00
    77Single
     
    11112 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    1212         1200 2100 1500 2100 1500 1800 1200 1800 1200 2100
    13 4 1 0 50 -1 0 11 0.0000 2 165 495 1350 2025 H$_1$\001
     134 1 0 50 -1 0 11 0.0000 2 195 495 1350 2025 H$_1$\001
    1414-6
    15156 1950 1800 2550 2100
    16162 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    1717         2100 2100 2400 2100 2400 1800 2100 1800 2100 2100
    18 4 1 0 50 -1 0 11 0.0000 2 165 495 2250 2025 H$_2$\001
     184 1 0 50 -1 0 11 0.0000 2 195 495 2250 2025 H$_2$\001
    1919-6
    20201 3 0 1 0 7 50 -1 -1 0.000 0 -0.0000 1350 1350 150 150 1350 1350 1500 1350
    21211 3 0 1 0 7 50 -1 -1 0.000 0 -0.0000 2250 1350 150 150 2250 1350 2400 1350
    22222 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    23         1 1 1.00 45.00 90.00
    24         1 1 1.00 45.00 90.00
     23        0 0 1.00 45.00 90.00
     24        0 0 1.00 45.00 90.00
    2525         2175 1500 1425 1800
    26262 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    27         1 1 1.00 45.00 90.00
    28         1 1 1.00 45.00 90.00
     27        0 0 1.00 45.00 90.00
     28        0 0 1.00 45.00 90.00
     29         1425 1500 2175 1800
     302 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
     31        0 0 1.00 45.00 90.00
     32        0 0 1.00 45.00 90.00
    2933         1275 1800 1275 1500
    30342 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    31         1 1 1.00 45.00 90.00
    32         1 1 1.00 45.00 90.00
     35        0 0 1.00 45.00 90.00
     36        0 0 1.00 45.00 90.00
    3337         2325 1800 2325 1500
    34 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    35         1 1 1.00 45.00 90.00
    36         1 1 1.00 45.00 90.00
    37          1425 1500 2175 1800
    38 4 1 0 50 -1 0 11 0.0000 2 165 465 2250 1425 T$_2$\001
    39 4 1 0 50 -1 0 11 0.0000 2 165 465 1350 1425 T$_1$\001
     384 1 0 50 -1 0 11 0.0000 2 195 465 2250 1425 T$_2$\001
     394 1 0 50 -1 0 11 0.0000 2 195 465 1350 1425 T$_1$\001
  • doc/theses/mubeen_zulfiqar_MMath/figures/PerThreadHeap.fig

    re5d9274 r015925a  
    1 #FIG 3.2  Produced by xfig version 3.2.7b
     1#FIG 3.2  Produced by xfig version 3.2.5
    22Landscape
    33Center
    44Inches
    5 Letter
     5Letter 
    66100.00
    77Single
     
    11112 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    1212         2700 1800 3000 1800 3000 2100 2700 2100 2700 1800
    13 4 1 0 50 -1 0 11 0.0000 2 120 135 2850 2025 G\001
     134 1 0 50 -1 0 11 0.0000 2 135 135 2850 2025 G\001
    1414-6
    15151 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 1350 1350 150 150 1350 1350 1500 1350
     
    17171 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 2250 1350 150 150 2250 1350 2400 1350
    18182 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    19         1 1 1.00 45.00 90.00
    20         1 1 1.00 45.00 90.00
     19        0 0 1.00 45.00 90.00
     20        0 0 1.00 45.00 90.00
    2121         1350 1500 1350 1800
    22222 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
     
    2727         2100 1800 2400 1800 2400 2100 2100 2100 2100 1800
    28282 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    29         1 1 1.00 45.00 90.00
    30         1 1 1.00 45.00 90.00
     29        0 0 1.00 45.00 90.00
     30        0 0 1.00 45.00 90.00
    3131         1800 1500 1800 1800
    32322 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    33         1 1 1.00 45.00 90.00
    34         1 1 1.00 45.00 90.00
     33        0 0 1.00 45.00 90.00
     34        0 0 1.00 45.00 90.00
    3535         2250 1500 2250 1800
    36 4 1 0 50 -1 0 11 0.0000 2 180 1260 2550 2025 $\\Leftrightarrow$\001
    37 4 1 0 50 -1 0 11 0.0000 2 180 1260 3150 2025 $\\Leftrightarrow$\001
    38 4 0 0 50 -1 0 11 0.0000 2 120 240 3300 2025 OS\001
    39 4 1 0 50 -1 0 11 0.0000 2 165 495 1350 2025 H$_1$\001
    40 4 1 0 50 -1 0 11 0.0000 2 165 465 1350 1425 T$_1$\001
    41 4 1 0 50 -1 0 11 0.0000 2 165 495 1800 2025 H$_2$\001
    42 4 1 0 50 -1 0 11 0.0000 2 165 465 1800 1425 T$_2$\001
    43 4 1 0 50 -1 0 11 0.0000 2 165 495 2250 2025 H$_3$\001
    44 4 1 0 50 -1 0 11 0.0000 2 165 465 2250 1425 T$_3$\001
     364 1 0 50 -1 0 11 0.0000 2 195 1320 2550 2025 $\\Leftrightarrow$\001
     374 1 0 50 -1 0 11 0.0000 2 195 1320 3150 2025 $\\Leftrightarrow$\001
     384 0 0 50 -1 0 11 0.0000 2 135 240 3300 2025 OS\001
     394 1 0 50 -1 0 11 0.0000 2 195 495 1350 2025 H$_1$\001
     404 1 0 50 -1 0 11 0.0000 2 195 465 1350 1425 T$_1$\001
     414 1 0 50 -1 0 11 0.0000 2 195 495 1800 2025 H$_2$\001
     424 1 0 50 -1 0 11 0.0000 2 195 465 1800 1425 T$_2$\001
     434 1 0 50 -1 0 11 0.0000 2 195 495 2250 2025 H$_3$\001
     444 1 0 50 -1 0 11 0.0000 2 195 465 2250 1425 T$_3$\001
  • doc/theses/mubeen_zulfiqar_MMath/figures/SharedHeaps.fig

    re5d9274 r015925a  
    1 #FIG 3.2  Produced by xfig version 3.2.7b
     1#FIG 3.2  Produced by xfig version 3.2.5
    22Landscape
    33Center
    44Inches
    5 Letter
     5Letter 
    66100.00
    77Single
     
    10106 1500 1200 2100 1500
    11111 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 1800 1350 150 150 1800 1350 1950 1350
    12 4 1 0 50 -1 0 11 0.0000 2 165 465 1800 1425 T$_2$\001
     124 1 0 50 -1 0 11 0.0000 2 195 465 1800 1425 T$_2$\001
    1313-6
    14146 1050 1200 1650 1500
    15151 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 1350 1350 150 150 1350 1350 1500 1350
    16 4 1 0 50 -1 0 11 0.0000 2 165 465 1350 1425 T$_1$\001
     164 1 0 50 -1 0 11 0.0000 2 195 465 1350 1425 T$_1$\001
    1717-6
    18186 1950 1200 2550 1500
    19191 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 2250 1350 150 150 2250 1350 2400 1350
    20 4 1 0 50 -1 0 11 0.0000 2 165 465 2250 1425 T$_3$\001
     204 1 0 50 -1 0 11 0.0000 2 195 465 2250 1425 T$_3$\001
    2121-6
    22226 1275 1800 1875 2100
    23232 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    2424         1425 1800 1725 1800 1725 2100 1425 2100 1425 1800
    25 4 1 0 50 -1 0 11 0.0000 2 165 495 1575 2025 H$_1$\001
     254 1 0 50 -1 0 11 0.0000 2 195 495 1575 2025 H$_1$\001
    2626-6
    27276 1725 1800 2325 2100
    28282 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    2929         1875 1800 2175 1800 2175 2100 1875 2100 1875 1800
    30 4 1 0 50 -1 0 11 0.0000 2 165 495 2025 2025 H$_2$\001
     304 1 0 50 -1 0 11 0.0000 2 195 495 2025 2025 H$_2$\001
    3131-6
    32326 2475 1800 2775 2100
    33332 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    3434         2475 1800 2775 1800 2775 2100 2475 2100 2475 1800
    35 4 1 0 50 -1 0 11 0.0000 2 120 135 2625 2025 G\001
     354 1 0 50 -1 0 11 0.0000 2 135 135 2625 2025 G\001
    3636-6
    37372 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    38         1 1 1.00 45.00 90.00
    39         1 1 1.00 45.00 90.00
     38        0 0 1.00 45.00 90.00
     39        0 0 1.00 45.00 90.00
    4040         1275 1500 1500 1800
    41412 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    42         1 1 1.00 45.00 90.00
    43         1 1 1.00 45.00 90.00
     42        0 0 1.00 45.00 90.00
     43        0 0 1.00 45.00 90.00
    4444         1425 1500 1950 1800
    45452 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    46         1 1 1.00 45.00 90.00
    47         1 1 1.00 45.00 90.00
     46        0 0 1.00 45.00 90.00
     47        0 0 1.00 45.00 90.00
    4848         1725 1500 1650 1800
    49492 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    50         1 1 1.00 45.00 90.00
    51         1 1 1.00 45.00 90.00
     50        0 0 1.00 45.00 90.00
     51        0 0 1.00 45.00 90.00
    5252         1875 1500 2025 1800
    53532 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    54         1 1 1.00 45.00 90.00
    55         1 1 1.00 45.00 90.00
     54        0 0 1.00 45.00 90.00
     55        0 0 1.00 45.00 90.00
    5656         2250 1500 2100 1800
    57 4 0 0 50 -1 0 11 0.0000 2 120 240 3075 2025 OS\001
    58 4 1 0 50 -1 0 11 0.0000 2 180 1260 2325 2025 $\\Leftrightarrow$\001
    59 4 1 0 50 -1 0 11 0.0000 2 180 1260 2925 2025 $\\Leftrightarrow$\001
     574 0 0 50 -1 0 11 0.0000 2 135 240 3075 2025 OS\001
     584 1 0 50 -1 0 11 0.0000 2 195 1320 2325 2025 $\\Leftrightarrow$\001
     594 1 0 50 -1 0 11 0.0000 2 195 1320 2925 2025 $\\Leftrightarrow$\001
  • doc/theses/mubeen_zulfiqar_MMath/figures/SingleHeap.fig

    re5d9274 r015925a  
    1 #FIG 3.2  Produced by xfig version 3.2.7b
     1#FIG 3.2  Produced by xfig version 3.2.5
    22Landscape
    33Center
    44Inches
    5 Letter
     5Letter 
    66100.00
    77Single
     
    10106 1500 1200 2100 1500
    11111 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 1800 1350 150 150 1800 1350 1950 1350
    12 4 1 0 50 -1 0 11 0.0000 2 165 465 1800 1425 T$_2$\001
     124 1 0 50 -1 0 11 0.0000 2 195 465 1800 1425 T$_2$\001
    1313-6
    14146 1050 1200 1650 1500
    15151 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 1350 1350 150 150 1350 1350 1500 1350
    16 4 1 0 50 -1 0 11 0.0000 2 165 465 1350 1425 T$_1$\001
     164 1 0 50 -1 0 11 0.0000 2 195 465 1350 1425 T$_1$\001
    1717-6
    18186 1950 1200 2550 1500
    19191 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 2250 1350 150 150 2250 1350 2400 1350
    20 4 1 0 50 -1 0 11 0.0000 2 165 465 2250 1425 T$_3$\001
     204 1 0 50 -1 0 11 0.0000 2 195 465 2250 1425 T$_3$\001
    2121-6
    22222 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    23         1 1 1.00 45.00 90.00
    24         1 1 1.00 45.00 90.00
     23        0 0 1.00 45.00 90.00
     24        0 0 1.00 45.00 90.00
    2525         1350 1500 1725 1800
    26262 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    27         1 1 1.00 45.00 90.00
    28         1 1 1.00 45.00 90.00
     27        0 0 1.00 45.00 90.00
     28        0 0 1.00 45.00 90.00
    2929         2250 1500 1875 1800
    30302 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    3131         1650 1800 1950 1800 1950 2100 1650 2100 1650 1800
    32322 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    33         1 1 1.00 45.00 90.00
    34         1 1 1.00 45.00 90.00
     33        0 0 1.00 45.00 90.00
     34        0 0 1.00 45.00 90.00
    3535         1800 1500 1800 1800
    36 4 1 0 50 -1 0 11 0.0000 2 165 495 1800 2025 H$_1$\001
    37 4 1 0 50 -1 0 11 0.0000 2 180 1260 2100 2025 $\\Leftrightarrow$\001
    38 4 0 0 50 -1 0 11 0.0000 2 120 240 2250 2025 OS\001
     364 1 0 50 -1 0 11 0.0000 2 195 495 1800 2025 H$_1$\001
     374 1 0 50 -1 0 11 0.0000 2 195 1320 2100 2025 $\\Leftrightarrow$\001
     384 0 0 50 -1 0 11 0.0000 2 135 240 2250 2025 OS\001
  • doc/theses/mubeen_zulfiqar_MMath/figures/UserKernelHeaps.fig

    re5d9274 r015925a  
    4545-6
    46462 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    47         1 1 1.00 45.00 90.00
    48         1 1 1.00 45.00 90.00
     47        0 0 1.00 45.00 90.00
     48        0 0 1.00 45.00 90.00
    4949         2025 2100 2025 2400
    50502 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    51         1 1 1.00 45.00 90.00
    52         1 1 1.00 45.00 90.00
     51        0 0 1.00 45.00 90.00
     52        0 0 1.00 45.00 90.00
    5353         2475 2100 2475 2400
    54542 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
    55         1 1 1.00 45.00 90.00
    56         1 1 1.00 45.00 90.00
     55        0 0 1.00 45.00 90.00
     56        0 0 1.00 45.00 90.00
    5757         2925 2100 2925 2400
    58584 1 0 50 -1 0 11 0.0000 2 135 2235 2475 1725 scheduled across kernel threads\001
  • doc/theses/mubeen_zulfiqar_MMath/intro.tex

    re5d9274 r015925a  
    5353When this allocator proves inadequate, programmers often write specialize allocators for specific needs.
    5454C and \CC allow easy replacement of the default memory allocator with an alternative specialized or general-purpose memory-allocator.
    55 Jikes RVM MMTk~\cite{MMTk} provides a similar generalization for the Java virtual machine.
     55(Jikes RVM MMTk~\cite{MMTk} provides a similar generalization for the Java virtual machine.)
    5656However, high-performance memory-allocators for kernel and user multi-threaded programs are still being designed and improved.
    5757For this reason, several alternative general-purpose allocators have been written for C/\CC with the goal of scaling in a multi-threaded program~\cite{Berger00,mtmalloc,streamflow,tcmalloc}.
     
    6565\begin{enumerate}[leftmargin=*]
    6666\item
    67 Implementation of a new stand-alone concurrent low-latency memory-allocator ($\approx$1,200 lines of code) for C/\CC programs using kernel threads (1:1 threading), and specialized versions of the allocator for the programming languages \uC and \CFA using user-level threads running over multiple kernel threads (M:N threading).
     67Implementation of a new stand-lone concurrent low-latency memory-allocator ($\approx$1,200 lines of code) for C/\CC programs using kernel threads (1:1 threading), and specialized versions of the allocator for the programming languages \uC and \CFA using user-level threads running over multiple kernel threads (M:N threading).
     68
     69\item
     70Adopt @nullptr@ return for a zero-sized allocation, rather than an actual memory address, which can be passed to @free@.
    6871
    6972\item
     
    101104
    102105\item
    103 Provide additional heap wrapper functions in \CFA creating a more usable set of allocation operations and properties.
     106Provide additional heap wrapper functions in \CFA creating an orthogonal set of allocation operations and properties.
    104107
    105108\item
     
    108111\item
    109112@malloc_alignment( addr )@ returns the alignment of the allocation pointed-to by @addr@.
    110 If the allocation is not aligned or @addr@ is the @NULL@, the minimal alignment is returned.
     113If the allocation is not aligned or @addr@ is the @nulladdr@, the minimal alignment is returned.
    111114\item
    112115@malloc_zero_fill( addr )@ returns a boolean result indicating if the memory pointed-to by @addr@ is allocated with zero fill, e.g., by @calloc@/@cmemalign@.
     
    116119@malloc_usable_size( addr )@ returns the usable (total) size of the memory pointed-to by @addr@, i.e., the bin size containing the allocation, where @malloc_size( addr )@ $\le$ @malloc_usable_size( addr )@.
    117120\end{itemize}
     121
     122\item
     123Provide mostly contention-free allocation and free operations via a heap-per-kernel-thread implementation.
    118124
    119125\item
     
    130136
    131137\item
    132 Provide extensive runtime checks to validate allocation operations and identify the amount of unfreed storage at program termination.
     138Provide extensive runtime checks to valid allocation operations and identify the amount of unfreed storage at program termination.
    133139
    134140\item
  • doc/theses/mubeen_zulfiqar_MMath/performance.tex

    re5d9274 r015925a  
    33
    44This chapter uses the micro-benchmarks from \VRef[Chapter]{s:Benchmarks} to test a number of current memory allocators, including llheap.
    5 The goal is to see if llheap is competitive with the currently popular memory allocators.
     5The goal is to see if llheap is competitive with the current best memory allocators.
    66
    77
     
    1111\begin{itemize}
    1212\item
     13\textbf{Nasus} AMD EPYC 7662, 64-core socket $\times$ 2, 2.0 GHz, GCC version 9.3.0
     14\item
    1315\textbf{Algol} Huawei ARM TaiShan 2280 V2 Kunpeng 920, 24-core socket $\times$ 4, 2.6 GHz, GCC version 9.4.0
    14 \item
    15 \textbf{Nasus} AMD EPYC 7662, 64-core socket $\times$ 2, 2.0 GHz, GCC version 9.3.0
    1616\end{itemize}
    1717
     
    3131
    3232\paragraph{glibc (\textsf{glc})}
    33 \cite{glibc} is the default glibc thread-safe allocator.
     33\cite{glibc} is the default gcc thread-safe allocator.
    3434\\
    3535\textbf{Version:} Ubuntu GLIBC 2.31-0ubuntu9.7 2.31\\
     
    4646
    4747\paragraph{hoard (\textsf{hrd})}
    48 \cite{hoard} is a thread-safe allocator that is multi-threaded and uses a heap layer framework. It has per-thread heaps that have thread-local free-lists, and a global shared heap.
     48\cite{hoard} is a thread-safe allocator that is multi-threaded and using a heap layer framework. It has per-thread heaps that have thread-local free-lists, and a global shared heap.
    4949\\
    5050\textbf{Version:} 3.13\\
     
    7878
    7979\paragraph{tbb malloc (\textsf{tbb})}
    80 \cite{tbbmalloc} is a thread-safe allocator that is multi-threaded and uses a private heap for each thread.
     80\cite{tbbmalloc} is a thread-safe allocator that is multi-threaded and uses private heap for each thread.
    8181Each private-heap has multiple bins of different sizes. Each bin contains free regions of the same size.
    8282\\
     
    9090\section{Experiments}
    9191
    92 Each micro-benchmark is configured and run with each of the allocators,
    93 The less time an allocator takes to complete a benchmark the better so lower in the graphs is better, except for the Memory micro-benchmark graphs.
     92The each micro-benchmark is configured and run with each of the allocators,
     93The less time an allocator takes to complete a benchmark the better, so lower in the graphs is better.
    9494All graphs use log scale on the Y-axis, except for the Memory micro-benchmark (see \VRef{s:MemoryMicroBenchmark}).
    9595
     
    231231Second is the low-performer group, which includes the rest of the memory allocators.
    232232These memory allocators have significant program-induced passive false-sharing, where \textsf{hrd}'s is the worst performing allocator.
    233 All of the allocators in this group are sharing heaps among threads at some level.
    234 
    235 Interestingly, allocators such as \textsf{hrd} and \textsf{glc} performed well in micro-benchmark cache thrash (see \VRef{sec:cache-thrash-perf}), but, these allocators are among the low performers in the cache scratch.
    236 It suggests these allocators do not actively produce false-sharing, but preserve program-induced passive false sharing.
     233All of the allocator's in this group are sharing heaps among threads at some level.
     234
     235Interestingly, allocators such as \textsf{hrd} and \textsf{glc} performed well in micro-benchmark cache thrash (see \VRef{sec:cache-thrash-perf}).
     236But, these allocators are among the low performers in the cache scratch.
     237It suggests these allocators do not actively produce false-sharing but preserve program-induced passive false sharing.
    237238
    238239%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  • doc/theses/mubeen_zulfiqar_MMath/uw-ethesis-frontpgs.tex

    re5d9274 r015925a  
    1313        \vspace*{1.0cm}
    1414
    15         {\Huge\bf High-Performance Concurrent Memory Allocation}
     15        {\Huge\bf \CFA Memory Allocation}
    1616
    1717        \vspace*{1.0cm}
     
    108108% D E C L A R A T I O N   P A G E
    109109% -------------------------------
    110   % The following is a sample Declaration Page as provided by the GSO
     110  % The following is a sample Delaration Page as provided by the GSO
    111111  % December 13th, 2006.  It is designed for an electronic thesis.
    112112 \begin{center}\textbf{Author's Declaration}\end{center}
     
    136136
    137137The goal of this thesis is to build a low-latency memory allocator for both kernel and user multi-threaded systems, which is competitive with the best current memory allocators, while extending the feature set of existing and new allocator routines.
    138 A new llheap memory-allocator is created that achieves all of these goals, while maintaining and managing sticky allocation properties for zero-filled and aligned allocations without a performance loss.
     138A new llheap memory-allocator is created that achieves all of these goals, while maintaining and managing sticky allocation properties for zero-fill and alignment allocations without a performance loss.
    139139Hence, it becomes possible to use @realloc@ frequently as a safe operation, rather than just occasionally, because it preserves sticky properties when enlarging storage requests.
    140140Furthermore, the ability to query sticky properties and information allows programmers to write safer programs, as it is possible to dynamically match allocation styles from unknown library routines that return allocations.
    141141The C allocation API is also extended with @resize@, advanced @realloc@, @aalloc@, @amemalign@, and @cmemalign@ so programmers do not make mistakes writing theses useful allocation operations.
    142142llheap is embedded into the \uC and \CFA runtime systems, both of which have user-level threading.
    143 The ability to use \CFA's advanced type-system (and possibly \CC's too) to combine advanced memory operations into one allocation routine using named arguments shows how far the allocation API can be pushed, which increases safety and greatly simplifies programmer's use of dynamic allocation.
     143The ability to use \CFA's advanced type-system (and possibly \CC's too) to have one allocation routine with completely orthogonal sticky properties shows how far the allocation API can be pushed, which increases safety and greatly simplifies programmer's use of dynamic allocation.
    144144
    145145The llheap allocator also provides comprehensive statistics for all allocation operations, which are invaluable in understanding and debugging a program's dynamic behaviour.
    146 No other memory allocator examined in the thesis provides such comprehensive statistics gathering.
    147 As well, llheap provides a debugging mode where allocations are checked with internal pre/post conditions and invariants. It is extremely useful, especially for students.
     146No other memory allocator examined in the thesis provides comprehensive statistics gathering.
     147As well, llheap provides a debugging mode where allocations are checked, along with internal pre/post conditions and invariants, is extremely useful, especially for students.
    148148While not as powerful as the @valgrind@ interpreter, a large number of allocations mistakes are detected.
    149149Finally, contention-free statistics gathering and debugging have a low enough cost to be used in production code.
    150150
    151 A micro-benchmark test-suite is started for comparing allocators, rather than relying on a suite of arbitrary programs. It has been an interesting challenge.
     151A micro-benchmark test-suite is started for comparing allocators, rather than relying on a suite of arbitrary programs, has been an interesting challenge.
    152152These micro-benchmarks have adjustment knobs to simulate allocation patterns hard-coded into arbitrary test programs.
    153 Existing memory allocators, glibc, dlmalloc, hoard, jemalloc, ptmalloc3, rpmalloc, tbmalloc, and the new allocator llheap are all compared using the new micro-benchmark test-suite.
     153Existing memory allocators, glibc, dlmalloc, hoard, jemalloc, ptmalloc3, rpmalloc, tbmalloc and the new allocator llheap are all compared using the new micro-benchmark test-suite.
    154154\cleardoublepage
    155155
     
    162162I would like to thank all the people who made this thesis possible.
    163163
    164 I would like to acknowledge Peter A. Buhr for his assistance and support throughout the process.
     164I would like to acknowledge Peter A. Buhr for his assistance and support throughtout the process.
    165165It would have been impossible without him.
    166166
    167 I would like to acknowledge Gregor Richards and Trevor Brown for reading my thesis quickly and giving me great feedback on my work.
    168 
    169167Also, I would say thanks to my team members at PLG especially Thierry, Michael, and Andrew for their input.
    170 
    171 Finally, a special thank you to Huawei Canada for funding this work.
    172168\end{center}
    173169\cleardoublepage
     
    199195% L I S T   O F   T A B L E S
    200196% ---------------------------
    201 % \addcontentsline{toc}{chapter}{List of Tables}
    202 % \listoftables
    203 % \cleardoublepage
    204 % \phantomsection               % allows hyperref to link to the correct page
     197\addcontentsline{toc}{chapter}{List of Tables}
     198\listoftables
     199\cleardoublepage
     200\phantomsection         % allows hyperref to link to the correct page
    205201
    206202% Change page numbering back to Arabic numerals
  • doc/theses/mubeen_zulfiqar_MMath/uw-ethesis.tex

    re5d9274 r015925a  
    106106    pdffitwindow=false,     % window fit to page when opened
    107107    pdfstartview={FitH},    % fits the width of the page to the window
    108     pdftitle={High-Performance Concurrent Memory Allocation}, % title: CHANGE THIS TEXT!
     108    pdftitle={Cforall Memory Allocation}, % title: CHANGE THIS TEXT!
    109109    pdfauthor={Mubeen Zulfiqar},    % author: CHANGE THIS TEXT! and uncomment this line
    110110    pdfsubject={Cforall},  % subject: CHANGE THIS TEXT! and uncomment this line
  • doc/theses/thierry_delisle_PhD/thesis/Makefile

    re5d9274 r015925a  
    33Build = build
    44Figures = img
    5 
    6 LaTMac = ../../../LaTeXmacros
    7 BibRep = ../../../bibliography
    8 
    9 Macros = ${LaTMac}
    10 TeXLIB = .:${Macros}:${Build}:${BibRep}:
     5Macros = ../../../LaTeXmacros
     6TeXLIB = .:${Macros}:${Build}:../../../bibliography:
    117LaTeX  = TEXINPUTS=${TeXLIB} && export TEXINPUTS && latex -halt-on-error -output-directory=${Build}
    128BibTeX = BIBINPUTS=${TeXLIB} && export BIBINPUTS && bibtex
     
    4137        emptytree \
    4238        fairness \
    43         idle \
    44         idle1 \
    45         idle2 \
    46         idle_state \
    4739        io_uring \
    4840        pivot_ring \
     
    5042        cycle \
    5143        result.cycle.jax.ops \
    52         result.yield.jax.ops \
    53         result.churn.jax.ops \
    54         result.cycle.jax.ns \
    55         result.yield.jax.ns \
    56         result.churn.jax.ns \
    57         result.cycle.low.jax.ops \
    58         result.yield.low.jax.ops \
    59         result.churn.low.jax.ops \
    60         result.cycle.low.jax.ns \
    61         result.yield.low.jax.ns \
    62         result.churn.low.jax.ns \
    63         result.memcd.updt.qps \
    64         result.memcd.updt.lat \
    65         result.memcd.rate.qps \
    66         result.memcd.rate.99th \
    6744}
    6845
     
    7552## Define the documents that need to be made.
    7653all: thesis.pdf
    77 thesis.pdf: ${TEXTS} ${FIGURES} ${PICTURES} thesis.tex glossary.tex local.bib ${LaTMac}/common.tex ${LaTMac}/common.sty ${BibRep}/pl.bib
     54thesis.pdf: ${TEXTS} ${FIGURES} ${PICTURES} thesis.tex glossary.tex local.bib ../../../LaTeXmacros/common.tex ../../../LaTeXmacros/common.sty
    7855
    7956DOCUMENT = thesis.pdf
     
    139116        python3 $< $@
    140117
    141 cycle_jax_ops_FLAGS = --MaxY=120000000
    142 cycle_low_jax_ops_FLAGS = --MaxY=120000000
    143 cycle_jax_ns_FLAGS = --MaxY=2000
    144 cycle_low_jax_ns_FLAGS = --MaxY=2000
     118build/result.%.ns.svg : data/% | ${Build}
     119        ../../../../benchmark/plot.py -f $< -o $@ -y "ns per ops"
    145120
    146 yield_jax_ops_FLAGS = --MaxY=150000000
    147 yield_low_jax_ops_FLAGS = --MaxY=150000000
    148 yield_jax_ns_FLAGS = --MaxY=1500
    149 yield_low_jax_ns_FLAGS = --MaxY=1500
    150 
    151 build/result.%.ns.svg : data/% Makefile | ${Build}
    152         ../../../../benchmark/plot.py -f $< -o $@ -y "ns per ops/procs" $($(subst .,_,$*)_ns_FLAGS)
    153 
    154 build/result.%.ops.svg : data/% Makefile | ${Build}
    155         ../../../../benchmark/plot.py -f $< -o $@ -y "Ops per second" $($(subst .,_,$*)_ops_FLAGS)
    156 
    157 build/result.memcd.updt.qps.svg : data/memcd.updt Makefile | ${Build}
    158         ../../../../benchmark/plot.py -f $< -o $@ -y "Actual QPS" -x "Update Ratio"
    159 
    160 build/result.memcd.updt.lat.svg : data/memcd.updt Makefile | ${Build}
    161         ../../../../benchmark/plot.py -f $< -o $@ -y "Average Read Latency" -x "Update Ratio"
    162 
    163 build/result.memcd.rate.qps.svg : data/memcd.rate Makefile | ${Build}
    164         ../../../../benchmark/plot.py -f $< -o $@ -y "Actual QPS" -x "Target QPS"
    165 
    166 build/result.memcd.rate.99th.svg : data/memcd.rate Makefile | ${Build}
    167         ../../../../benchmark/plot.py -f $< -o $@ -y "Tail Read Latency" -x "Target QPS"
     121build/result.%.ops.svg : data/% | ${Build}
     122        ../../../../benchmark/plot.py -f $< -o $@ -y "Ops per second"
    168123
    169124## pstex with inverted colors
  • doc/theses/thierry_delisle_PhD/thesis/data/cycle.jax

    re5d9274 r015925a  
    1 [["rdq-cycle-go", "./rdq-cycle-go -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10001.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 1138076440.0, "Ops per second": 113792094.48, "ns per ops": 8.79, "Ops per threads": 94839.0, "Ops per procs": 47419851.0, "Ops/sec/procs": 4741337.27, "ns per ops/procs": 210.91}],["rdq-cycle-go", "./rdq-cycle-go -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 200285.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 17638575791.0, "Ops per second": 88067238.72, "ns per ops": 11.35, "Ops per threads": 2204821.0, "Ops per procs": 1102410986.0, "Ops/sec/procs": 5504202.42, "ns per ops/procs": 181.68}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10100.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 54856916.0, "Ops per second": 5485691.0, "ns per ops": 184.0, "Ops per threads": 109713.0, "Ops per procs": 54856916.0, "Ops/sec/procs": 5485691.0, "ns per ops/procs": 184.0}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10025.449006, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 558836360.0, "Total blocks": 558836360.0, "Ops per second": 55741778.71, "ns per ops": 17.94, "Ops per threads": 69854.0, "Ops per procs": 34927272.0, "Ops/sec/procs": 3483861.17, "ns per ops/procs": 287.04}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10038.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 58647049.0, "Total blocks": 58647049.0, "Ops per second": 5842287.68, "ns per ops": 171.17, "Ops per threads": 7330.0, "Ops per procs": 3665440.0, "Ops/sec/procs": 365142.98, "ns per ops/procs": 2738.65}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10003.489711, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 728096996.0, "Total blocks": 728096996.0, "Ops per second": 72784299.98, "ns per ops": 13.74, "Ops per threads": 60674.0, "Ops per procs": 30337374.0, "Ops/sec/procs": 3032679.17, "ns per ops/procs": 329.74}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10021.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 63157049.0, "Total blocks": 63157049.0, "Ops per second": 6302255.13, "ns per ops": 158.67, "Ops per threads": 15789.0, "Ops per procs": 7894631.0, "Ops/sec/procs": 787781.89, "ns per ops/procs": 1269.39}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10009.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 62412200.0, "Total blocks": 62411700.0, "Ops per second": 6235572.31, "ns per ops": 160.37, "Ops per threads": 124824.0, "Ops per procs": 62412200.0, "Ops/sec/procs": 6235572.31, "ns per ops/procs": 160.37}],["rdq-cycle-go", "./rdq-cycle-go -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10000.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 464608617.0, "Ops per second": 46457191.42, "ns per ops": 21.53, "Ops per threads": 116152.0, "Ops per procs": 58076077.0, "Ops/sec/procs": 5807148.93, "ns per ops/procs": 172.2}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10099.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 391521066.0, "Ops per second": 39152106.0, "ns per ops": 25.0, "Ops per threads": 97880.0, "Ops per procs": 48940133.0, "Ops/sec/procs": 4894013.0, "ns per ops/procs": 206.0}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10099.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 963549550.0, "Ops per second": 96354955.0, "ns per ops": 10.0, "Ops per threads": 80295.0, "Ops per procs": 40147897.0, "Ops/sec/procs": 4014789.0, "ns per ops/procs": 251.0}],["rdq-cycle-go", "./rdq-cycle-go -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10001.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 867718190.0, "Ops per second": 86761170.55, "ns per ops": 11.53, "Ops per threads": 108464.0, "Ops per procs": 54232386.0, "Ops/sec/procs": 5422573.16, "ns per ops/procs": 184.41}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10100.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 962016289.0, "Ops per second": 96201628.0, "ns per ops": 10.0, "Ops per threads": 80168.0, "Ops per procs": 40084012.0, "Ops/sec/procs": 4008401.0, "ns per ops/procs": 251.0}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10016.837824, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 54738237.0, "Total blocks": 54737741.0, "Ops per second": 5464622.46, "ns per ops": 183.0, "Ops per threads": 109476.0, "Ops per procs": 54738237.0, "Ops/sec/procs": 5464622.46, "ns per ops/procs": 183.0}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10099.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 731309408.0, "Ops per second": 73130940.0, "ns per ops": 13.0, "Ops per threads": 91413.0, "Ops per procs": 45706838.0, "Ops/sec/procs": 4570683.0, "ns per ops/procs": 220.0}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10100.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 739772688.0, "Ops per second": 73977268.0, "ns per ops": 13.0, "Ops per threads": 92471.0, "Ops per procs": 46235793.0, "Ops/sec/procs": 4623579.0, "ns per ops/procs": 218.0}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10100.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 391449785.0, "Ops per second": 39144978.0, "ns per ops": 25.0, "Ops per threads": 97862.0, "Ops per procs": 48931223.0, "Ops/sec/procs": 4893122.0, "ns per ops/procs": 206.0}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10048.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 57239183.0, "Total blocks": 57239183.0, "Ops per second": 5696211.13, "ns per ops": 175.56, "Ops per threads": 4769.0, "Ops per procs": 2384965.0, "Ops/sec/procs": 237342.13, "ns per ops/procs": 4213.33}],["rdq-cycle-go", "./rdq-cycle-go -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10000.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 55248375.0, "Ops per second": 5524562.87, "ns per ops": 181.01, "Ops per threads": 110496.0, "Ops per procs": 55248375.0, "Ops/sec/procs": 5524562.87, "ns per ops/procs": 181.01}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10021.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 61553053.0, "Total blocks": 61553053.0, "Ops per second": 6142186.88, "ns per ops": 162.81, "Ops per threads": 15388.0, "Ops per procs": 7694131.0, "Ops/sec/procs": 767773.36, "ns per ops/procs": 1302.47}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10008.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 62811642.0, "Total blocks": 62811142.0, "Ops per second": 6275517.47, "ns per ops": 159.35, "Ops per threads": 125623.0, "Ops per procs": 62811642.0, "Ops/sec/procs": 6275517.47, "ns per ops/procs": 159.35}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10018.820873, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 260866706.0, "Total blocks": 260862710.0, "Ops per second": 26037665.44, "ns per ops": 38.41, "Ops per threads": 65216.0, "Ops per procs": 32608338.0, "Ops/sec/procs": 3254708.18, "ns per ops/procs": 307.25}],["rdq-cycle-go", "./rdq-cycle-go -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10000.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 874581175.0, "Ops per second": 87449851.2, "ns per ops": 11.44, "Ops per threads": 109322.0, "Ops per procs": 54661323.0, "Ops/sec/procs": 5465615.7, "ns per ops/procs": 182.96}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10099.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 55228782.0, "Ops per second": 5522878.0, "ns per ops": 182.0, "Ops per threads": 110457.0, "Ops per procs": 55228782.0, "Ops/sec/procs": 5522878.0, "ns per ops/procs": 182.0}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10009.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 62564955.0, "Total blocks": 62564455.0, "Ops per second": 6250797.96, "ns per ops": 159.98, "Ops per threads": 125129.0, "Ops per procs": 62564955.0, "Ops/sec/procs": 6250797.96, "ns per ops/procs": 159.98}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10100.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 738848909.0, "Ops per second": 73884890.0, "ns per ops": 13.0, "Ops per threads": 92356.0, "Ops per procs": 46178056.0, "Ops/sec/procs": 4617805.0, "ns per ops/procs": 218.0}],["rdq-cycle-go", "./rdq-cycle-go -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10001.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 1131221613.0, "Ops per second": 113108175.94, "ns per ops": 8.84, "Ops per threads": 94268.0, "Ops per procs": 47134233.0, "Ops/sec/procs": 4712840.66, "ns per ops/procs": 212.19}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10008.209159, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 729328104.0, "Total blocks": 729328099.0, "Ops per second": 72872987.81, "ns per ops": 13.72, "Ops per threads": 60777.0, "Ops per procs": 30388671.0, "Ops/sec/procs": 3036374.49, "ns per ops/procs": 329.34}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10099.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 961002611.0, "Ops per second": 96100261.0, "ns per ops": 10.0, "Ops per threads": 80083.0, "Ops per procs": 40041775.0, "Ops/sec/procs": 4004177.0, "ns per ops/procs": 252.0}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10099.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 390098231.0, "Ops per second": 39009823.0, "ns per ops": 25.0, "Ops per threads": 97524.0, "Ops per procs": 48762278.0, "Ops/sec/procs": 4876227.0, "ns per ops/procs": 207.0}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10100.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 55237591.0, "Ops per second": 5523759.0, "ns per ops": 182.0, "Ops per threads": 110475.0, "Ops per procs": 55237591.0, "Ops/sec/procs": 5523759.0, "ns per ops/procs": 182.0}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10016.576699, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 54510321.0, "Total blocks": 54509820.0, "Ops per second": 5442011.04, "ns per ops": 183.76, "Ops per threads": 109020.0, "Ops per procs": 54510321.0, "Ops/sec/procs": 5442011.04, "ns per ops/procs": 183.76}],["rdq-cycle-go", "./rdq-cycle-go -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10001.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 1135730371.0, "Ops per second": 113558509.97, "ns per ops": 8.81, "Ops per threads": 94644.0, "Ops per procs": 47322098.0, "Ops/sec/procs": 4731604.58, "ns per ops/procs": 211.34}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10039.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 61004037.0, "Total blocks": 61004037.0, "Ops per second": 6076255.04, "ns per ops": 164.58, "Ops per threads": 7625.0, "Ops per procs": 3812752.0, "Ops/sec/procs": 379765.94, "ns per ops/procs": 2633.2}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10004.891999, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 747946345.0, "Total blocks": 747934349.0, "Ops per second": 74758062.86, "ns per ops": 13.38, "Ops per threads": 62328.0, "Ops per procs": 31164431.0, "Ops/sec/procs": 3114919.29, "ns per ops/procs": 321.04}],["rdq-cycle-go", "./rdq-cycle-go -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10000.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 466424792.0, "Ops per second": 46638931.23, "ns per ops": 21.44, "Ops per threads": 116606.0, "Ops per procs": 58303099.0, "Ops/sec/procs": 5829866.4, "ns per ops/procs": 171.53}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10086.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 57343570.0, "Total blocks": 57343570.0, "Ops per second": 5685308.81, "ns per ops": 175.89, "Ops per threads": 4778.0, "Ops per procs": 2389315.0, "Ops/sec/procs": 236887.87, "ns per ops/procs": 4221.41}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10020.39533, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 263517289.0, "Total blocks": 263513293.0, "Ops per second": 26298093.07, "ns per ops": 38.03, "Ops per threads": 65879.0, "Ops per procs": 32939661.0, "Ops/sec/procs": 3287261.63, "ns per ops/procs": 304.2}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10025.357431, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 551670395.0, "Total blocks": 551662399.0, "Ops per second": 55027503.89, "ns per ops": 18.17, "Ops per threads": 68958.0, "Ops per procs": 34479399.0, "Ops/sec/procs": 3439218.99, "ns per ops/procs": 290.76}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10050.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 56162695.0, "Total blocks": 56162695.0, "Ops per second": 5588033.65, "ns per ops": 178.95, "Ops per threads": 4680.0, "Ops per procs": 2340112.0, "Ops/sec/procs": 232834.74, "ns per ops/procs": 4294.89}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10019.690183, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 271866976.0, "Total blocks": 271862980.0, "Ops per second": 27133271.69, "ns per ops": 36.86, "Ops per threads": 67966.0, "Ops per procs": 33983372.0, "Ops/sec/procs": 3391658.96, "ns per ops/procs": 294.84}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10057.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 62105022.0, "Total blocks": 62105022.0, "Ops per second": 6175186.04, "ns per ops": 161.94, "Ops per threads": 15526.0, "Ops per procs": 7763127.0, "Ops/sec/procs": 771898.25, "ns per ops/procs": 1295.51}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10025.81217, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 537080117.0, "Total blocks": 537072121.0, "Ops per second": 53569736.59, "ns per ops": 18.67, "Ops per threads": 67135.0, "Ops per procs": 33567507.0, "Ops/sec/procs": 3348108.54, "ns per ops/procs": 298.68}],["rdq-cycle-go", "./rdq-cycle-go -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10000.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 55967030.0, "Ops per second": 5596438.25, "ns per ops": 178.69, "Ops per threads": 111934.0, "Ops per procs": 55967030.0, "Ops/sec/procs": 5596438.25, "ns per ops/procs": 178.69}],["rdq-cycle-go", "./rdq-cycle-go -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10000.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 55703320.0, "Ops per second": 5570084.72, "ns per ops": 179.53, "Ops per threads": 111406.0, "Ops per procs": 55703320.0, "Ops/sec/procs": 5570084.72, "ns per ops/procs": 179.53}],["rdq-cycle-go", "./rdq-cycle-go -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10000.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 469211793.0, "Ops per second": 46918327.16, "ns per ops": 21.31, "Ops per threads": 117302.0, "Ops per procs": 58651474.0, "Ops/sec/procs": 5864790.9, "ns per ops/procs": 170.51}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10016.545208, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 54925472.0, "Total blocks": 54924976.0, "Ops per second": 5483474.68, "ns per ops": 182.37, "Ops per threads": 109850.0, "Ops per procs": 54925472.0, "Ops/sec/procs": 5483474.68, "ns per ops/procs": 182.37}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10037.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 60770550.0, "Total blocks": 60770550.0, "Ops per second": 6054474.7, "ns per ops": 165.17, "Ops per threads": 7596.0, "Ops per procs": 3798159.0, "Ops/sec/procs": 378404.67, "ns per ops/procs": 2642.67}]]
     1[["rdq-cycle-go", "./rdq-cycle-go -t 4 -p 4 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 4.0, "Number of threads": 20.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 43606897.0, "Ops per second": 8720908.73, "ns per ops": 114.67, "Ops per threads": 2180344.0, "Ops per procs": 10901724.0, "Ops/sec/procs": 2180227.18, "ns per ops/procs": 458.67}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 16 -p 16 -d 5 -r 5", {"Duration (ms)": 5010.922033, "Number of processors": 16.0, "Number of threads": 80.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 93993568.0, "Total blocks": 93993209.0, "Ops per second": 18757739.07, "ns per ops": 53.31, "Ops per threads": 1174919.0, "Ops per procs": 5874598.0, "Ops/sec/procs": 1172358.69, "ns per ops/procs": 852.98}],["rdq-cycle-go", "./rdq-cycle-go -t 16 -p 16 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 16.0, "Number of threads": 80.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 136763517.0, "Ops per second": 27351079.35, "ns per ops": 36.56, "Ops per threads": 1709543.0, "Ops per procs": 8547719.0, "Ops/sec/procs": 1709442.46, "ns per ops/procs": 584.99}],["rdq-cycle-go", "./rdq-cycle-go -t 1 -p 1 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 1.0, "Number of threads": 5.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 27778961.0, "Ops per second": 5555545.09, "ns per ops": 180.0, "Ops per threads": 5555792.0, "Ops per procs": 27778961.0, "Ops/sec/procs": 5555545.09, "ns per ops/procs": 180.0}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 4 -p 4 -d 5 -r 5", {"Duration (ms)": 5009.290878, "Number of processors": 4.0, "Number of threads": 20.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 43976310.0, "Total blocks": 43976217.0, "Ops per second": 8778949.17, "ns per ops": 113.91, "Ops per threads": 2198815.0, "Ops per procs": 10994077.0, "Ops/sec/procs": 2194737.29, "ns per ops/procs": 455.64}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 4 -p 4 -d 5 -r 5", {"Duration (ms)": 5009.151542, "Number of processors": 4.0, "Number of threads": 20.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 44132300.0, "Total blocks": 44132201.0, "Ops per second": 8810334.37, "ns per ops": 113.5, "Ops per threads": 2206615.0, "Ops per procs": 11033075.0, "Ops/sec/procs": 2202583.59, "ns per ops/procs": 454.01}],["rdq-cycle-go", "./rdq-cycle-go -t 4 -p 4 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 4.0, "Number of threads": 20.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 46353896.0, "Ops per second": 9270294.11, "ns per ops": 107.87, "Ops per threads": 2317694.0, "Ops per procs": 11588474.0, "Ops/sec/procs": 2317573.53, "ns per ops/procs": 431.49}],["rdq-cycle-go", "./rdq-cycle-go -t 1 -p 1 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 1.0, "Number of threads": 5.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 27894379.0, "Ops per second": 5578591.58, "ns per ops": 179.26, "Ops per threads": 5578875.0, "Ops per procs": 27894379.0, "Ops/sec/procs": 5578591.58, "ns per ops/procs": 179.26}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 1 -p 1 -d 5 -r 5", {"Duration (ms)": 5008.743463, "Number of processors": 1.0, "Number of threads": 5.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 32825528.0, "Total blocks": 32825527.0, "Ops per second": 6553645.29, "ns per ops": 152.59, "Ops per threads": 6565105.0, "Ops per procs": 32825528.0, "Ops/sec/procs": 6553645.29, "ns per ops/procs": 152.59}],["rdq-cycle-go", "./rdq-cycle-go -t 16 -p 16 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 16.0, "Number of threads": 80.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 138213098.0, "Ops per second": 27640977.5, "ns per ops": 36.18, "Ops per threads": 1727663.0, "Ops per procs": 8638318.0, "Ops/sec/procs": 1727561.09, "ns per ops/procs": 578.85}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 4 -p 4 -d 5 -r 5", {"Duration (ms)": 5007.914168, "Number of processors": 4.0, "Number of threads": 20.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 44109513.0, "Total blocks": 44109419.0, "Ops per second": 8807961.06, "ns per ops": 113.53, "Ops per threads": 2205475.0, "Ops per procs": 11027378.0, "Ops/sec/procs": 2201990.27, "ns per ops/procs": 454.13}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 16 -p 16 -d 5 -r 5", {"Duration (ms)": 5012.121876, "Number of processors": 16.0, "Number of threads": 80.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 94130673.0, "Total blocks": 94130291.0, "Ops per second": 18780603.37, "ns per ops": 53.25, "Ops per threads": 1176633.0, "Ops per procs": 5883167.0, "Ops/sec/procs": 1173787.71, "ns per ops/procs": 851.94}],["rdq-cycle-go", "./rdq-cycle-go -t 16 -p 16 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 16.0, "Number of threads": 80.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 140936367.0, "Ops per second": 28185668.38, "ns per ops": 35.48, "Ops per threads": 1761704.0, "Ops per procs": 8808522.0, "Ops/sec/procs": 1761604.27, "ns per ops/procs": 567.66}],["rdq-cycle-go", "./rdq-cycle-go -t 4 -p 4 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 4.0, "Number of threads": 20.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 44279585.0, "Ops per second": 8855475.01, "ns per ops": 112.92, "Ops per threads": 2213979.0, "Ops per procs": 11069896.0, "Ops/sec/procs": 2213868.75, "ns per ops/procs": 451.7}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 1 -p 1 -d 5 -r 5", {"Duration (ms)": 5008.37392, "Number of processors": 1.0, "Number of threads": 5.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 32227534.0, "Total blocks": 32227533.0, "Ops per second": 6434730.02, "ns per ops": 155.41, "Ops per threads": 6445506.0, "Ops per procs": 32227534.0, "Ops/sec/procs": 6434730.02, "ns per ops/procs": 155.41}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 16 -p 16 -d 5 -r 5", {"Duration (ms)": 5011.019789, "Number of processors": 16.0, "Number of threads": 80.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 90600569.0, "Total blocks": 90600173.0, "Ops per second": 18080265.66, "ns per ops": 55.31, "Ops per threads": 1132507.0, "Ops per procs": 5662535.0, "Ops/sec/procs": 1130016.6, "ns per ops/procs": 884.94}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 1 -p 1 -d 5 -r 5", {"Duration (ms)": 5008.52474, "Number of processors": 1.0, "Number of threads": 5.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 32861776.0, "Total blocks": 32861775.0, "Ops per second": 6561168.75, "ns per ops": 152.41, "Ops per threads": 6572355.0, "Ops per procs": 32861776.0, "Ops/sec/procs": 6561168.75, "ns per ops/procs": 152.41}],["rdq-cycle-go", "./rdq-cycle-go -t 1 -p 1 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 1.0, "Number of threads": 5.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 28097680.0, "Ops per second": 5619274.9, "ns per ops": 177.96, "Ops per threads": 5619536.0, "Ops per procs": 28097680.0, "Ops/sec/procs": 5619274.9, "ns per ops/procs": 177.96}]]
  • doc/theses/thierry_delisle_PhD/thesis/local.bib

    re5d9274 r015925a  
    701701  note = "[Online; accessed 12-April-2022]"
    702702}
    703 
    704 % RMR notes :
    705 % [05/04, 12:36] Trevor Brown
    706 %     i don't know where rmr complexity was first introduced, but there are many many many papers that use the term and define it
    707 % ​[05/04, 12:37] Trevor Brown
    708 %     here's one paper that uses the term a lot and links to many others that use it... might trace it to something useful there https://drops.dagstuhl.de/opus/volltexte/2021/14832/pdf/LIPIcs-DISC-2021-30.pdf
    709 % ​[05/04, 12:37] Trevor Brown
    710 %     another option might be to cite a textbook
    711 % ​[05/04, 12:42] Trevor Brown
    712 %     but i checked two textbooks in the area i'm aware of and i don't see a definition of rmr complexity in either
    713 % ​[05/04, 12:42] Trevor Brown
    714 %     this one has a nice statement about the prevelance of rmr complexity, as well as some rough definition
    715 % ​[05/04, 12:42] Trevor Brown
    716 %     https://dl.acm.org/doi/pdf/10.1145/3465084.3467938
    717 
    718 % Race to idle notes :
    719 % [13/04, 16:56] Martin Karsten
    720 %       I don't have a citation. Google brings up this one, which might be good:
    721 %
    722 % https://doi.org/10.1137/1.9781611973099.100
  • doc/theses/thierry_delisle_PhD/thesis/text/eval_macro.tex

    re5d9274 r015925a  
    77Networked ZIPF
    88
    9 Nginx : 5Gb still good, 4Gb starts to suffer
    10 
    11 Cforall : 10Gb too high, 4 Gb too low
    12 
    139\section{Memcached}
    1410
    15 \subsection{Benchmark Environment}
    16 These experiments are run on a cluster of homogenous Supermicro SYS-6017R-TDF compute nodes with the following characteristics:
    17 The server runs Ubuntu 20.04.3 LTS on top of Linux Kernel 5.11.0-34.
    18 Each node has 2 Intel(R) Xeon(R) CPU E5-2620 v2 running at 2.10GHz.
    19 These CPUs have 6 cores per CPUs and 2 \glspl{hthrd} per core, for a total of 24 \glspl{hthrd}.
    20 The cpus each have 384 KB, 3 MB and 30 MB of L1, L2 and L3 caches respectively.
    21 Each node is connected to the network through a Mellanox 10 Gigabit Ethernet port.
    22 The network route uses 1 Mellanox SX1012 10/40 Gigabit Ethernet cluster switch.
     11In Memory
    2312
    24 
    25 
    26 \begin{figure}
    27         \centering
    28         \input{result.memcd.updt.qps.pstex_t}
    29         \caption[Churn Benchmark : Throughput on Intel]{Churn Benchmark : Throughput on Intel\smallskip\newline Description}
    30         \label{fig:memcd:updt:qps}
    31 \end{figure}
    32 
    33 \begin{figure}
    34         \centering
    35         \input{result.memcd.updt.lat.pstex_t}
    36         \caption[Churn Benchmark : Throughput on Intel]{Churn Benchmark : Throughput on Intel\smallskip\newline Description}
    37         \label{fig:memcd:updt:lat}
    38 \end{figure}
    39 
    40 \begin{figure}
    41         \centering
    42         \input{result.memcd.rate.qps.pstex_t}
    43         \caption[Churn Benchmark : Throughput on Intel]{Churn Benchmark : Throughput on Intel\smallskip\newline Description}
    44         \label{fig:memcd:rate:qps}
    45 \end{figure}
    46 
    47 \begin{figure}
    48         \centering
    49         \input{result.memcd.rate.99th.pstex_t}
    50         \caption[Churn Benchmark : Throughput on Intel]{Churn Benchmark : Throughput on Intel\smallskip\newline Description}
    51         \label{fig:memcd:rate:tail}
    52 \end{figure}
     13Networked
  • doc/theses/thierry_delisle_PhD/thesis/text/eval_micro.tex

    re5d9274 r015925a  
    66\section{Benchmark Environment}
    77All of these benchmarks are run on two distinct hardware environment, an AMD and an INTEL machine.
    8 
    9 For all benchmarks, \texttt{taskset} is used to limit the experiment to 1 NUMA Node with no hyper threading.
    10 If more \glspl{hthrd} are needed, then 1 NUMA Node with hyperthreading is used.
    11 If still more \glspl{hthrd} are needed then the experiment is limited to as few NUMA Nodes as needed.
    12 
    138
    149\paragraph{AMD} The AMD machine is a server with two AMD EPYC 7662 CPUs and 256GB of DDR4 RAM.
     
    2823
    2924\section{Cycling latency}
    30 \begin{figure}
    31         \centering
    32         \input{cycle.pstex_t}
    33         \caption[Cycle benchmark]{Cycle benchmark\smallskip\newline Each \gls{at} unparks the next \gls{at} in the cycle before parking itself.}
    34         \label{fig:cycle}
    35 \end{figure}
    3625The most basic evaluation of any ready queue is to evaluate the latency needed to push and pop one element from the ready-queue.
    3726Since these two operation also describe a \texttt{yield} operation, many systems use this as the most basic benchmark.
     
    5342Note that this problem is only present on SMP machines and is significantly mitigated by the fact that there are multiple rings in the system.
    5443
     44\begin{figure}
     45        \centering
     46        \input{cycle.pstex_t}
     47        \caption[Cycle benchmark]{Cycle benchmark\smallskip\newline Each \gls{at} unparks the next \gls{at} in the cycle before parking itself.}
     48        \label{fig:cycle}
     49\end{figure}
     50
    5551To avoid this benchmark from being dominated by the idle sleep handling, the number of rings is kept at least as high as the number of \glspl{proc} available.
    5652Beyond this point, adding more rings serves to mitigate even more the idle sleep handling.
     
    5854
    5955The actual benchmark is more complicated to handle termination, but that simply requires using a binary semphore or a channel instead of raw \texttt{park}/\texttt{unpark} and carefully picking the order of the \texttt{P} and \texttt{V} with respect to the loop condition.
    60 Figure~\ref{fig:cycle:code} shows pseudo code for this benchmark.
     56
     57\begin{lstlisting}
     58        Thread.main() {
     59                count := 0
     60                for {
     61                        wait()
     62                        this.next.wake()
     63                        count ++
     64                        if must_stop() { break }
     65                }
     66                global.count += count
     67        }
     68\end{lstlisting}
    6169
    6270\begin{figure}
    63         \begin{lstlisting}
    64                 Thread.main() {
    65                         count := 0
    66                         for {
    67                                 wait()
    68                                 this.next.wake()
    69                                 count ++
    70                                 if must_stop() { break }
    71                         }
    72                         global.count += count
    73                 }
    74         \end{lstlisting}
    75         \caption[Cycle Benchmark : Pseudo Code]{Cycle Benchmark : Pseudo Code}
    76         \label{fig:cycle:code}
     71        \centering
     72        \input{result.cycle.jax.ops.pstex_t}
     73        \vspace*{-10pt}
     74        \label{fig:cycle:ns:jax}
    7775\end{figure}
    78 
    79 
    80 
    81 \subsection{Results}
    82 \begin{figure}
    83         \subfloat[][Throughput, 100 \ats per \proc]{
    84                 \resizebox{0.5\linewidth}{!}{
    85                         \input{result.cycle.jax.ops.pstex_t}
    86                 }
    87                 \label{fig:cycle:jax:ops}
    88         }
    89         \subfloat[][Throughput, 1 \ats per \proc]{
    90                 \resizebox{0.5\linewidth}{!}{
    91                         \input{result.cycle.low.jax.ops.pstex_t}
    92                 }
    93                 \label{fig:cycle:jax:low:ops}
    94         }
    95 
    96         \subfloat[][Latency, 100 \ats per \proc]{
    97                 \resizebox{0.5\linewidth}{!}{
    98                         \input{result.cycle.jax.ns.pstex_t}
    99                 }
    100 
    101         }
    102         \subfloat[][Latency, 1 \ats per \proc]{
    103                 \resizebox{0.5\linewidth}{!}{
    104                         \input{result.cycle.low.jax.ns.pstex_t}
    105                 }
    106                 \label{fig:cycle:jax:low:ns}
    107         }
    108         \caption[Cycle Benchmark on Intel]{Cycle Benchmark on Intel\smallskip\newline Throughput as a function of \proc count, using 100 cycles per \proc, 5 \ats per cycle.}
    109         \label{fig:cycle:jax}
    110 \end{figure}
    111 Figure~\ref{fig:cycle:jax} shows the throughput as a function of \proc count, with the following constants:
    112 Each run uses 100 cycles per \proc, 5 \ats per cycle.
    113 
    114 \todo{results discussion}
    11576
    11677\section{Yield}
     
    12081Its only interesting variable is the number of \glspl{at} per \glspl{proc}, where ratios close to 1 means the ready queue(s) could be empty.
    12182This sometimes puts more strain on the idle sleep handling, compared to scenarios where there is clearly plenty of work to be done.
    122 Figure~\ref{fig:yield:code} shows pseudo code for this benchmark, the ``wait/wake-next'' is simply replaced by a yield.
    12383
    124 \begin{figure}
    125         \begin{lstlisting}
    126                 Thread.main() {
    127                         count := 0
    128                         for {
    129                                 yield()
    130                                 count ++
    131                                 if must_stop() { break }
    132                         }
    133                         global.count += count
     84\todo{code, setup, results}
     85
     86\begin{lstlisting}
     87        Thread.main() {
     88                count := 0
     89                while !stop {
     90                        yield()
     91                        count ++
    13492                }
    135         \end{lstlisting}
    136         \caption[Yield Benchmark : Pseudo Code]{Yield Benchmark : Pseudo Code}
    137         \label{fig:yield:code}
    138 \end{figure}
    139 
    140 \subsection{Results}
    141 \begin{figure}
    142         \subfloat[][Throughput, 100 \ats per \proc]{
    143                 \resizebox{0.5\linewidth}{!}{
    144                         \input{result.yield.jax.ops.pstex_t}
    145                 }
    146                 \label{fig:yield:jax:ops}
     93                global.count += count
    14794        }
    148         \subfloat[][Throughput, 1 \ats per \proc]{
    149                 \resizebox{0.5\linewidth}{!}{
    150                 \input{result.yield.low.jax.ops.pstex_t}
    151                 }
    152                 \label{fig:yield:jax:low:ops}
    153         }
    154 
    155         \subfloat[][Latency, 100 \ats per \proc]{
    156                 \resizebox{0.5\linewidth}{!}{
    157                 \input{result.yield.jax.ns.pstex_t}
    158                 }
    159                 \label{fig:yield:jax:ns}
    160         }
    161         \subfloat[][Latency, 1 \ats per \proc]{
    162                 \resizebox{0.5\linewidth}{!}{
    163                 \input{result.yield.low.jax.ns.pstex_t}
    164                 }
    165                 \label{fig:yield:jax:low:ns}
    166         }
    167         \caption[Yield Benchmark on Intel]{Yield Benchmark on Intel\smallskip\newline Throughput as a function of \proc count, using 1 \ats per \proc.}
    168         \label{fig:yield:jax}
    169 \end{figure}
    170 Figure~\ref{fig:yield:ops:jax} shows the throughput as a function of \proc count, with the following constants:
    171 Each run uses 100 \ats per \proc.
    172 
    173 \todo{results discussion}
     95\end{lstlisting}
    17496
    17597
     
    183105In either case, this benchmark aims to highlight how each scheduler handles these cases, since both cases can lead to performance degradation if they are not handled correctly.
    184106
    185 To achieve this the benchmark uses a fixed size array of semaphores.
    186 Each \gls{at} picks a random semaphore, \texttt{V}s it to unblock a \at waiting and then \texttt{P}s on the semaphore.
    187 This creates a flow where \glspl{at} push each other out of the semaphores before being pushed out themselves.
    188 For this benchmark to work however, the number of \glspl{at} must be equal or greater to the number of semaphores plus the number of \glspl{proc}.
    189 Note that the nature of these semaphores mean the counter can go beyond 1, which could lead to calls to \texttt{P} not blocking.
     107To achieve this the benchmark uses a fixed size array of \newterm{chair}s, where a chair is a data structure that holds a single blocked \gls{at}.
     108When a \gls{at} attempts to block on the chair, it must first unblocked the \gls{at} currently blocked on said chair, if any.
     109This creates a flow where \glspl{at} push each other out of the chairs before being pushed out themselves.
     110For this benchmark to work however, the number of \glspl{at} must be equal or greater to the number of chairs plus the number of \glspl{proc}.
    190111
    191112\todo{code, setup, results}
     
    195116                for {
    196117                        r := random() % len(spots)
    197                         spots[r].V()
    198                         spots[r].P()
     118                        next := xchg(spots[r], this)
     119                        if next { next.wake() }
     120                        wait()
    199121                        count ++
    200122                        if must_stop() { break }
     
    203125        }
    204126\end{lstlisting}
    205 
    206 \begin{figure}
    207         \subfloat[][Throughput, 100 \ats per \proc]{
    208                 \resizebox{0.5\linewidth}{!}{
    209                         \input{result.churn.jax.ops.pstex_t}
    210                 }
    211                 \label{fig:churn:jax:ops}
    212         }
    213         \subfloat[][Throughput, 1 \ats per \proc]{
    214                 \resizebox{0.5\linewidth}{!}{
    215                         \input{result.churn.low.jax.ops.pstex_t}
    216                 }
    217                 \label{fig:churn:jax:low:ops}
    218         }
    219 
    220         \subfloat[][Latency, 100 \ats per \proc]{
    221                 \resizebox{0.5\linewidth}{!}{
    222                         \input{result.churn.jax.ns.pstex_t}
    223                 }
    224 
    225         }
    226         \subfloat[][Latency, 1 \ats per \proc]{
    227                 \resizebox{0.5\linewidth}{!}{
    228                         \input{result.churn.low.jax.ns.pstex_t}
    229                 }
    230                 \label{fig:churn:jax:low:ns}
    231         }
    232         \caption[Churn Benchmark on Intel]{\centering Churn Benchmark on Intel\smallskip\newline Throughput and latency of the Churn on the benchmark on the Intel machine. Throughput is the total operation per second across all cores. Latency is the duration of each opeartion.}
    233         \label{fig:churn:jax}
    234 \end{figure}
    235127
    236128\section{Locality}
  • doc/theses/thierry_delisle_PhD/thesis/text/intro.tex

    re5d9274 r015925a  
    22\todo{A proper intro}
    33
    4 The C programming language~\cite{C11}
     4The C programming language\cit{C}
    55
    6 The \CFA programming language~\cite{cfa:frontpage,cfa:typesystem} extends the C programming language by adding modern safety and productivity features, while maintaining backwards compatibility. Among its productivity features, \CFA supports user-level threading~\cite{Delisle21} allowing programmers to write modern concurrent and parallel programs.
    7 My previous master's thesis on concurrent in \CFA focused on features and interfaces.
    8 This Ph.D.\ thesis focuses on performance, introducing \glsxtrshort{api} changes only when required by performance considerations. Specifically, this work concentrates on scheduling and \glsxtrshort{io}. Prior to this work, the \CFA runtime used a strict \glsxtrshort{fifo} \gls{rQ} and  no non-blocking I/O capabilities at the user-thread level.
     6The \CFA programming language\cite{cfa:frontpage,cfa:typesystem} which extends the C programming language to add modern safety and productiviy features while maintaining backwards compatibility. Among it's productiviy features, \CFA introduces support for threading\cit{CFA Concurrency}, to allow programmers to write modern concurrent and parallel programming.
     7While previous work on the concurrent package of \CFA focused on features and interfaces, this thesis focuses on performance, introducing \glsxtrshort{api} changes only when required by performance considerations. More specifically, this thesis concentrates on scheduling and \glsxtrshort{io}. Prior to this work, the \CFA runtime used a strictly \glsxtrshort{fifo} \gls{rQ}.
    98
    10 As a research project, this work builds exclusively on newer versions of the Linux operating-system and gcc/clang compilers. While \CFA is released, supporting older versions of Linux ($<$~Ubuntu 16.04) and gcc/clang compilers ($<$~gcc 6.0) is not a goal of this work.
     9This work exclusively concentrates on Linux as it's operating system since the existing \CFA runtime and compiler does not already support other operating systems. Furthermore, as \CFA is yet to be released, supporting version of Linux older than the latest version is not a goal of this work.
  • doc/theses/thierry_delisle_PhD/thesis/text/practice.tex

    re5d9274 r015925a  
    77More precise \CFA supports adding \procs using the RAII object @processor@.
    88These objects can be created at any time and can be destroyed at any time.
    9 They are normally created as automatic stack variables, but this is not a requirement.
     9They are normally create as automatic stack variables, but this is not a requirement.
    1010
    1111The consequence is that the scheduler and \io subsystems must support \procs comming in and out of existence.
    1212
    1313\section{Manual Resizing}
    14 Manual resizing is expected to be a rare operation.
    15 Programmers are mostly expected to resize clusters on startup or teardown.
    16 Therefore dynamically changing the number of \procs is an appropriate moment to allocate or free resources to match the new state.
    17 As such all internal arrays that are sized based on the number of \procs need to be \texttt{realloc}ed.
    18 This also means that any references into these arrays, pointers or indexes, may need to be fixed when shrinking\footnote{Indexes may still need fixing when shrinkingbecause some indexes are expected to refer to dense contiguous resources and there is no guarantee the resource being removed has the highest index.}.
     14The consequence of dynamically changing the number of \procs is that all internal arrays that are sized based on the number of \procs neede to be \texttt{realloc}ed.
     15This also means that any references into these arrays, pointers or indexes, may need to be fixed when shrinking\footnote{Indexes may still need fixing because there is no guarantee the \proc causing the shrink had the highest index. Therefore indexes need to be reassigned to preserve contiguous indexes.}.
    1916
    20 There are no performance requirements, within reason, for resizing since it is expected to be rare.
     17There are no performance requirements, within reason, for resizing since this is usually considered as part of setup and teardown.
    2118However, this operation has strict correctness requirements since shrinking and idle sleep can easily lead to deadlocks.
    2219It should also avoid as much as possible any effect on performance when the number of \procs remain constant.
    23 This later requirement prohibits naive solutions, like simply adding a global lock to the ready-queue arrays.
     20This later requirement prehibits simple solutions, like simply adding a global lock to these arrays.
    2421
    2522\subsection{Read-Copy-Update}
     
    2724In this pattern, resizing is done by creating a copy of the internal data strucures, updating the copy with the desired changes, and then attempt an Idiana Jones Switch to replace the original witht the copy.
    2825This approach potentially has the advantage that it may not need any synchronization to do the switch.
    29 However, there is a race where \procs could still use the previous, original, data structure after the copy was switched in.
    30 This race not only requires some added memory reclamation scheme, it also requires that operations made on the stale original version be eventually moved to the copy.
     26The switch definitely implies a race where \procs could still use the previous, original, data structure after the copy was switched in.
     27The important question then becomes whether or not this race can be recovered from.
     28If the changes that arrived late can be transferred from the original to the copy then this solution works.
    3129
    32 For linked-lists, enqueing is only somewhat problematic, \ats enqueued to the original queues need to be transferred to the new, which might not preserve ordering.
    33 Dequeing is more challenging.
     30For linked-lists, dequeing is somewhat of a problem.
    3431Dequeing from the original will not necessarily update the copy which could lead to multiple \procs dequeing the same \at.
    35 Fixing this requires more synchronization or more indirection on the queues.
     32Fixing this requires making the array contain pointers to subqueues rather than the subqueues themselves.
    3633
    3734Another challenge is that the original must be kept until all \procs have witnessed the change.
     
    10097In addition to users manually changing the number of \procs, it is desireable to support ``removing'' \procs when there is not enough \ats for all the \procs to be useful.
    10198While manual resizing is expected to be rare, the number of \ats is expected to vary much more which means \procs may need to be ``removed'' for only short periods of time.
    102 Furthermore, race conditions that spuriously lead to the impression that no \ats are ready are actually common in practice.
    103 Therefore resources associated with \procs should not be freed but \procs simply put into an idle state where the \gls{kthrd} is blocked until more \ats become ready.
     99Furthermore, race conditions that spuriously lead to the impression no \ats are ready are actually common in practice.
     100Therefore \procs should not be actually \emph{removed} but simply put into an idle state where the \gls{kthrd} is blocked until more \ats become ready.
    104101This state is referred to as \newterm{Idle-Sleep}.
    105102
     
    113110The \CFA scheduler simply follows the ``Race-to-Idle'\cit{https://doi.org/10.1137/1.9781611973099.100}' approach where a sleeping \proc is woken any time an \at becomes ready and \procs go to idle sleep anytime they run out of work.
    114111
    115 \section{Sleeping}
    116 As usual, the corner-stone of any feature related to the kernel is the choice of system call.
    117 In terms of blocking a \gls{kthrd} until some event occurs the linux kernel has many available options:
    118 
    119 \paragraph{\texttt{pthread\_mutex}/\texttt{pthread\_cond}}
    120 The most classic option is to use some combination of \texttt{pthread\_mutex} and \texttt{pthread\_cond}.
    121 These serve as straight forward mutual exclusion and synchronization tools and allow a \gls{kthrd} to wait on a \texttt{pthread\_cond} until signalled.
    122 While this approach is generally perfectly appropriate for \glspl{kthrd} waiting after eachother, \io operations do not signal \texttt{pthread\_cond}s.
    123 For \io results to wake a \proc waiting on a \texttt{pthread\_cond} means that a different \glspl{kthrd} must be woken up first, and then the \proc can be signalled.
    124 
    125 \subsection{\texttt{io\_uring} and Epoll}
    126 An alternative is to flip the problem on its head and block waiting for \io, using \texttt{io\_uring} or even \texttt{epoll}.
    127 This creates the inverse situation, where \io operations directly wake sleeping \procs but waking \proc from a running \gls{kthrd} must use an indirect scheme.
    128 This generally takes the form of creating a file descriptor, \eg, a dummy file, a pipe or an event fd, and using that file descriptor when \procs need to wake eachother.
    129 This leads to additional complexity because there can be a race between these artificial \io operations and genuine \io operations.
    130 If not handled correctly, this can lead to the artificial files going out of sync.
    131 
    132 \subsection{Event FDs}
    133 Another interesting approach is to use an event file descriptor\cit{eventfd}.
    134 This is a Linux feature that is a file descriptor that behaves like \io, \ie, uses \texttt{read} and \texttt{write}, but also behaves like a semaphore.
    135 Indeed, all read and writes must use 64bits large values\footnote{On 64-bit Linux, a 32-bit Linux would use 32 bits values.}.
    136 Writes add their values to the buffer, that is arithmetic addition and not buffer append, and reads zero out the buffer and return the buffer values so far\footnote{This is without the \texttt{EFD\_SEMAPHORE} flag. This flags changes the behavior of \texttt{read} but is not needed for this work.}.
    137 If a read is made while the buffer is already 0, the read blocks until a non-0 value is added.
    138 What makes this feature particularly interesting is that \texttt{io\_uring} supports the \texttt{IORING\_REGISTER\_EVENTFD} command, to register an event fd to a particular instance.
    139 Once that instance is registered, any \io completion will result in \texttt{io\_uring} writing to the event FD.
    140 This means that a \proc waiting on the event FD can be \emph{directly} woken up by either other \procs or incomming \io.
    141 
    142 \begin{figure}
    143         \centering
    144         \input{idle1.pstex_t}
    145         \caption[Basic Idle Sleep Data Structure]{Basic Idle Sleep Data Structure \smallskip\newline Each idle \proc is put unto a doubly-linked stack protected by a lock.
    146         Each \proc has a private event FD.}
    147         \label{fig:idle1}
    148 \end{figure}
    149 
    150112
    151113\section{Tracking Sleepers}
    152114Tracking which \procs are in idle sleep requires a data structure holding all the sleeping \procs, but more importantly it requires a concurrent \emph{handshake} so that no \at is stranded on a ready-queue with no active \proc.
    153115The classic challenge is when a \at is made ready while a \proc is going to sleep, there is a race where the new \at may not see the sleeping \proc and the sleeping \proc may not see the ready \at.
    154 Since \ats can be made ready by timers, \io operations or other events outside a clusre, this race can occur even if the \proc going to sleep is the only \proc awake.
    155 As a result, improper handling of this race can lead to all \procs going to sleep and the system deadlocking.
    156116
    157 Furthermore, the ``Race-to-Idle'' approach means that there may be contention on the data structure tracking sleepers.
    158 Contention slowing down \procs attempting to sleep or wake-up can be tolerated.
    159 These \procs are not doing useful work and therefore not contributing to overall performance.
    160 However, notifying, checking if a \proc must be woken-up and doing so if needed, can significantly affect overall performance and must be low cost.
     117Furthermore, the ``Race-to-Idle'' approach means that there is some
    161118
    162 \subsection{Sleepers List}
    163 Each cluster maintains a list of idle \procs, organized as a stack.
    164 This ordering hopefully allows \proc at the tail to stay in idle sleep for extended period of times.
    165 Because of these unbalanced performance requirements, the algorithm tracking sleepers is designed to have idle \proc handle as much of the work as possible.
    166 The idle \procs maintain the of sleepers among themselves and notifying a sleeping \proc takes as little work as possible.
    167 This approach means that maintaining the list is fairly straightforward.
    168 The list can simply use a single lock per cluster and only \procs that are getting in and out of idle state will contend for that lock.
     119\section{Sleeping}
    169120
    170 This approach also simplifies notification.
    171 Indeed, \procs need to be notify when a new \at is readied, but they also must be notified during resizing, so the \gls{kthrd} can be joined.
    172 This means that whichever entity removes idle \procs from the sleeper list must be able to do so in any order.
    173 Using a simple lock over this data structure makes the removal much simpler than using a lock-free data structure.
    174 The notification process then simply needs to wake-up the desired idle \proc, using \texttt{pthread\_cond\_signal}, \texttt{write} on an fd, etc., and the \proc will handle the rest.
     121\subsection{Event FDs}
    175122
    176 \subsection{Reducing Latency}
    177 As mentioned in this section, \procs going idle for extremely short periods of time is likely in certain common scenarios.
    178 Therefore, the latency of doing a system call to read from and writing to the event fd can actually negatively affect overall performance in a notable way.
    179 Is it important to reduce latency and contention of the notification as much as possible.
    180 Figure~\ref{fig:idle1} shoes the basic idle sleep data structure.
    181 For the notifiers, this data structure can cause contention on the lock and the event fd syscall can cause notable latency.
     123\subsection{Epoll}
    182124
    183 \begin{figure}
    184         \centering
    185         \input{idle2.pstex_t}
    186         \caption[Improved Idle Sleep Data Structure]{Improved Idle Sleep Data Structure \smallskip\newline An atomic pointer is added to the list, pointing to the Event FD of the first \proc on the list.}
    187         \label{fig:idle2}
    188 \end{figure}
     125\subsection{\texttt{io\_uring}}
    189126
    190 The contention is mostly due to the lock on the list needing to be held to get to the head \proc.
    191 That lock can be contended by \procs attempting to go to sleep, \procs waking or notification attempts.
    192 The contentention from the \procs attempting to go to sleep can be mitigated slightly by using \texttt{try\_acquire} instead, so the \procs simply continue searching for \ats if the lock is held.
    193 This trick cannot be used for waking \procs since they are not in a state where they can run \ats.
    194 However, it is worth nothing that notification does not strictly require accessing the list or the head \proc.
    195 Therefore, contention can be reduced notably by having notifiers avoid the lock entirely and adding a pointer to the event fd of the first idle \proc, as in Figure~\ref{fig:idle2}.
    196 To avoid contention between the notifiers, instead of simply reading the atomic pointer, notifiers atomically exchange it to \texttt{null} so only only notifier will contend on the system call.
    197 
    198 \begin{figure}
    199         \centering
    200         \input{idle_state.pstex_t}
    201         \caption[Improved Idle Sleep Data Structure]{Improved Idle Sleep Data Structure \smallskip\newline An atomic pointer is added to the list, pointing to the Event FD of the first \proc on the list.}
    202         \label{fig:idle:state}
    203 \end{figure}
    204 
    205 The next optimization that can be done is to avoid the latency of the event fd when possible.
    206 This can be done by adding what is effectively a benaphore\cit{benaphore} in front of the event fd.
    207 A simple three state flag is added beside the event fd to avoid unnecessary system calls, as shown in Figure~\ref{fig:idle:state}.
    208 The flag starts in state \texttt{SEARCH}, while the \proc is searching for \ats to run.
    209 The \proc then confirms the sleep by atomically swaping the state to \texttt{SLEEP}.
    210 If the previous state was still \texttt{SEARCH}, then the \proc does read the event fd.
    211 Meanwhile, notifiers atomically exchange the state to \texttt{AWAKE} state.
    212 if the previous state was \texttt{SLEEP}, then the notifier must write to the event fd.
    213 However, if the notify arrives almost immediately after the \proc marks itself idle, then both reads and writes on the event fd can be omitted, which reduces latency notably.
    214 This leads to the final data structure shown in Figure~\ref{fig:idle}.
    215 
    216 \begin{figure}
    217         \centering
    218         \input{idle.pstex_t}
    219         \caption[Low-latency Idle Sleep Data Structure]{Low-latency Idle Sleep Data Structure \smallskip\newline Each idle \proc is put unto a doubly-linked stack protected by a lock.
    220         Each \proc has a private event FD with a benaphore in front of it.
    221         The list also has an atomic pointer to the event fd and benaphore of the first \proc on the list.}
    222         \label{fig:idle}
    223 \end{figure}
     127\section{Reducing Latency}
  • doc/theses/thierry_delisle_PhD/thesis/thesis.tex

    re5d9274 r015925a  
    8080%\usepackage{nomencl} % For a nomenclature (optional; available from ctan.org)
    8181\usepackage{amsmath,amssymb,amstext} % Lots of math symbols and environments
    82 \usepackage[dvipsnames]{xcolor}
     82\usepackage{xcolor}
    8383\usepackage{graphicx} % For including graphics
    84 \usepackage{subcaption}
    8584
    8685% Hyperlinks make it very easy to navigate an electronic document.
     
    105104        colorlinks=true,        % false: boxed links; true: colored links
    106105        linkcolor=blue,         % color of internal links
    107         citecolor=OliveGreen,   % color of links to bibliography
     106        citecolor=green,        % color of links to bibliography
    108107        filecolor=magenta,      % color of file links
    109108        urlcolor=cyan           % color of external links
     
    205204\newcommand\at{\gls{at}\xspace}%
    206205\newcommand\ats{\glspl{at}\xspace}%
    207 \newcommand\Proc{\Pls{proc}\xspace}%
    208206\newcommand\proc{\gls{proc}\xspace}%
    209207\newcommand\procs{\glspl{proc}\xspace}%
  • libcfa/src/Makefile.am

    re5d9274 r015925a  
    3333# The built sources must not depend on the installed inst_headers_src
    3434AM_CFAFLAGS = -quiet -cfalib -I$(srcdir)/stdhdr -I$(srcdir)/concurrency $(if $(findstring ${gdbwaittarget}, ${@}), -XCFA --gdb) @CONFIG_CFAFLAGS@
    35 AM_CFLAGS = -g -Wall -Werror=return-type -Wno-unused-function -fPIC -fexceptions -fvisibility=hidden -pthread @ARCH_FLAGS@ @CONFIG_CFLAGS@
     35AM_CFLAGS = -g -Wall -Werror=return-type -Wno-unused-function -fPIC -fexceptions -pthread @ARCH_FLAGS@ @CONFIG_CFLAGS@
    3636AM_CCASFLAGS = -g -Wall -Werror=return-type -Wno-unused-function @ARCH_FLAGS@ @CONFIG_CFLAGS@
    3737CFACC = @CFACC@
     
    194194
    195195prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @LOCAL_CFACC@ @CFACPP@
    196         ${AM_V_GEN}$(CFACOMPILE) -quiet -XCFA,-l ${<} -c -fvisibility=default -o ${@}
     196        ${AM_V_GEN}$(CFACOMPILE) -quiet -XCFA,-l ${<} -c -o ${@}
    197197
    198198prelude.lo: prelude.cfa extras.cf gcc-builtins.cf builtins.cf @LOCAL_CFACC@ @CFACPP@
    199199        ${AM_V_GEN}$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile \
    200         $(CFACOMPILE) -quiet -XCFA,-l ${<} -c -fvisibility=default -o ${@}
     200        $(CFACOMPILE) -quiet -XCFA,-l ${<} -c -o ${@}
    201201
    202202concurrency/io/call.cfa: $(srcdir)/concurrency/io/call.cfa.in
  • libcfa/src/algorithms/range_iterator.cfa

    re5d9274 r015925a  
    2020#include <fstream.hfa>
    2121
    22 #include "bits/defs.hfa"
    23 
    24 void main(RangeIter & this) libcfa_public {
     22void main(RangeIter & this) {
    2523        for() {
    2624                this._start = -1;
  • libcfa/src/assert.cfa

    re5d9274 r015925a  
    1919#include <unistd.h>                                                             // STDERR_FILENO
    2020#include "bits/debug.hfa"
    21 #include "bits/defs.hfa"
    2221
    2322extern "C" {
     
    2726
    2827        // called by macro assert in assert.h
    29         // would be cool to remove libcfa_public but it's needed for libcfathread
    30         void __assert_fail( const char assertion[], const char file[], unsigned int line, const char function[] ) libcfa_public {
     28        void __assert_fail( const char assertion[], const char file[], unsigned int line, const char function[] ) {
    3129                __cfaabi_bits_print_safe( STDERR_FILENO, CFA_ASSERT_FMT ".\n", assertion, __progname, function, line, file );
    3230                abort();
     
    3432
    3533        // called by macro assertf
    36         // would be cool to remove libcfa_public but it's needed for libcfathread
    37         void __assert_fail_f( const char assertion[], const char file[], unsigned int line, const char function[], const char fmt[], ... ) libcfa_public {
     34        void __assert_fail_f( const char assertion[], const char file[], unsigned int line, const char function[], const char fmt[], ... ) {
    3835                __cfaabi_bits_acquire();
    3936                __cfaabi_bits_print_nolock( STDERR_FILENO, CFA_ASSERT_FMT ": ", assertion, __progname, function, line, file );
  • libcfa/src/bits/debug.cfa

    re5d9274 r015925a  
    2121#include <unistd.h>
    2222
    23 #include "bits/defs.hfa"
    24 
    2523enum { buffer_size = 4096 };
    2624static char buffer[ buffer_size ];
    2725
    2826extern "C" {
    29         // would be cool to remove libcfa_public but it's needed for libcfathread
    30         void __cfaabi_bits_write( int fd, const char in_buffer[], int len ) libcfa_public {
     27        void __cfaabi_bits_write( int fd, const char in_buffer[], int len ) {
    3128                // ensure all data is written
    3229                for ( int count = 0, retcode; count < len; count += retcode ) {
     
    4744        void __cfaabi_bits_release() __attribute__((__weak__)) {}
    4845
    49         // would be cool to remove libcfa_public but it's needed for libcfathread
    50         int __cfaabi_bits_print_safe  ( int fd, const char fmt[], ... ) __attribute__(( format(printf, 2, 3) )) libcfa_public {
     46        int __cfaabi_bits_print_safe  ( int fd, const char fmt[], ... ) __attribute__(( format(printf, 2, 3) )) {
    5147                va_list args;
    5248
  • libcfa/src/bits/defs.hfa

    re5d9274 r015925a  
    3636#define __cfa_dlink(x) struct { struct x * next; struct x * back; } __dlink_substitute
    3737#endif
    38 
    39 #define libcfa_public __attribute__((visibility("default")))
    4038
    4139#ifdef __cforall
  • libcfa/src/bits/weakso_locks.cfa

    re5d9274 r015925a  
    1818#include "bits/weakso_locks.hfa"
    1919
    20 #pragma GCC visibility push(default)
    21 
    2220void  ?{}( blocking_lock &, bool, bool ) {}
    2321void ^?{}( blocking_lock & ) {}
  • libcfa/src/common.cfa

    re5d9274 r015925a  
    1818#include <stdlib.h>                                     // div_t, *div
    1919
    20 #pragma GCC visibility push(default)
    21 
    2220//---------------------------------------
    2321
  • libcfa/src/concurrency/alarm.cfa

    re5d9274 r015925a  
    141141//=============================================================================================
    142142
    143 void sleep( Duration duration ) libcfa_public {
     143void sleep( Duration duration ) {
    144144        alarm_node_t node = { active_thread(), duration, 0`s };
    145145
  • libcfa/src/concurrency/clib/cfathread.cfa

    re5d9274 r015925a  
    237237
    238238typedef ThreadCancelled(cfathread_object) cfathread_exception;
    239 typedef vtable(ThreadCancelled(cfathread_object)) cfathread_vtable;
     239typedef ThreadCancelled_vtable(cfathread_object) cfathread_vtable;
    240240
    241241void defaultResumptionHandler(ThreadCancelled(cfathread_object) & except) {
     
    283283
    284284typedef ThreadCancelled(__cfainit) __cfainit_exception;
    285 typedef vtable(ThreadCancelled(__cfainit)) __cfainit_vtable;
     285typedef ThreadCancelled_vtable(__cfainit) __cfainit_vtable;
    286286
    287287void defaultResumptionHandler(ThreadCancelled(__cfainit) & except) {
     
    326326}
    327327
    328 #pragma GCC visibility push(default)
    329 
    330328//================================================================================
    331329// Main Api
    332330extern "C" {
    333         int cfathread_cluster_create(cfathread_cluster_t * cl) __attribute__((nonnull(1))) libcfa_public {
     331        int cfathread_cluster_create(cfathread_cluster_t * cl) __attribute__((nonnull(1))) {
    334332                *cl = new();
    335333                return 0;
    336334        }
    337335
    338         cfathread_cluster_t cfathread_cluster_self(void) libcfa_public {
     336        cfathread_cluster_t cfathread_cluster_self(void) {
    339337                return active_cluster();
    340338        }
    341339
    342         int cfathread_cluster_print_stats( cfathread_cluster_t cl ) libcfa_public {
     340        int cfathread_cluster_print_stats( cfathread_cluster_t cl ) {
    343341                #if !defined(__CFA_NO_STATISTICS__)
    344342                        print_stats_at_exit( *cl, CFA_STATS_READY_Q | CFA_STATS_IO );
  • libcfa/src/concurrency/coroutine.cfa

    re5d9274 r015925a  
    4848//-----------------------------------------------------------------------------
    4949forall(T &)
    50 void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) libcfa_public {
     50void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) {
    5151        dst->virtual_table = src->virtual_table;
    5252        dst->the_coroutine = src->the_coroutine;
     
    5555
    5656forall(T &)
    57 const char * msg(CoroutineCancelled(T) *) libcfa_public {
     57const char * msg(CoroutineCancelled(T) *) {
    5858        return "CoroutineCancelled(...)";
    5959}
     
    6262forall(T & | is_coroutine(T))
    6363void __cfaehm_cancelled_coroutine(
    64                 T & cor, coroutine$ * desc, EHM_DEFAULT_VTABLE(CoroutineCancelled(T)) ) libcfa_public {
     64                T & cor, coroutine$ * desc, EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)) ) {
    6565        verify( desc->cancellation );
    6666        desc->state = Cancelled;
     
    8989
    9090void __stack_prepare( __stack_info_t * this, size_t create_size );
    91 static void __stack_clean  ( __stack_info_t * this );
     91void __stack_clean  ( __stack_info_t * this );
    9292
    9393//-----------------------------------------------------------------------------
     
    114114}
    115115
    116 void ?{}( coroutine$ & this, const char name[], void * storage, size_t storageSize ) libcfa_public with( this ) {
     116void ?{}( coroutine$ & this, const char name[], void * storage, size_t storageSize ) with( this ) {
    117117        (this.context){0p, 0p};
    118118        (this.stack){storage, storageSize};
     
    124124}
    125125
    126 void ^?{}(coroutine$& this) libcfa_public {
     126void ^?{}(coroutine$& this) {
    127127        if(this.state != Halted && this.state != Start && this.state != Primed) {
    128128                coroutine$ * src = active_coroutine();
     
    146146// Part of the Public API
    147147// Not inline since only ever called once per coroutine
    148 forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled(T)); })
    149 void prime(T& cor) libcfa_public {
     148forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)); })
     149void prime(T& cor) {
    150150        coroutine$* this = get_coroutine(cor);
    151151        assert(this->state == Start);
     
    155155}
    156156
    157 static [void *, size_t] __stack_alloc( size_t storageSize ) {
     157[void *, size_t] __stack_alloc( size_t storageSize ) {
    158158        const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment
    159159        assert(__page_size != 0l);
     
    193193}
    194194
    195 static void __stack_clean  ( __stack_info_t * this ) {
     195void __stack_clean  ( __stack_info_t * this ) {
    196196        void * storage = this->storage->limit;
    197197
     
    215215}
    216216
    217 void __stack_prepare( __stack_info_t * this, size_t create_size ) libcfa_public {
     217void __stack_prepare( __stack_info_t * this, size_t create_size ) {
    218218        const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment
    219219        bool userStack;
  • libcfa/src/concurrency/coroutine.hfa

    re5d9274 r015925a  
    2222//-----------------------------------------------------------------------------
    2323// Exception thrown from resume when a coroutine stack is cancelled.
    24 forall(coroutine_t &)
    25 exception CoroutineCancelled {
     24EHM_FORALL_EXCEPTION(CoroutineCancelled, (coroutine_t &), (coroutine_t)) (
    2625        coroutine_t * the_coroutine;
    2726        exception_t * the_exception;
    28 };
     27);
    2928
    3029forall(T &)
     
    3837// Anything that implements this trait can be resumed.
    3938// Anything that is resumed is a coroutine.
    40 trait is_coroutine(T & | IS_RESUMPTION_EXCEPTION(CoroutineCancelled(T))) {
     39trait is_coroutine(T & | IS_RESUMPTION_EXCEPTION(CoroutineCancelled, (T))) {
    4140        void main(T & this);
    4241        coroutine$ * get_coroutine(T & this);
     
    6160//-----------------------------------------------------------------------------
    6261// Public coroutine API
    63 forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled(T)); })
     62forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)); })
    6463void prime(T & cor);
    6564
     
    114113
    115114extern void __stack_prepare( __stack_info_t * this, size_t size /* ignored if storage already allocated */);
     115extern void __stack_clean  ( __stack_info_t * this );
     116
    116117
    117118// Suspend implementation inlined for performance
     
    140141forall(T & | is_coroutine(T))
    141142void __cfaehm_cancelled_coroutine(
    142         T & cor, coroutine$ * desc, EHM_DEFAULT_VTABLE(CoroutineCancelled(T)) );
     143        T & cor, coroutine$ * desc, EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)) );
    143144
    144145// Resume implementation inlined for performance
    145 forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled(T)); })
     146forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)); })
    146147static inline T & resume(T & cor) {
    147148        // optimization : read TLS once and reuse it
  • libcfa/src/concurrency/exception.cfa

    re5d9274 r015925a  
    6464extern "C" {
    6565
    66 struct exception_context_t * this_exception_context(void) libcfa_public {
     66struct exception_context_t * this_exception_context(void) {
    6767        return &__get_stack( active_coroutine() )->exception_context;
    6868}
    6969
    70 _Unwind_Reason_Code __cfaehm_cancellation_unwind( struct _Unwind_Exception * unwind_exception ) libcfa_public {
     70_Unwind_Reason_Code __cfaehm_cancellation_unwind( struct _Unwind_Exception * unwind_exception ) {
    7171        _Unwind_Stop_Fn stop_func;
    7272        void * stop_param;
  • libcfa/src/concurrency/invoke.c

    re5d9274 r015925a  
    3636extern void enable_interrupts( _Bool poll );
    3737
    38 libcfa_public void __cfactx_invoke_coroutine(
     38void __cfactx_invoke_coroutine(
    3939        void (*main)(void *),
    4040        void *this
     
    7070}
    7171
    72 libcfa_public void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct coroutine$ * cor) __attribute__ ((__noreturn__));
     72void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct coroutine$ * cor) __attribute__ ((__noreturn__));
    7373void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct coroutine$ * cor) {
    7474        _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, __cfactx_coroutine_unwindstop, cor );
     
    7777}
    7878
    79 libcfa_public void __cfactx_invoke_thread(
     79void __cfactx_invoke_thread(
    8080        void (*main)(void *),
    8181        void *this
     
    9898}
    9999
    100 libcfa_public void __cfactx_start(
     100void __cfactx_start(
    101101        void (*main)(void *),
    102102        struct coroutine$ * cor,
  • libcfa/src/concurrency/io.cfa

    re5d9274 r015925a  
    221221                        const unsigned long long ctsc = rdtscl();
    222222
    223                         if(proc->io.target == UINT_MAX) {
     223                        if(proc->io.target == MAX) {
    224224                                uint64_t chaos = __tls_rand();
    225225                                unsigned ext = chaos & 0xff;
     
    232232                        else {
    233233                                const unsigned target = proc->io.target;
    234                                 /* paranoid */ verify( io.tscs[target].tv != ULLONG_MAX );
     234                                /* paranoid */ verify( io.tscs[target].tv != MAX );
    235235                                HELP: if(target < ctxs_count) {
    236236                                        const unsigned long long cutoff = calc_cutoff(ctsc, ctx->cq.id, ctxs_count, io.data, io.tscs, __shard_factor.io);
     
    246246                                        __STATS__( true, io.calls.helped++; )
    247247                                }
    248                                 proc->io.target = UINT_MAX;
     248                                proc->io.target = MAX;
    249249                        }
    250250                }
     
    340340        // for convenience, return both the index and the pointer to the sqe
    341341        // sqe == &sqes[idx]
    342         struct $io_context * cfa_io_allocate(struct io_uring_sqe * sqes[], __u32 idxs[], __u32 want) libcfa_public {
     342        struct $io_context * cfa_io_allocate(struct io_uring_sqe * sqes[], __u32 idxs[], __u32 want) {
    343343                // __cfadbg_print_safe(io, "Kernel I/O : attempting to allocate %u\n", want);
    344344
     
    419419        }
    420420
    421         void cfa_io_submit( struct $io_context * inctx, __u32 idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1))) libcfa_public {
     421        void cfa_io_submit( struct $io_context * inctx, __u32 idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1))) {
    422422                // __cfadbg_print_safe(io, "Kernel I/O : attempting to submit %u (%s)\n", have, lazy ? "lazy" : "eager");
    423423
  • libcfa/src/concurrency/io/call.cfa.in

    re5d9274 r015925a  
    139139// I/O Interface
    140140//=============================================================================================
    141 #pragma GCC visibility push(default)
    142141"""
    143142
  • libcfa/src/concurrency/io/setup.cfa

    re5d9274 r015925a  
    2626
    2727#if !defined(CFA_HAVE_LINUX_IO_URING_H)
    28         void ?{}(io_context_params & this) libcfa_public {}
     28        void ?{}(io_context_params & this) {}
    2929
    3030        void  ?{}($io_context & this, struct cluster & cl) {}
     
    6666#pragma GCC diagnostic pop
    6767
    68         void ?{}(io_context_params & this) libcfa_public {
     68        void ?{}(io_context_params & this) {
    6969                this.num_entries = 256;
    7070        }
  • libcfa/src/concurrency/io/types.hfa

    re5d9274 r015925a  
    1717#pragma once
    1818
    19 #include <limits.h>
    20 
    2119extern "C" {
    2220        #include <linux/types.h>
     
    2725#include "iofwd.hfa"
    2826#include "kernel/fwd.hfa"
     27#include "limits.hfa"
    2928
    3029#if defined(CFA_HAVE_LINUX_IO_URING_H)
     
    141140                const __u32 tail = *this->cq.tail;
    142141
    143                 if(head == tail) return ULLONG_MAX;
     142                if(head == tail) return MAX;
    144143
    145144                return this->cq.ts;
  • libcfa/src/concurrency/kernel.cfa

    re5d9274 r015925a  
    389389
    390390// KERNEL_ONLY
    391 static void returnToKernel() {
     391void returnToKernel() {
    392392        /* paranoid */ verify( ! __preemption_enabled() );
    393393        coroutine$ * proc_cor = get_coroutine(kernelTLS().this_processor->runner);
     
    547547}
    548548
    549 void unpark( thread$ * thrd, unpark_hint hint ) libcfa_public {
     549void unpark( thread$ * thrd, unpark_hint hint ) {
    550550        if( !thrd ) return;
    551551
     
    558558}
    559559
    560 void park( void ) libcfa_public {
     560void park( void ) {
    561561        __disable_interrupts_checked();
    562562                /* paranoid */ verify( kernelTLS().this_thread->preempted == __NO_PREEMPTION );
     
    601601
    602602// KERNEL ONLY
    603 bool force_yield( __Preemption_Reason reason ) libcfa_public {
     603bool force_yield( __Preemption_Reason reason ) {
    604604        __disable_interrupts_checked();
    605605                thread$ * thrd = kernelTLS().this_thread;
     
    849849//-----------------------------------------------------------------------------
    850850// Debug
    851 bool threading_enabled(void) __attribute__((const)) libcfa_public {
     851bool threading_enabled(void) __attribute__((const)) {
    852852        return true;
    853853}
     
    856856// Statistics
    857857#if !defined(__CFA_NO_STATISTICS__)
    858         void print_halts( processor & this ) libcfa_public {
     858        void print_halts( processor & this ) {
    859859                this.print_halts = true;
    860860        }
     
    873873        }
    874874
    875         static void crawl_cluster_stats( cluster & this ) {
     875        void crawl_cluster_stats( cluster & this ) {
    876876                // Stop the world, otherwise stats could get really messed-up
    877877                // this doesn't solve all problems but does solve many
     
    889889
    890890
    891         void print_stats_now( cluster & this, int flags ) libcfa_public {
     891        void print_stats_now( cluster & this, int flags ) {
    892892                crawl_cluster_stats( this );
    893893                __print_stats( this.stats, flags, "Cluster", this.name, (void*)&this );
  • libcfa/src/concurrency/kernel.hfa

    re5d9274 r015925a  
    4949
    5050// Coroutine used py processors for the 2-step context switch
    51 
    52 struct processorCtx_t {
    53         struct coroutine$ self;
     51coroutine processorCtx_t {
    5452        struct processor * proc;
    5553};
  • libcfa/src/concurrency/kernel/cluster.cfa

    re5d9274 r015925a  
    4949
    5050// returns the maximum number of processors the RWLock support
    51 __attribute__((weak)) unsigned __max_processors() libcfa_public {
     51__attribute__((weak)) unsigned __max_processors() {
    5252        const char * max_cores_s = getenv("CFA_MAX_PROCESSORS");
    5353        if(!max_cores_s) {
     
    233233                                        if(is_empty(sl)) {
    234234                                                assert( sl.anchor.next == 0p );
    235                                                 assert( sl.anchor.ts   == MAX );
     235                                                assert( sl.anchor.ts   == -1llu );
    236236                                                assert( mock_head(sl)  == sl.prev );
    237237                                        } else {
    238238                                                assert( sl.anchor.next != 0p );
    239                                                 assert( sl.anchor.ts   != MAX );
     239                                                assert( sl.anchor.ts   != -1llu );
    240240                                                assert( mock_head(sl)  != sl.prev );
    241241                                        }
     
    259259                /* paranoid */ verifyf( it, "Unexpected null iterator, at index %u of %u\n", i, count);
    260260                it->rdq.id = valrq;
    261                 it->rdq.target = UINT_MAX;
     261                it->rdq.target = MAX;
    262262                valrq += __shard_factor.readyq;
    263263                #if defined(CFA_HAVE_LINUX_IO_URING_H)
    264264                        it->io.ctx->cq.id = valio;
    265                         it->io.target = UINT_MAX;
     265                        it->io.target = MAX;
    266266                        valio += __shard_factor.io;
    267267                #endif
     
    472472        this.prev = mock_head(this);
    473473        this.anchor.next = 0p;
    474         this.anchor.ts   = MAX;
     474        this.anchor.ts   = -1llu;
    475475        #if !defined(__CFA_NO_STATISTICS__)
    476476                this.cnt  = 0;
     
    484484        /* paranoid */ verify( &mock_head(this)->link.ts   == &this.anchor.ts   );
    485485        /* paranoid */ verify( mock_head(this)->link.next == 0p );
    486         /* paranoid */ verify( mock_head(this)->link.ts   == MAX );
     486        /* paranoid */ verify( mock_head(this)->link.ts   == -1llu );
    487487        /* paranoid */ verify( mock_head(this) == this.prev );
    488488        /* paranoid */ verify( __alignof__(__intrusive_lane_t) == 128 );
     
    495495        // Make sure the list is empty
    496496        /* paranoid */ verify( this.anchor.next == 0p );
    497         /* paranoid */ verify( this.anchor.ts   == MAX );
     497        /* paranoid */ verify( this.anchor.ts   == -1llu );
    498498        /* paranoid */ verify( mock_head(this)  == this.prev );
    499499}
  • libcfa/src/concurrency/kernel/cluster.hfa

    re5d9274 r015925a  
    1919#include "kernel/private.hfa"
    2020
    21 #include <limits.h>
     21#include "limits.hfa"
    2222
    2323//-----------------------------------------------------------------------
     
    3737
    3838static inline void touch_tsc(__timestamp_t * tscs, size_t idx, unsigned long long ts_prev, unsigned long long ts_next) {
    39         if (ts_next == ULLONG_MAX) return;
     39        if (ts_next == MAX) return;
    4040        unsigned long long now = rdtscl();
    4141        unsigned long long pma = __atomic_load_n(&tscs[ idx ].ma, __ATOMIC_RELAXED);
     
    5959        for(i; shard_factor) {
    6060                unsigned long long ptsc = ts(data[start + i]);
    61                 if(ptsc != ULLONG_MAX) {
     61                if(ptsc != -1ull) {
    6262                        /* paranoid */ verify( start + i < count );
    6363                        unsigned long long tsc = moving_average(ctsc, ptsc, tscs[start + i].ma);
  • libcfa/src/concurrency/kernel/private.hfa

    re5d9274 r015925a  
    109109//-----------------------------------------------------------------------------
    110110// Processor
    111 void main(processorCtx_t &);
    112 static inline coroutine$* get_coroutine(processorCtx_t & this) { return &this.self; }
     111void main(processorCtx_t *);
    113112
    114113void * __create_pthread( pthread_t *, void * (*)(void *), void * );
  • libcfa/src/concurrency/kernel/startup.cfa

    re5d9274 r015925a  
    120120#endif
    121121
    122 cluster              * mainCluster libcfa_public;
     122cluster              * mainCluster;
    123123processor            * mainProcessor;
    124124thread$              * mainThread;
     
    169169};
    170170
    171 static void ?{}( current_stack_info_t & this ) {
     171void ?{}( current_stack_info_t & this ) {
    172172        __stack_context_t ctx;
    173173        CtxGet( ctx );
     
    209209        // Construct the processor context of the main processor
    210210        void ?{}(processorCtx_t & this, processor * proc) {
    211                 (this.self){ "Processor" };
    212                 this.self.starter = 0p;
     211                (this.__cor){ "Processor" };
     212                this.__cor.starter = 0p;
    213213                this.proc = proc;
    214214        }
     
    507507        self_mon_p = &self_mon;
    508508        link.next = 0p;
    509         link.ts   = MAX;
     509        link.ts   = -1llu;
    510510        preferred = ready_queue_new_preferred();
    511511        last_proc = 0p;
     
    526526// Construct the processor context of non-main processors
    527527static void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info) {
    528         (this.self){ info };
     528        (this.__cor){ info };
    529529        this.proc = proc;
    530530}
     
    578578}
    579579
    580 void ?{}(processor & this, const char name[], cluster & _cltr, thread$ * initT) libcfa_public {
     580void ?{}(processor & this, const char name[], cluster & _cltr, thread$ * initT) {
    581581        ( this.terminated ){};
    582582        ( this.runner ){};
     
    591591}
    592592
    593 void ?{}(processor & this, const char name[], cluster & _cltr) libcfa_public {
     593void ?{}(processor & this, const char name[], cluster & _cltr) {
    594594        (this){name, _cltr, 0p};
    595595}
    596596
    597597extern size_t __page_size;
    598 void ^?{}(processor & this) libcfa_public with( this ) {
     598void ^?{}(processor & this) with( this ){
    599599        /* paranoid */ verify( !__atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE) );
    600600        __cfadbg_print_safe(runtime_core, "Kernel : core %p signaling termination\n", &this);
     
    623623}
    624624
    625 void ?{}(cluster & this, const char name[], Duration preemption_rate, unsigned num_io, const io_context_params & io_params) libcfa_public with( this ) {
     625void ?{}(cluster & this, const char name[], Duration preemption_rate, unsigned num_io, const io_context_params & io_params) with( this ) {
    626626        this.name = name;
    627627        this.preemption_rate = preemption_rate;
     
    658658}
    659659
    660 void ^?{}(cluster & this) libcfa_public {
     660void ^?{}(cluster & this) {
    661661        destroy(this.io.arbiter);
    662662
  • libcfa/src/concurrency/locks.cfa

    re5d9274 r015925a  
    2424#include <stdlib.hfa>
    2525
    26 #pragma GCC visibility push(default)
    27 
    2826//-----------------------------------------------------------------------------
    2927// info_thread
     
    118116}
    119117
    120 static void pop_and_set_new_owner( blocking_lock & this ) with( this ) {
     118void pop_and_set_new_owner( blocking_lock & this ) with( this ) {
    121119        thread$ * t = &try_pop_front( blocked_threads );
    122120        owner = t;
     
    266264        void ^?{}( alarm_node_wrap(L) & this ) { }
    267265
    268         static void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) {
     266        void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) {
    269267                // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin.
    270268                lock( cond->lock __cfaabi_dbg_ctx2 );
     
    290288
    291289        // this casts the alarm node to our wrapped type since we used type erasure
    292         static void alarm_node_wrap_cast( alarm_node_t & a ) { timeout_handler( (alarm_node_wrap(L) &)a ); }
     290        void alarm_node_wrap_cast( alarm_node_t & a ) { timeout_handler( (alarm_node_wrap(L) &)a ); }
    293291}
    294292
     
    307305        void ^?{}( condition_variable(L) & this ){ }
    308306
    309         static void process_popped( condition_variable(L) & this, info_thread(L) & popped ) with( this ) {
     307        void process_popped( condition_variable(L) & this, info_thread(L) & popped ) with( this ) {
    310308                if(&popped != 0p) {
    311309                        popped.signalled = true;
     
    352350        int counter( condition_variable(L) & this ) with(this) { return count; }
    353351
    354         static size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) {
     352        size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) {
    355353                // add info_thread to waiting queue
    356354                insert_last( blocked_threads, *i );
     
    365363
    366364        // helper for wait()'s' with no timeout
    367         static void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) {
     365        void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) {
    368366                lock( lock __cfaabi_dbg_ctx2 );
    369367                size_t recursion_count = queue_and_get_recursion(this, &i);
     
    382380
    383381        // helper for wait()'s' with a timeout
    384         static void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) {
     382        void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) {
    385383                lock( lock __cfaabi_dbg_ctx2 );
    386384                size_t recursion_count = queue_and_get_recursion(this, &info);
     
    417415        // fast_cond_var
    418416        void  ?{}( fast_cond_var(L) & this ){
    419                 this.blocked_threads{};
     417                this.blocked_threads{}; 
    420418                #ifdef __CFA_DEBUG__
    421419                this.lock_used = 0p;
  • libcfa/src/concurrency/monitor.cfa

    re5d9274 r015925a  
    4444static inline void restore( monitor$ * ctx [], __lock_size_t count, __spinlock_t * locks [], unsigned int /*in */ recursions [], __waitfor_mask_t /*in */ masks [] );
    4545
    46 static inline void ?{}(__condition_node_t & this, thread$ * waiting_thread, __lock_size_t count, uintptr_t user_info );
    47 static inline void ?{}(__condition_criterion_t & this );
    48 static inline void ?{}(__condition_criterion_t & this, monitor$ * target, __condition_node_t * owner );
    49 
    5046static inline void init     ( __lock_size_t count, monitor$ * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] );
    5147static inline void init_push( __lock_size_t count, monitor$ * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] );
     
    247243
    248244// Leave single monitor
    249 static void __leave( monitor$ * this ) {
     245void __leave( monitor$ * this ) {
    250246        // Lock the monitor spinlock
    251247        lock( this->lock __cfaabi_dbg_ctx2 );
     
    282278
    283279// Leave single monitor for the last time
    284 static void __dtor_leave( monitor$ * this, bool join ) {
     280void __dtor_leave( monitor$ * this, bool join ) {
    285281        __cfaabi_dbg_debug_do(
    286282                if( active_thread() != this->owner ) {
     
    348344// Ctor for monitor guard
    349345// Sorts monitors before entering
    350 void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count, fptr_t func ) libcfa_public {
     346void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count, fptr_t func ) {
    351347        thread$ * thrd = active_thread();
    352348
     
    373369}
    374370
    375 void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count ) libcfa_public {
     371void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count ) {
    376372        this{ m, count, 0p };
    377373}
     
    379375
    380376// Dtor for monitor guard
    381 void ^?{}( monitor_guard_t & this ) libcfa_public {
     377void ^?{}( monitor_guard_t & this ) {
    382378        // __cfaabi_dbg_print_safe( "MGUARD : leaving %d\n", this.count);
    383379
     
    393389// Ctor for monitor guard
    394390// Sorts monitors before entering
    395 void ?{}( monitor_dtor_guard_t & this, monitor$ * m [], fptr_t func, bool join ) libcfa_public {
     391void ?{}( monitor_dtor_guard_t & this, monitor$ * m [], fptr_t func, bool join ) {
    396392        // optimization
    397393        thread$ * thrd = active_thread();
     
    413409
    414410// Dtor for monitor guard
    415 void ^?{}( monitor_dtor_guard_t & this ) libcfa_public {
     411void ^?{}( monitor_dtor_guard_t & this ) {
    416412        // Leave the monitors in order
    417413        __dtor_leave( this.m, this.join );
     
    423419//-----------------------------------------------------------------------------
    424420// Internal scheduling types
    425 static void ?{}(__condition_node_t & this, thread$ * waiting_thread, __lock_size_t count, uintptr_t user_info ) {
     421void ?{}(__condition_node_t & this, thread$ * waiting_thread, __lock_size_t count, uintptr_t user_info ) {
    426422        this.waiting_thread = waiting_thread;
    427423        this.count = count;
     
    430426}
    431427
    432 static void ?{}(__condition_criterion_t & this ) with( this ) {
     428void ?{}(__condition_criterion_t & this ) with( this ) {
    433429        ready  = false;
    434430        target = 0p;
     
    437433}
    438434
    439 static void ?{}(__condition_criterion_t & this, monitor$ * target, __condition_node_t & owner ) {
     435void ?{}(__condition_criterion_t & this, monitor$ * target, __condition_node_t & owner ) {
    440436        this.ready  = false;
    441437        this.target = target;
     
    446442//-----------------------------------------------------------------------------
    447443// Internal scheduling
    448 void wait( condition & this, uintptr_t user_info = 0 ) libcfa_public {
     444void wait( condition & this, uintptr_t user_info = 0 ) {
    449445        brand_condition( this );
    450446
     
    500496}
    501497
    502 bool signal( condition & this ) libcfa_public {
     498bool signal( condition & this ) {
    503499        if( is_empty( this ) ) { return false; }
    504500
     
    542538}
    543539
    544 bool signal_block( condition & this ) libcfa_public {
     540bool signal_block( condition & this ) {
    545541        if( !this.blocked.head ) { return false; }
    546542
     
    590586
    591587// Access the user_info of the thread waiting at the front of the queue
    592 uintptr_t front( condition & this ) libcfa_public {
     588uintptr_t front( condition & this ) {
    593589        verifyf( !is_empty(this),
    594590                "Attempt to access user data on an empty condition.\n"
     
    612608//              setup mask
    613609//              block
    614 void __waitfor_internal( const __waitfor_mask_t & mask, int duration ) libcfa_public {
     610void __waitfor_internal( const __waitfor_mask_t & mask, int duration ) {
    615611        // This statment doesn't have a contiguous list of monitors...
    616612        // Create one!
     
    998994// Can't be accepted since a mutex stmt is effectively an anonymous routine
    999995// Thus we do not need a monitor group
    1000 void lock( monitor$ * this ) libcfa_public {
     996void lock( monitor$ * this ) {
    1001997        thread$ * thrd = active_thread();
    1002998
     
    10501046// Leave routine for mutex stmt
    10511047// Is just a wrapper around __leave for the is_lock trait to see
    1052 void unlock( monitor$ * this ) libcfa_public { __leave( this ); }
     1048void unlock( monitor$ * this ) { __leave( this ); }
    10531049
    10541050// Local Variables: //
  • libcfa/src/concurrency/monitor.hfa

    re5d9274 r015925a  
    119119}
    120120
    121 // void ?{}(__condition_node_t & this, thread$ * waiting_thread, __lock_size_t count, uintptr_t user_info );
    122 // void ?{}(__condition_criterion_t & this );
    123 // void ?{}(__condition_criterion_t & this, monitor$ * target, __condition_node_t * owner );
     121void ?{}(__condition_node_t & this, thread$ * waiting_thread, __lock_size_t count, uintptr_t user_info );
     122void ?{}(__condition_criterion_t & this );
     123void ?{}(__condition_criterion_t & this, monitor$ * target, __condition_node_t * owner );
    124124
    125125struct condition {
  • libcfa/src/concurrency/preemption.cfa

    re5d9274 r015925a  
    3838#endif
    3939
    40 __attribute__((weak)) Duration default_preemption() libcfa_public {
     40__attribute__((weak)) Duration default_preemption() {
    4141        const char * preempt_rate_s = getenv("CFA_DEFAULT_PREEMPTION");
    4242        if(!preempt_rate_s) {
     
    238238//----------
    239239// special case for preemption since used often
    240 __attribute__((optimize("no-reorder-blocks"))) bool __preemption_enabled() libcfa_public {
     240__attribute__((optimize("no-reorder-blocks"))) bool __preemption_enabled() {
    241241        // create a assembler label before
    242242        // marked as clobber all to avoid movement
     
    276276// Get data from the TLS block
    277277// struct asm_region __cfaasm_get;
    278 uintptr_t __cfatls_get( unsigned long int offset ) __attribute__((__noinline__, visibility("default"))); //no inline to avoid problems
     278uintptr_t __cfatls_get( unsigned long int offset ) __attribute__((__noinline__)); //no inline to avoid problems
    279279uintptr_t __cfatls_get( unsigned long int offset ) {
    280280        // create a assembler label before
     
    295295extern "C" {
    296296        // Disable interrupts by incrementing the counter
    297         __attribute__((__noinline__, visibility("default"))) void disable_interrupts() libcfa_public {
     297        void disable_interrupts() {
    298298                // create a assembler label before
    299299                // marked as clobber all to avoid movement
     
    326326        // Enable interrupts by decrementing the counter
    327327        // If counter reaches 0, execute any pending __cfactx_switch
    328         void enable_interrupts( bool poll ) libcfa_public {
     328        void enable_interrupts( bool poll ) {
    329329                // Cache the processor now since interrupts can start happening after the atomic store
    330330                processor   * proc = __cfaabi_tls.this_processor;
     
    362362//-----------------------------------------------------------------------------
    363363// Kernel Signal Debug
    364 void __cfaabi_check_preemption() libcfa_public {
     364void __cfaabi_check_preemption() {
    365365        bool ready = __preemption_enabled();
    366366        if(!ready) { abort("Preemption should be ready"); }
  • libcfa/src/concurrency/ready_queue.cfa

    re5d9274 r015925a  
    125125        const unsigned long long ctsc = rdtscl();
    126126
    127         if(proc->rdq.target == UINT_MAX) {
     127        if(proc->rdq.target == MAX) {
    128128                uint64_t chaos = __tls_rand();
    129129                unsigned ext = chaos & 0xff;
     
    137137                const unsigned target = proc->rdq.target;
    138138                __cfadbg_print_safe(ready_queue, "Kernel : %u considering helping %u, tcsc %llu\n", this, target, readyQ.tscs[target].tv);
    139                 /* paranoid */ verify( readyQ.tscs[target].tv != ULLONG_MAX );
     139                /* paranoid */ verify( readyQ.tscs[target].tv != MAX );
    140140                if(target < lanes_count) {
    141141                        const unsigned long long cutoff = calc_cutoff(ctsc, proc->rdq.id, lanes_count, cltr->sched.readyQ.data, cltr->sched.readyQ.tscs, __shard_factor.readyq);
     
    147147                        }
    148148                }
    149                 proc->rdq.target = UINT_MAX;
     149                proc->rdq.target = MAX;
    150150        }
    151151
     
    245245// get preferred ready for new thread
    246246unsigned ready_queue_new_preferred() {
    247         unsigned pref = UINT_MAX;
     247        unsigned pref = MAX;
    248248        if(struct thread$ * thrd = publicTLS_get( this_thread )) {
    249249                pref = thrd->preferred;
  • libcfa/src/concurrency/ready_subqueue.hfa

    re5d9274 r015925a  
    3232        /* paranoid */ verify( this.lock );
    3333        /* paranoid */ verify( node->link.next == 0p );
    34         /* paranoid */ verify( __atomic_load_n(&node->link.ts, __ATOMIC_RELAXED) == MAX  );
     34        /* paranoid */ verify( node->link.ts  == MAX  );
    3535        /* paranoid */ verify( this.prev->link.next == 0p );
    36         /* paranoid */ verify( __atomic_load_n(&this.prev->link.ts, __ATOMIC_RELAXED)   == MAX  );
     36        /* paranoid */ verify( this.prev->link.ts   == MAX  );
    3737        if( this.anchor.next == 0p ) {
    3838                /* paranoid */ verify( this.anchor.next == 0p );
    39                 /* paranoid */ verify( __atomic_load_n(&this.anchor.ts, __ATOMIC_RELAXED) == MAX );
    40                 /* paranoid */ verify( __atomic_load_n(&this.anchor.ts, __ATOMIC_RELAXED) != 0  );
     39                /* paranoid */ verify( this.anchor.ts  == MAX );
     40                /* paranoid */ verify( this.anchor.ts  != 0  );
    4141                /* paranoid */ verify( this.prev == mock_head( this ) );
    4242        } else {
    4343                /* paranoid */ verify( this.anchor.next != 0p );
    44                 /* paranoid */ verify( __atomic_load_n(&this.anchor.ts, __ATOMIC_RELAXED) != MAX );
    45                 /* paranoid */ verify( __atomic_load_n(&this.anchor.ts, __ATOMIC_RELAXED) != 0  );
     44                /* paranoid */ verify( this.anchor.ts  != MAX );
     45                /* paranoid */ verify( this.anchor.ts  != 0  );
    4646                /* paranoid */ verify( this.prev != mock_head( this ) );
    4747        }
     
    6262        /* paranoid */ verify( this.lock );
    6363        /* paranoid */ verify( this.anchor.next != 0p );
    64         /* paranoid */ verify( __atomic_load_n(&this.anchor.ts, __ATOMIC_RELAXED) != MAX );
    65         /* paranoid */ verify( __atomic_load_n(&this.anchor.ts, __ATOMIC_RELAXED) != 0   );
     64        /* paranoid */ verify( this.anchor.ts  != MAX );
     65        /* paranoid */ verify( this.anchor.ts   != 0  );
    6666
    6767        // Get the relevant nodes locally
    6868        thread$ * node = this.anchor.next;
    6969        this.anchor.next = node->link.next;
    70         __atomic_store_n(&this.anchor.ts, __atomic_load_n(&node->link.ts, __ATOMIC_RELAXED), __ATOMIC_RELAXED);
     70        this.anchor.ts   = node->link.ts;
    7171        bool is_empty = this.anchor.next == 0p;
    7272        node->link.next = 0p;
    73         __atomic_store_n(&node->link.ts, ULLONG_MAX, __ATOMIC_RELAXED);
     73        node->link.ts   = MAX;
    7474        #if !defined(__CFA_NO_STATISTICS__)
    7575                this.cnt--;
     
    7979        if(is_empty) this.prev = mock_head( this );
    8080
    81         unsigned long long ats = __atomic_load_n(&this.anchor.ts, __ATOMIC_RELAXED);
    8281        /* paranoid */ verify( node->link.next == 0p );
    83         /* paranoid */ verify( __atomic_load_n(&node->link.ts , __ATOMIC_RELAXED) == MAX );
    84         /* paranoid */ verify( __atomic_load_n(&node->link.ts , __ATOMIC_RELAXED) != 0   );
    85         /* paranoid */ verify( ats != 0 );
    86         /* paranoid */ verify( (ats == MAX) == is_empty );
    87         return [node, ats];
     82        /* paranoid */ verify( node->link.ts   == MAX );
     83        /* paranoid */ verify( node->link.ts   != 0  );
     84        /* paranoid */ verify( this.anchor.ts  != 0 );
     85        /* paranoid */ verify( (this.anchor.ts == MAX) == is_empty );
     86        return [node, this.anchor.ts];
    8887}
    8988
     
    9796        // Cannot verify 'emptiness' here since it may not be locked
    9897        /* paranoid */ verify(this.anchor.ts != 0);
    99         /* paranoid */ static_assert(__atomic_always_lock_free(sizeof(this.anchor.ts), &this.anchor.ts));
    100         return __atomic_load_n(&this.anchor.ts, __ATOMIC_RELAXED);
     98        return this.anchor.ts;
    10199}
  • libcfa/src/concurrency/thread.cfa

    re5d9274 r015925a  
    1919#include "thread.hfa"
    2020
     21#include "kernel/private.hfa"
    2122#include "exception.hfa"
    22 #include "kernel/private.hfa"
    23 #include "limits.hfa"
    2423
    2524#define __CFA_INVOKE_PRIVATE__
     
    2726
    2827extern uint32_t __global_random_seed, __global_random_prime, __global_random_mask;
    29 
    30 #pragma GCC visibility push(default)
    3128
    3229//-----------------------------------------------------------------------------
     
    4542        curr_cluster = &cl;
    4643        link.next = 0p;
    47         link.ts   = MAX;
     44        link.ts   = -1llu;
    4845        preferred = ready_queue_new_preferred();
    4946        last_proc = 0p;
     
    9087}
    9188
    92 forall(T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled(T))
    93     | { EHM_DEFAULT_VTABLE(ThreadCancelled(T)); })
     89forall(T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T))
     90    | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); })
    9491void ?{}( thread_dtor_guard_t & this,
    9592                T & thrd, void(*cancelHandler)(ThreadCancelled(T) &)) {
     
    169166
    170167//-----------------------------------------------------------------------------
    171 forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled(T))
    172         | { EHM_DEFAULT_VTABLE(ThreadCancelled(T)); })
     168forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T))
     169    | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); })
    173170T & join( T & this ) {
    174171        thread_dtor_guard_t guard = { this, defaultResumptionHandler };
  • libcfa/src/concurrency/thread.hfa

    re5d9274 r015925a  
    3232};
    3333
    34 forall(thread_t &)
    35 exception ThreadCancelled {
     34EHM_FORALL_EXCEPTION(ThreadCancelled, (thread_t &), (thread_t)) (
    3635        thread_t * the_thread;
    3736        exception_t * the_exception;
    38 };
     37);
    3938
    4039forall(T &)
     
    8079};
    8180
    82 forall( T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled(T))
    83         | { EHM_DEFAULT_VTABLE(ThreadCancelled(T)); })
     81forall( T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T))
     82    | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); })
    8483void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(ThreadCancelled(T) &) );
    8584void ^?{}( thread_dtor_guard_t & this );
     
    127126//----------
    128127// join
    129 forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled(T))
    130         | { EHM_DEFAULT_VTABLE(ThreadCancelled(T)); })
     128forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T))
     129    | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); })
    131130T & join( T & this );
    132131
  • libcfa/src/containers/maybe.cfa

    re5d9274 r015925a  
    1717#include <assert.h>
    1818
    19 #pragma GCC visibility push(default)
    2019
    2120forall(T)
  • libcfa/src/containers/result.cfa

    re5d9274 r015925a  
    1717#include <assert.h>
    1818
    19 #pragma GCC visibility push(default)
    2019
    2120forall(T, E)
  • libcfa/src/containers/string.cfa

    re5d9274 r015925a  
    1818#include <stdlib.hfa>
    1919
    20 #pragma GCC visibility push(default)
    2120
    2221/*
  • libcfa/src/containers/string_sharectx.hfa

    re5d9274 r015925a  
    1616#pragma once
    1717
    18 #pragma GCC visibility push(default)
    19 
    2018//######################### String Sharing Context #########################
    2119
    2220struct VbyteHeap;
    2321
    24 // A string_sharectx
     22// A string_sharectx 
    2523//
    2624// Usage:
  • libcfa/src/containers/vector.cfa

    re5d9274 r015925a  
    1818#include <stdlib.hfa>
    1919
    20 #pragma GCC visibility push(default)
    21 
    2220forall(T, allocator_t | allocator_c(T, allocator_t))
    23 static void copy_internal(vector(T, allocator_t)* this, vector(T, allocator_t)* other);
     21void copy_internal(vector(T, allocator_t)* this, vector(T, allocator_t)* other);
    2422
    2523//------------------------------------------------------------------------------
     
    8583
    8684forall(T, allocator_t | allocator_c(T, allocator_t))
    87 static void copy_internal(vector(T, allocator_t)* this, vector(T, allocator_t)* other)
     85void copy_internal(vector(T, allocator_t)* this, vector(T, allocator_t)* other)
    8886{
    8987        this->size = other->size;
  • libcfa/src/device/cpu.cfa

    re5d9274 r015925a  
    3131}
    3232
    33 #include "bits/defs.hfa"
    3433#include "algorithms/range_iterator.hfa"
    3534
     
    457456}
    458457
    459 libcfa_public cpu_info_t cpu_info;
     458cpu_info_t cpu_info;
  • libcfa/src/exception.c

    re5d9274 r015925a  
    2727#include "stdhdr/assert.h"
    2828#include "virtual.h"
    29 
    30 #pragma GCC visibility push(default)
    31 
    3229#include "lsda.h"
    3330
     
    264261#else // defined( __ARM_ARCH )
    265262        // The return code from _Unwind_RaiseException seems to be corrupt on ARM at end of stack.
    266         // This workaround tries to keep default exception handling working.
     263        // This workaround tries to keep default exception handling working. 
    267264        if ( ret == _URC_FATAL_PHASE1_ERROR || ret == _URC_FATAL_PHASE2_ERROR ) {
    268265#endif
  • libcfa/src/exception.hfa

    re5d9274 r015925a  
    1010// Created On       : Thu Apr  7 10:25:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed May 25 17:20:00 2022
    13 // Update Count     : 5
     12// Last Modified On : Thr Apr  8 15:16:00 2021
     13// Update Count     : 4
    1414//
    1515
     
    1818// -----------------------------------------------------------------------------------------------
    1919
    20 // EHM_DEFAULT_VTABLE(exception_type)
     20// EHM_EXCEPTION(exception_name)(fields...);
     21// Create an exception (a virtual structure that inherits from exception_t)
     22// with the given name and fields.
     23#define EHM_EXCEPTION(exception_name) \
     24        _EHM_TYPE_ID_STRUCT(exception_name, ); \
     25        _EHM_TYPE_ID_VALUE(exception_name, ); \
     26        _EHM_VIRTUAL_TABLE_STRUCT(exception_name, , ); \
     27        _EHM_EXCEPTION_STRUCT(exception_name, , )
     28
     29// EHM_EXTERN_VTABLE(exception_name, table_name);
     30// Forward declare a virtual table called table_name for exception_name type.
     31#define EHM_EXTERN_VTABLE(exception_name, table_name) \
     32        _EHM_EXTERN_VTABLE(exception_name, , table_name)
     33
     34// EHM_VIRTUAL_TABLE(exception_name, table_name);
     35// Define a virtual table called table_name for exception_name type.
     36#define EHM_VIRTUAL_TABLE(exception_name, table_name) \
     37        _EHM_DEFINE_COPY(exception_name, ) \
     38        _EHM_DEFINE_MSG(exception_name, ) \
     39        _EHM_VIRTUAL_TABLE(exception_name, , table_name)
     40
     41// EHM_FORALL_EXCEPTION(exception_name, (assertions), (parameters))(fields...);
     42// As EHM_EXCEPTION but for polymorphic types instead of monomorphic ones.
     43// The assertions list should include all polymorphic parameters and
     44// assertions inside a parentisized list. Parameters should include all the
     45// polymorphic parameter names inside a parentisized list (same order).
     46#define EHM_FORALL_EXCEPTION(exception_name, assertions, parameters) \
     47        _EHM_TYPE_ID_STRUCT(exception_name, forall assertions); \
     48        _EHM_VIRTUAL_TABLE_STRUCT(exception_name, forall assertions, parameters); \
     49        _EHM_EXCEPTION_STRUCT(exception_name, forall assertions, parameters)
     50
     51// EHM_FORALL_EXTERN_VTABLE(exception_name, (arguments), table_name);
     52// As EHM_EXTERN_VTABLE but for polymorphic types instead of monomorphic ones.
     53// Arguments should be the parentisized list of polymorphic arguments.
     54#define EHM_FORALL_EXTERN_VTABLE(exception_name, arguments, table_name) \
     55        _EHM_EXTERN_VTABLE(exception_name, arguments, table_name)
     56
     57// EHM_FORALL_VIRTUAL_TABLE(exception_name, (arguments), table_name);
     58// As EHM_VIRTUAL_TABLE but for polymorphic types instead of monomorphic ones.
     59// Arguments should be the parentisized list of polymorphic arguments.
     60#define EHM_FORALL_VIRTUAL_TABLE(exception_name, arguments, table_name) \
     61        _EHM_TYPE_ID_VALUE(exception_name, arguments); \
     62        _EHM_DEFINE_COPY(exception_name, arguments) \
     63        _EHM_DEFINE_MSG(exception_name, arguments) \
     64        _EHM_VIRTUAL_TABLE(exception_name, arguments, table_name)
     65
     66// EHM_DEFAULT_VTABLE(exception_name, (arguments))
    2167// Create a declaration for a (possibly polymorphic) default vtable.
    22 // Mostly used by and for the currency module.
    23 #define EHM_DEFAULT_VTABLE(type) vtable(type) & const _default_vtable
     68#define EHM_DEFAULT_VTABLE(exception_name, arguments) \
     69        _EHM_VTABLE_TYPE(exception_name) arguments & const _default_vtable
    2470
    25 // IS_EXCEPTION(exception_type)
    26 // IS_RESUMPTION_EXCEPTION(exception_type)
    27 // IS_TERMINATION_EXCEPTION(exception_type)
    28 // Create an assertion that exception_type is the given kind of exception.
    29 // This is used to mimic associated types so the vtable type is unmentioned.
    30 #define IS_EXCEPTION(type) is_exception(type, vtable(type))
    31 #define IS_RESUMPTION_EXCEPTION(type) is_resumption_exception(type, vtable(type))
    32 #define IS_TERMINATION_EXCEPTION(type) is_termination_exception(type, vtable(type))
     71// IS_EXCEPTION(exception_name [, (...parameters)])
     72// IS_RESUMPTION_EXCEPTION(exception_name [, (parameters...)])
     73// IS_TERMINATION_EXCEPTION(exception_name [, (parameters...)])
     74// Create an assertion that exception_name, possibly with the qualifing parameters, is the given
     75// kind of exception with the standard vtable with the same parameters if applicable.
     76#define IS_EXCEPTION(...) _IS_EXCEPTION(is_exception, __VA_ARGS__, , ~)
     77#define IS_RESUMPTION_EXCEPTION(...) _IS_EXCEPTION(is_resumption_exception, __VA_ARGS__, , ~)
     78#define IS_TERMINATION_EXCEPTION(...) _IS_EXCEPTION(is_termination_exception, __VA_ARGS__, , ~)
     79
     80// Macros starting with a leading underscore are internal.
     81
     82// Create an exception type definition. must be tailing, can be polymorphic.
     83#define _EHM_EXCEPTION_STRUCT(exception_name, forall_clause, parameters) \
     84        forall_clause struct exception_name { \
     85                _EHM_VTABLE_TYPE(exception_name) parameters const * virtual_table; \
     86                _CLOSE
     87
     88// Create a (possibly polymorphic) virtual table forward declaration.
     89#define _EHM_EXTERN_VTABLE(exception_name, arguments, table_name) \
     90        extern const _EHM_VTABLE_TYPE(exception_name) arguments table_name
     91
     92// Create a (possibly polymorphic) virtual table definition.
     93#define _EHM_VIRTUAL_TABLE(exception_type, arguments, table_name) \
     94        const _EHM_VTABLE_TYPE(exception_type) arguments table_name @= { \
     95                .__cfavir_typeid : &_EHM_TYPE_ID_NAME(exception_type), \
     96                .size : sizeof(struct exception_type arguments), \
     97                .copy : copy, \
     98                .^?{} : ^?{}, \
     99                .msg : msg, \
     100        }
     101
     102// Create a (possibly polymorphic) copy function from an assignment operator.
     103#define _EHM_DEFINE_FORALL_COPY(exception_name, forall_clause, parameters) \
     104        forall_clause void copy(exception_name parameters * this, \
     105                        exception_name parameters * that) { \
     106                *this = *that; \
     107        }
     108
     109#define _EHM_DEFINE_COPY(exception_name, arguments) \
     110        void copy(exception_name arguments * this, exception_name arguments * that) { \
     111                *this = *that; \
     112        }
     113
     114// Create a (possibly polymorphic) msg function
     115#define _EHM_DEFINE_FORALL_MSG(exception_name, forall_clause, parameters) \
     116        forall_clause const char * msg(exception_name parameters * this) { \
     117                return #exception_name #parameters; \
     118        }
     119
     120#define _EHM_DEFINE_MSG(exception_name, arguments) \
     121        const char * msg(exception_name arguments * this) { \
     122                return #exception_name #arguments; \
     123        }
     124
     125// Produces the C compatable name of the virtual table type for a virtual type.
     126#define _EHM_VTABLE_TYPE(type_name) struct _GLUE2(type_name,_vtable)
     127
     128// Create the vtable type for exception name.
     129#define _EHM_VIRTUAL_TABLE_STRUCT(exception_name, forall_clause, parameters) \
     130        forall_clause struct exception_name; \
     131        forall_clause _EHM_VTABLE_TYPE(exception_name) { \
     132                _EHM_TYPE_ID_TYPE(exception_name) parameters const * __cfavir_typeid; \
     133                size_t size; \
     134                void (*copy)(exception_name parameters * this, exception_name parameters * other); \
     135                void (*^?{})(exception_name parameters & this); \
     136                const char * (*msg)(exception_name parameters * this); \
     137        }
     138
     139// Define the function required to satify the trait for exceptions.
     140#define _EHM_TRAIT_FUNCTION(exception_name, forall_clause, parameters) \
     141        forall_clause inline void mark_exception( \
     142                exception_name parameters const &, \
     143                _EHM_VTABLE_TYPE(exception_name) parameters const &) {} \
     144
     145#define __EHM_TRAIT_FUNCTION(exception_name, forall_clause, parameters) \
     146        forall_clause inline _EHM_VTABLE_TYPE(exception_name) parameters const & \
     147                        get_exception_vtable(exception_name parameters const & this) { \
     148                /* This comes before the structure definition, but we know the offset. */ \
     149                /* return (_EHM_VTABLE_TYPE(exception_name) parameters const &)this; */ \
     150                assert(false); \
     151        }
     152
     153// Generates a new type-id structure. This is used to mangle the name of the
     154// type-id instance so it also includes polymorphic information. Must be the
     155// direct decendent of exception_t.
     156// The second field is used to recover type information about the exception.
     157#define _EHM_TYPE_ID_STRUCT(exception_name, forall_clause) \
     158        forall_clause _EHM_TYPE_ID_TYPE(exception_name) { \
     159                __cfavir_type_info const * parent; \
     160        }
     161
     162// Generate a new type-id value.
     163#define _EHM_TYPE_ID_VALUE(exception_name, arguments) \
     164        __attribute__((cfa_linkonce)) \
     165        _EHM_TYPE_ID_TYPE(exception_name) arguments const \
     166                        _EHM_TYPE_ID_NAME(exception_name) = { \
     167                &__cfatid_exception_t, \
     168        }
     169
     170// _EHM_TYPE_ID_STRUCT and _EHM_TYPE_ID_VALUE are the two that would need to
     171// be updated to extend the hierarchy if we are still using macros when that
     172// is added.
     173
     174// Produce the C compatable name of the type-id type for an exception type.
     175#define _EHM_TYPE_ID_TYPE(exception_name) \
     176        struct _GLUE2(__cfatid_struct_, exception_name)
     177
     178// Produce the name of the instance of the type-id for an exception type.
     179#define _EHM_TYPE_ID_NAME(exception_name) _GLUE2(__cfatid_,exception_name)
     180
     181#define _IS_EXCEPTION(kind, exception_name, parameters, ...) \
     182        kind(exception_name parameters, _EHM_VTABLE_TYPE(exception_name) parameters)
     183
     184// Internal helper macros:
     185#define _CLOSE(...) __VA_ARGS__ }
     186#define _GLUE2(left, right) left##right
  • libcfa/src/fstream.cfa

    re5d9274 r015925a  
    2222#include <assert.h>
    2323#include <errno.h>                                                                              // errno
    24 
    25 #pragma GCC visibility push(default)
    2624
    2725// *********************************** ofstream ***********************************
     
    120118                // abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno );
    121119        } // if
    122         (os){ file };                                                                           // initialize
     120        (os){ file };                                                                           // initialize 
    123121} // open
    124122
     
    159157        va_list args;
    160158        va_start( args, format );
    161 
     159               
    162160        int len;
    163161    for ( cnt; 10 ) {
     
    243241                // abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno );
    244242        } // if
    245         (is){ file };                                                                           // initialize
     243        (is){ file };                                                                           // initialize 
    246244} // open
    247245
  • libcfa/src/fstream.hfa

    re5d9274 r015925a  
    1818#include "bits/weakso_locks.hfa"                                                // mutex_lock
    1919#include "iostream.hfa"
     20#include <exception.hfa>
    2021
    2122
  • libcfa/src/heap.cfa

    re5d9274 r015925a  
    3636static bool traceHeap = false;
    3737
    38 inline bool traceHeap() libcfa_public { return traceHeap; }
    39 
    40 bool traceHeapOn() libcfa_public {
     38inline bool traceHeap() { return traceHeap; }
     39
     40bool traceHeapOn() {
    4141        bool temp = traceHeap;
    4242        traceHeap = true;
     
    4444} // traceHeapOn
    4545
    46 bool traceHeapOff() libcfa_public {
     46bool traceHeapOff() {
    4747        bool temp = traceHeap;
    4848        traceHeap = false;
     
    5050} // traceHeapOff
    5151
    52 bool traceHeapTerm() libcfa_public { return false; }
     52bool traceHeapTerm() { return false; }
    5353
    5454
    5555static bool prtFree = false;
    5656
    57 static bool prtFree() {
     57bool prtFree() {
    5858        return prtFree;
    5959} // prtFree
    6060
    61 static bool prtFreeOn() {
     61bool prtFreeOn() {
    6262        bool temp = prtFree;
    6363        prtFree = true;
     
    6565} // prtFreeOn
    6666
    67 static bool prtFreeOff() {
     67bool prtFreeOff() {
    6868        bool temp = prtFree;
    6969        prtFree = false;
     
    388388static unsigned int maxBucketsUsed;                                             // maximum number of buckets in use
    389389// extern visibility, used by runtime kernel
    390 // would be cool to remove libcfa_public but it's needed for libcfathread
    391 libcfa_public size_t __page_size;                                                       // architecture pagesize
    392 libcfa_public int __map_prot;                                                           // common mmap/mprotect protection
     390size_t __page_size;                                                                             // architecture pagesize
     391int __map_prot;                                                                                 // common mmap/mprotect protection
    393392
    394393
     
    728727
    729728
    730 static size_t prtFree( Heap & manager ) with( manager ) {
     729size_t prtFree( Heap & manager ) with( manager ) {
    731730        size_t total = 0;
    732731        #ifdef __STATISTICS__
     
    880879        // Allocates size bytes and returns a pointer to the allocated memory.  The contents are undefined. If size is 0,
    881880        // then malloc() returns a unique pointer value that can later be successfully passed to free().
    882         void * malloc( size_t size ) libcfa_public {
     881        void * malloc( size_t size ) {
    883882                #ifdef __STATISTICS__
    884883                if ( likely( size > 0 ) ) {
     
    895894
    896895        // Same as malloc() except size bytes is an array of dim elements each of elemSize bytes.
    897         void * aalloc( size_t dim, size_t elemSize ) libcfa_public {
     896        void * aalloc( size_t dim, size_t elemSize ) {
    898897                size_t size = dim * elemSize;
    899898                #ifdef __STATISTICS__
     
    911910
    912911        // Same as aalloc() with memory set to zero.
    913         void * calloc( size_t dim, size_t elemSize ) libcfa_public {
     912        void * calloc( size_t dim, size_t elemSize ) {
    914913                size_t size = dim * elemSize;
    915914          if ( unlikely( size ) == 0 ) {                        // 0 BYTE ALLOCATION RETURNS NULL POINTER
     
    952951        // not 0p, then the call is equivalent to free(oaddr). Unless oaddr is 0p, it must have been returned by an earlier
    953952        // call to malloc(), alloc(), calloc() or realloc(). If the area pointed to was moved, a free(oaddr) is done.
    954         void * resize( void * oaddr, size_t size ) libcfa_public {
     953        void * resize( void * oaddr, size_t size ) {
    955954                // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    956955          if ( unlikely( size == 0 ) ) {                                        // special cases
     
    997996        // Same as resize() but the contents are unchanged in the range from the start of the region up to the minimum of
    998997        // the old and new sizes.
    999         void * realloc( void * oaddr, size_t size ) libcfa_public {
     998        void * realloc( void * oaddr, size_t size ) {
    1000999                // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    10011000          if ( unlikely( size == 0 ) ) {                                        // special cases
     
    10611060
    10621061        // Same as realloc() except the new allocation size is large enough for an array of nelem elements of size elsize.
    1063         void * reallocarray( void * oaddr, size_t dim, size_t elemSize ) libcfa_public {
     1062        void * reallocarray( void * oaddr, size_t dim, size_t elemSize ) {
    10641063                return realloc( oaddr, dim * elemSize );
    10651064        } // reallocarray
     
    10671066
    10681067        // Same as malloc() except the memory address is a multiple of alignment, which must be a power of two. (obsolete)
    1069         void * memalign( size_t alignment, size_t size ) libcfa_public {
     1068        void * memalign( size_t alignment, size_t size ) {
    10701069                #ifdef __STATISTICS__
    10711070                if ( likely( size > 0 ) ) {
     
    10821081
    10831082        // Same as aalloc() with memory alignment.
    1084         void * amemalign( size_t alignment, size_t dim, size_t elemSize ) libcfa_public {
     1083        void * amemalign( size_t alignment, size_t dim, size_t elemSize ) {
    10851084                size_t size = dim * elemSize;
    10861085                #ifdef __STATISTICS__
     
    10981097
    10991098        // Same as calloc() with memory alignment.
    1100         void * cmemalign( size_t alignment, size_t dim, size_t elemSize ) libcfa_public {
     1099        void * cmemalign( size_t alignment, size_t dim, size_t elemSize ) {
    11011100                size_t size = dim * elemSize;
    11021101          if ( unlikely( size ) == 0 ) {                                        // 0 BYTE ALLOCATION RETURNS NULL POINTER
     
    11371136        // Same as memalign(), but ISO/IEC 2011 C11 Section 7.22.2 states: the value of size shall be an integral multiple
    11381137        // of alignment. This requirement is universally ignored.
    1139         void * aligned_alloc( size_t alignment, size_t size ) libcfa_public {
     1138        void * aligned_alloc( size_t alignment, size_t size ) {
    11401139                return memalign( alignment, size );
    11411140        } // aligned_alloc
     
    11461145        // is 0, then posix_memalign() returns either 0p, or a unique pointer value that can later be successfully passed to
    11471146        // free(3).
    1148         int posix_memalign( void ** memptr, size_t alignment, size_t size ) libcfa_public {
     1147        int posix_memalign( void ** memptr, size_t alignment, size_t size ) {
    11491148          if ( unlikely( alignment < libAlign() || ! is_pow2( alignment ) ) ) return EINVAL; // check alignment
    11501149                *memptr = memalign( alignment, size );
     
    11551154        // Allocates size bytes and returns a pointer to the allocated memory. The memory address shall be a multiple of the
    11561155        // page size.  It is equivalent to memalign(sysconf(_SC_PAGESIZE),size).
    1157         void * valloc( size_t size ) libcfa_public {
     1156        void * valloc( size_t size ) {
    11581157                return memalign( __page_size, size );
    11591158        } // valloc
     
    11611160
    11621161        // Same as valloc but rounds size to multiple of page size.
    1163         void * pvalloc( size_t size ) libcfa_public {
     1162        void * pvalloc( size_t size ) {
    11641163                return memalign( __page_size, ceiling2( size, __page_size ) ); // round size to multiple of page size
    11651164        } // pvalloc
     
    11691168        // or realloc().  Otherwise, or if free(ptr) has already been called before, undefined behaviour occurs. If ptr is
    11701169        // 0p, no operation is performed.
    1171         void free( void * addr ) libcfa_public {
     1170        void free( void * addr ) {
    11721171          if ( unlikely( addr == 0p ) ) {                                       // special case
    11731172                        #ifdef __STATISTICS__
     
    11901189
    11911190        // Returns the alignment of an allocation.
    1192         size_t malloc_alignment( void * addr ) libcfa_public {
     1191        size_t malloc_alignment( void * addr ) {
    11931192          if ( unlikely( addr == 0p ) ) return libAlign();      // minimum alignment
    11941193                Heap.Storage.Header * header = HeaderAddr( addr );
     
    12021201
    12031202        // Returns true if the allocation is zero filled, e.g., allocated by calloc().
    1204         bool malloc_zero_fill( void * addr ) libcfa_public {
     1203        bool malloc_zero_fill( void * addr ) {
    12051204          if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
    12061205                Heap.Storage.Header * header = HeaderAddr( addr );
     
    12131212
    12141213        // Returns original total allocation size (not bucket size) => array size is dimension * sizeof(T).
    1215         size_t malloc_size( void * addr ) libcfa_public {
     1214        size_t malloc_size( void * addr ) {
    12161215          if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has zero size
    12171216                Heap.Storage.Header * header = HeaderAddr( addr );
     
    12251224        // Returns the number of usable bytes in the block pointed to by ptr, a pointer to a block of memory allocated by
    12261225        // malloc or a related function.
    1227         size_t malloc_usable_size( void * addr ) libcfa_public {
     1226        size_t malloc_usable_size( void * addr ) {
    12281227          if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has 0 size
    12291228                Heap.Storage.Header * header;
     
    12371236
    12381237        // Prints (on default standard error) statistics about memory allocated by malloc and related functions.
    1239         void malloc_stats( void ) libcfa_public {
     1238        void malloc_stats( void ) {
    12401239                #ifdef __STATISTICS__
    12411240                printStats();
     
    12461245
    12471246        // Changes the file descriptor where malloc_stats() writes statistics.
    1248         int malloc_stats_fd( int fd __attribute__(( unused )) ) libcfa_public {
     1247        int malloc_stats_fd( int fd __attribute__(( unused )) ) {
    12491248                #ifdef __STATISTICS__
    12501249                int temp = stats_fd;
     
    12601259        // The string is printed on the file stream stream.  The exported string includes information about all arenas (see
    12611260        // malloc).
    1262         int malloc_info( int options, FILE * stream __attribute__(( unused )) ) libcfa_public {
     1261        int malloc_info( int options, FILE * stream __attribute__(( unused )) ) {
    12631262          if ( options != 0 ) { errno = EINVAL; return -1; }
    12641263                #ifdef __STATISTICS__
     
    12721271        // Adjusts parameters that control the behaviour of the memory-allocation functions (see malloc). The param argument
    12731272        // specifies the parameter to be modified, and value specifies the new value for that parameter.
    1274         int mallopt( int option, int value ) libcfa_public {
     1273        int mallopt( int option, int value ) {
    12751274          if ( value < 0 ) return 0;
    12761275                choose( option ) {
     
    12861285
    12871286        // Attempt to release free memory at the top of the heap (by calling sbrk with a suitable argument).
    1288         int malloc_trim( size_t ) libcfa_public {
     1287        int malloc_trim( size_t ) {
    12891288                return 0;                                                                               // => impossible to release memory
    12901289        } // malloc_trim
     
    12951294        // structure dynamically allocated via malloc, and a pointer to that data structure is returned as the function
    12961295        // result.  (The caller must free this memory.)
    1297         void * malloc_get_state( void ) libcfa_public {
     1296        void * malloc_get_state( void ) {
    12981297                return 0p;                                                                              // unsupported
    12991298        } // malloc_get_state
     
    13021301        // Restores the state of all malloc internal bookkeeping variables to the values recorded in the opaque data
    13031302        // structure pointed to by state.
    1304         int malloc_set_state( void * ) libcfa_public {
     1303        int malloc_set_state( void * ) {
    13051304                return 0;                                                                               // unsupported
    13061305        } // malloc_set_state
     
    13081307
    13091308        // Sets the amount (bytes) to extend the heap when there is insufficent free storage to service an allocation.
    1310         __attribute__((weak)) size_t malloc_expansion() libcfa_public { return __CFA_DEFAULT_HEAP_EXPANSION__; }
     1309        __attribute__((weak)) size_t malloc_expansion() { return __CFA_DEFAULT_HEAP_EXPANSION__; }
    13111310
    13121311        // Sets the crossover point between allocations occuring in the sbrk area or separately mmapped.
    1313         __attribute__((weak)) size_t malloc_mmap_start() libcfa_public { return __CFA_DEFAULT_MMAP_START__; }
     1312        __attribute__((weak)) size_t malloc_mmap_start() { return __CFA_DEFAULT_MMAP_START__; }
    13141313
    13151314        // Amount subtracted to adjust for unfreed program storage (debug only).
    1316         __attribute__((weak)) size_t malloc_unfreed() libcfa_public { return __CFA_DEFAULT_HEAP_UNFREED__; }
     1315        __attribute__((weak)) size_t malloc_unfreed() { return __CFA_DEFAULT_HEAP_UNFREED__; }
    13171316} // extern "C"
    13181317
    13191318
    13201319// Must have CFA linkage to overload with C linkage realloc.
    1321 void * resize( void * oaddr, size_t nalign, size_t size ) libcfa_public {
     1320void * resize( void * oaddr, size_t nalign, size_t size ) {
    13221321        // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    13231322  if ( unlikely( size == 0 ) ) {                                                // special cases
     
    13811380
    13821381
    1383 void * realloc( void * oaddr, size_t nalign, size_t size ) libcfa_public {
     1382void * realloc( void * oaddr, size_t nalign, size_t size ) {
    13841383        // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    13851384  if ( unlikely( size == 0 ) ) {                                                // special cases
  • libcfa/src/interpose.cfa

    re5d9274 r015925a  
    3636//=============================================================================================
    3737
    38 static void preload_libgcc(void) {
     38void preload_libgcc(void) {
    3939        dlopen( "libgcc_s.so.1", RTLD_NOW );
    4040        if ( const char * error = dlerror() ) abort( "interpose_symbol : internal error pre-loading libgcc, %s\n", error );
     
    4242
    4343typedef void (* generic_fptr_t)(void);
    44 static generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) {
     44generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) {
    4545        const char * error;
    4646
     
    8383//=============================================================================================
    8484
    85 static void sigHandler_segv( __CFA_SIGPARMS__ );
    86 static void sigHandler_ill ( __CFA_SIGPARMS__ );
    87 static void sigHandler_fpe ( __CFA_SIGPARMS__ );
    88 static void sigHandler_abrt( __CFA_SIGPARMS__ );
    89 static void sigHandler_term( __CFA_SIGPARMS__ );
    90 
    91 static struct {
     85void sigHandler_segv( __CFA_SIGPARMS__ );
     86void sigHandler_ill ( __CFA_SIGPARMS__ );
     87void sigHandler_fpe ( __CFA_SIGPARMS__ );
     88void sigHandler_abrt( __CFA_SIGPARMS__ );
     89void sigHandler_term( __CFA_SIGPARMS__ );
     90
     91struct {
    9292        void (* exit)( int ) __attribute__(( __noreturn__ ));
    9393        void (* abort)( void ) __attribute__(( __noreturn__ ));
    9494} __cabi_libc;
    9595
    96 libcfa_public int cfa_main_returned;
     96int cfa_main_returned;
    9797
    9898extern "C" {
     
    148148
    149149// Forward declare abort after the __typeof__ call to avoid ambiguities
    150 libcfa_public void exit( int status, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
    151 libcfa_public void abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ ));
    152 libcfa_public void abort( bool signalAbort, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
    153 libcfa_public void __abort( bool signalAbort, const char fmt[], va_list args ) __attribute__(( __nothrow__, __leaf__, __noreturn__ ));
     150void exit( int status, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
     151void abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ ));
     152void abort( bool signalAbort, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
     153void __abort( bool signalAbort, const char fmt[], va_list args ) __attribute__(( __nothrow__, __leaf__, __noreturn__ ));
    154154
    155155extern "C" {
    156         libcfa_public void abort( void ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {
     156        void abort( void ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {
    157157                abort( false, "%s", "" );
    158158        }
    159159
    160         libcfa_public void __cabi_abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ )) {
     160        void __cabi_abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ )) {
    161161                va_list argp;
    162162                va_start( argp, fmt );
     
    165165        }
    166166
    167         libcfa_public void exit( int status ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {
     167        void exit( int status ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {
    168168                __cabi_libc.exit( status );
    169169        }
  • libcfa/src/iostream.cfa

    re5d9274 r015925a  
    3232#include "bitmanip.hfa"                                                                 // high1
    3333
    34 #pragma GCC visibility push(default)
    3534
    3635// *********************************** ostream ***********************************
  • libcfa/src/limits.cfa

    re5d9274 r015925a  
    2020#include <complex.h>
    2121#include "limits.hfa"
    22 
    23 #pragma GCC visibility push(default)
    2422
    2523// Integral Constants
  • libcfa/src/memory.cfa

    re5d9274 r015925a  
    1616#include "memory.hfa"
    1717#include "stdlib.hfa"
    18 
    19 #pragma GCC visibility push(default)
    2018
    2119// Internal data object.
  • libcfa/src/parseargs.cfa

    re5d9274 r015925a  
    2424#include "common.hfa"
    2525#include "limits.hfa"
    26 
    27 #pragma GCC visibility push(default)
    2826
    2927extern int cfa_args_argc __attribute__((weak));
  • libcfa/src/parseconfig.cfa

    re5d9274 r015925a  
    1414
    1515
    16 #pragma GCC visibility push(default)
    17 
    1816// *********************************** exceptions ***********************************
    1917
    2018
    2119// TODO: Add names of missing config entries to exception (see further below)
    22 vtable(Missing_Config_Entries) Missing_Config_Entries_vt;
     20static vtable(Missing_Config_Entries) Missing_Config_Entries_vt;
    2321
    2422[ void ] ?{}( & Missing_Config_Entries this, unsigned int num_missing ) {
     
    3331
    3432
    35 vtable(Parse_Failure) Parse_Failure_vt;
     33static vtable(Parse_Failure) Parse_Failure_vt;
    3634
    3735[ void ] ?{}( & Parse_Failure this, [] char failed_key, [] char failed_value ) {
     
    5553
    5654
    57 vtable(Validation_Failure) Validation_Failure_vt;
     55static vtable(Validation_Failure) Validation_Failure_vt;
    5856
    5957[ void ] ?{}( & Validation_Failure this, [] char failed_key, [] char failed_value ) {
     
    112110
    113111
    114 static [ bool ] comments( & ifstream in, [] char name ) {
     112[ bool ] comments( & ifstream in, [] char name ) {
    115113        while () {
    116114                in | name;
  • libcfa/src/rational.cfa

    re5d9274 r015925a  
    1717#include "fstream.hfa"
    1818#include "stdlib.hfa"
    19 
    20 #pragma GCC visibility push(default)
    2119
    2220forall( T | Arithmetic( T ) ) {
  • libcfa/src/startup.cfa

    re5d9274 r015925a  
    4141        } // __cfaabi_appready_shutdown
    4242
    43         void disable_interrupts() __attribute__(( weak )) libcfa_public {}
    44         void enable_interrupts() __attribute__(( weak )) libcfa_public {}
     43        void disable_interrupts() __attribute__(( weak )) {}
     44        void enable_interrupts() __attribute__(( weak )) {}
    4545
    4646
     
    6464struct __spinlock_t;
    6565extern "C" {
    66         void __cfaabi_dbg_record_lock(struct __spinlock_t & this, const char prev_name[]) __attribute__(( weak )) libcfa_public {}
     66        void __cfaabi_dbg_record_lock(struct __spinlock_t & this, const char prev_name[]) __attribute__(( weak )) {}
    6767}
    6868
  • libcfa/src/stdlib.cfa

    re5d9274 r015925a  
    2525#include <complex.h>                                                                    // _Complex_I
    2626#include <assert.h>
    27 
    28 #pragma GCC visibility push(default)
    2927
    3028//---------------------------------------
     
    227225#define GENERATOR LCG
    228226
    229 // would be cool to make hidden but it's needed for libcfathread
    230 __attribute__((visibility("default"))) uint32_t __global_random_seed;                                                   // sequential/concurrent
    231 __attribute__((visibility("hidden"))) uint32_t __global_random_state;                                                   // sequential only
     227uint32_t __global_random_seed;                                                  // sequential/concurrent
     228uint32_t __global_random_state;                                                 // sequential only
    232229
    233230void set_seed( PRNG & prng, uint32_t seed_ ) with( prng ) { state = seed = seed_; GENERATOR( state ); } // set seed
  • libcfa/src/strstream.cfa

    re5d9274 r015925a  
    1 //
     1// 
    22// Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo
    3 //
     3// 
    44// The contents of this file are covered under the licence agreement in the
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // strstream.cfa --
    8 //
     7// strstream.cfa -- 
     8// 
    99// Author           : Peter A. Buhr
    1010// Created On       : Thu Apr 22 22:24:35 2021
     
    1212// Last Modified On : Sun Oct 10 16:13:20 2021
    1313// Update Count     : 101
    14 //
     14// 
    1515
    1616#include "strstream.hfa"
     
    2424#include <unistd.h>                                                                             // sbrk, sysconf
    2525
    26 #pragma GCC visibility push(default)
    2726
    2827// *********************************** strstream ***********************************
  • libcfa/src/time.cfa

    re5d9274 r015925a  
    1818#include <stdio.h>                                                                              // snprintf
    1919#include <assert.h>
    20 
    21 #pragma GCC visibility push(default)
    2220
    2321static char * nanomsd( long int ns, char * buf ) {              // most significant digits
  • libcfa/src/virtual.c

    re5d9274 r015925a  
    1616#include "virtual.h"
    1717#include "assert.h"
    18 
    19 #pragma GCC visibility push(default)
    2018
    2119int __cfavir_is_parent(
  • src/AST/Expr.cpp

    re5d9274 r015925a  
    1010// Created On       : Wed May 15 17:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Created On       : Wed May 18 13:56:00 2022
    13 // Update Count     : 8
     12// Created On       : Tue Nov 30 14:23:00 2021
     13// Update Count     : 7
    1414//
    1515
     
    2121
    2222#include "Copy.hpp"                // for shallowCopy
     23#include "Eval.hpp"                // for call
    2324#include "GenericSubstitution.hpp"
    2425#include "LinkageSpec.hpp"
     
    6667// --- UntypedExpr
    6768
    68 bool UntypedExpr::get_lvalue() const {
    69         std::string fname = InitTweak::getFunctionName( this );
    70         return lvalueFunctionNames.count( fname );
    71 }
    72 
    7369UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, const Expr * arg ) {
    7470        assert( arg );
    7571
    76         UntypedExpr * ret = createCall( loc, "*?", { arg } );
     72        UntypedExpr * ret = call( loc, "*?", arg );
    7773        if ( const Type * ty = arg->result ) {
    7874                const Type * base = InitTweak::getPointerBase( ty );
     
    9187}
    9288
     89bool UntypedExpr::get_lvalue() const {
     90        std::string fname = InitTweak::getFunctionName( this );
     91        return lvalueFunctionNames.count( fname );
     92}
     93
    9394UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs ) {
    9495        assert( lhs && rhs );
    9596
    96         UntypedExpr * ret = createCall( loc, "?=?", { lhs, rhs } );
     97        UntypedExpr * ret = call( loc, "?=?", lhs, rhs );
    9798        if ( lhs->result && rhs->result ) {
    9899                // if both expressions are typed, assumes that this assignment is a C bitwise assignment,
     
    101102        }
    102103        return ret;
    103 }
    104 
    105 UntypedExpr * UntypedExpr::createCall( const CodeLocation & loc,
    106                 const std::string & name, std::vector<ptr<Expr>> && args ) {
    107         return new UntypedExpr( loc,
    108                         new NameExpr( loc, name ), std::move( args ) );
    109104}
    110105
  • src/AST/Expr.hpp

    re5d9274 r015925a  
    230230        /// Creates a new assignment expression
    231231        static UntypedExpr * createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs );
    232         /// Creates a new call of a variable.
    233         static UntypedExpr * createCall( const CodeLocation & loc,
    234                 const std::string & name, std::vector<ptr<Expr>> && args );
    235232
    236233        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/module.mk

    re5d9274 r015925a  
    2929        AST/DeclReplacer.cpp \
    3030        AST/DeclReplacer.hpp \
     31        AST/Eval.hpp \
    3132        AST/Expr.cpp \
    3233        AST/Expr.hpp \
  • src/CodeGen/CodeGenerator.cc

    re5d9274 r015925a  
    12381238} // namespace CodeGen
    12391239
     1240
     1241unsigned Indenter::tabsize = 2;
     1242
     1243std::ostream & operator<<( std::ostream & out, const BaseSyntaxNode * node ) {
     1244        if ( node ) {
     1245                node->print( out );
     1246        } else {
     1247                out << "nullptr";
     1248        }
     1249        return out;
     1250}
     1251
    12401252// Local Variables: //
    12411253// tab-width: 4 //
  • src/CodeGen/FixMain.cc

    re5d9274 r015925a  
    4949
    5050}
     51
     52        bool FixMain::replace_main = false;
    5153
    5254        template<typename container>
  • src/CodeGen/GenType.cc

    re5d9274 r015925a  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri May 20 11:18:00 2022
    13 // Update Count     : 24
     12// Last Modified On : Wed May  1 15:24:00 2019
     13// Update Count     : 23
    1414//
    1515#include "GenType.h"
     
    5050                void postvisit( TraitInstType * inst );
    5151                void postvisit( TypeofType * typeof );
    52                 void postvisit( VTableType * vtable );
    5352                void postvisit( QualifiedType * qualType );
    5453
     
    260259                        if ( options.genC ) {
    261260                                typeString = "enum " + typeString;
    262                         }
    263                 }
     261                        } 
     262                } 
    264263                handleQualifiers( enumInst );
    265264        }
    266265
    267266        void GenType::postvisit( TypeInstType * typeInst ) {
    268                 assertf( ! options.genC, "Type instance types should not reach code generation." );
    269267                typeString = typeInst->name + " " + typeString;
    270268                handleQualifiers( typeInst );
     
    322320        }
    323321
    324         void GenType::postvisit( VTableType * vtable ) {
    325                 assertf( ! options.genC, "Virtual table types should not reach code generation." );
    326                 std::ostringstream os;
    327                 os << "vtable(" << genType( vtable->base, "", options ) << ") " << typeString;
    328                 typeString = os.str();
    329                 handleQualifiers( vtable );
    330         }
    331 
    332322        void GenType::postvisit( QualifiedType * qualType ) {
    333323                assertf( ! options.genC, "Qualified types should not reach code generation." );
  • src/CodeGen/LinkOnce.cc

    re5d9274 r015925a  
    5353                                new ConstantExpr( Constant::from_string( section_name ) )
    5454                        );
    55 
    56                         // Unconditionnaly add "visibility(default)" to anything with gnu.linkonce
    57                         // visibility is a mess otherwise
    58                         attributes.push_back(new Attribute("visibility", {new ConstantExpr( Constant::from_string( "default" ) )}));
    59 
    6055                }
    6156                visit_children = false;
  • src/CodeGen/module.mk

    re5d9274 r015925a  
    1010## Author           : Richard C. Bilson
    1111## Created On       : Mon Jun  1 17:49:17 2015
    12 ## Last Modified By : Andrew Beach
    13 ## Last Modified On : Tue May 17 14:26:00 2022
    14 ## Update Count     : 5
     12## Last Modified By : Peter A. Buhr
     13## Last Modified On : Sat Dec 14 07:29:42 2019
     14## Update Count     : 4
    1515###############################################################################
    1616
     17#SRC +=  ArgTweak/Rewriter.cc \
     18#       ArgTweak/Mutate.cc
     19
    1720SRC_CODEGEN = \
    18         CodeGen/FixMain2.cc \
    19         CodeGen/FixMain.h \
    20         CodeGen/OperatorTable.cc \
    21         CodeGen/OperatorTable.h
    22 
    23 SRC += $(SRC_CODEGEN) \
    2421        CodeGen/CodeGenerator.cc \
    2522        CodeGen/CodeGenerator.h \
    26         CodeGen/Generate.cc \
    27         CodeGen/Generate.h \
    2823        CodeGen/FixMain.cc \
    29         CodeGen/FixNames.cc \
    30         CodeGen/FixNames.h \
     24        CodeGen/FixMain.h \
    3125        CodeGen/GenType.cc \
    3226        CodeGen/GenType.h \
    3327        CodeGen/LinkOnce.cc \
    3428        CodeGen/LinkOnce.h \
     29        CodeGen/OperatorTable.cc \
     30        CodeGen/OperatorTable.h \
    3531        CodeGen/Options.h
    3632
     33SRC += $(SRC_CODEGEN) CodeGen/Generate.cc CodeGen/Generate.h CodeGen/FixNames.cc CodeGen/FixNames.h
    3734SRCDEMANGLE += $(SRC_CODEGEN)
  • src/CodeTools/ResolvProtoDump.cc

    re5d9274 r015925a  
    304304
    305305                        // replace enums with int
    306                         void previsit( EnumInstType* ) {
    307                                 // TODO: add the meaningful representation of typed int
    308                                 ss << (int)BasicType::SignedInt;
    309                         }
     306                        void previsit( EnumInstType* ) { ss << (int)BasicType::SignedInt; }
    310307
    311308                        void previsit( TypeInstType* vt ) {
  • src/Common/Indenter.h

    re5d9274 r015925a  
    1010// Created On       : Fri Jun 30 16:55:23 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri May 13 14:10:00 2022
    13 // Update Count     : 2
     12// Last Modified On : Fri Aug 11 11:15:00 2017
     13// Update Count     : 1
    1414//
    1515
    16 #pragma once
    17 
    18 #include <ostream>
     16#ifndef INDENTER_H
     17#define INDENTER_H
    1918
    2019struct Indenter {
     
    3837        return out << std::string(indent.indent * indent.amt, ' ');
    3938}
     39
     40#endif // INDENTER_H
  • src/Common/ResolvProtoDump.cpp

    re5d9274 r015925a  
    227227        }
    228228
    229         void previsit( const ast::EnumInstType * enumInst) {
    230                 // TODO: Add the meaningful text representation of typed enum
     229        void previsit( const ast::EnumInstType * ) {
    231230                ss << (int)ast::BasicType::SignedInt;
    232231        }
  • src/Common/module.mk

    re5d9274 r015925a  
    1010## Author           : Richard C. Bilson
    1111## Created On       : Mon Jun  1 17:49:17 2015
    12 ## Last Modified By : Andrew Beach
    13 ## Last Modified On : Tue May 17 14:27:00 2022
    14 ## Update Count     : 5
     12## Last Modified By : Peter A. Buhr
     13## Last Modified On : Tue Sep 27 11:06:38 2016
     14## Update Count     : 4
    1515###############################################################################
    1616
    1717SRC_COMMON = \
    18         Common/Assert.cc \
    19         Common/CodeLocation.h \
    20         Common/CodeLocationTools.hpp \
    21         Common/CodeLocationTools.cpp \
    22         Common/CompilerError.h \
    23         Common/Debug.h \
    24         Common/DeclStats.hpp \
    25         Common/DeclStats.cpp \
    26         Common/ErrorObjects.h \
    27         Common/Eval.cc \
    28         Common/Examine.cc \
    29         Common/Examine.h \
    30         Common/FilterCombos.h \
    31         Common/Indenter.h \
    32         Common/Indenter.cc \
    33         Common/PassVisitor.cc \
    34         Common/PassVisitor.h \
    35         Common/PassVisitor.impl.h \
    36         Common/PassVisitor.proto.h \
    37         Common/PersistentMap.h \
    38         Common/ResolvProtoDump.hpp \
    39         Common/ResolvProtoDump.cpp \
    40         Common/ScopedMap.h \
    41         Common/SemanticError.cc \
    42         Common/SemanticError.h \
    43         Common/Stats.h \
    44         Common/Stats/Base.h \
    45         Common/Stats/Counter.cc \
    46         Common/Stats/Counter.h \
    47         Common/Stats/Heap.cc \
    48         Common/Stats/Heap.h \
    49         Common/Stats/ResolveTime.cc \
    50         Common/Stats/ResolveTime.h \
    51         Common/Stats/Stats.cc \
    52         Common/Stats/Time.cc \
    53         Common/Stats/Time.h \
    54         Common/UnimplementedError.h \
    55         Common/UniqueName.cc \
    56         Common/UniqueName.h \
    57         Common/utility.h \
    58         Common/VectorMap.h
     18      Common/Assert.cc \
     19      Common/CodeLocation.h \
     20      Common/CodeLocationTools.hpp \
     21      Common/CodeLocationTools.cpp \
     22      Common/CompilerError.h \
     23      Common/Debug.h \
     24      Common/DeclStats.hpp \
     25      Common/DeclStats.cpp \
     26      Common/ErrorObjects.h \
     27      Common/Eval.cc \
     28      Common/Examine.cc \
     29      Common/Examine.h \
     30      Common/FilterCombos.h \
     31      Common/Indenter.h \
     32      Common/PassVisitor.cc \
     33      Common/PassVisitor.h \
     34      Common/PassVisitor.impl.h \
     35      Common/PassVisitor.proto.h \
     36      Common/PersistentMap.h \
     37      Common/ResolvProtoDump.hpp \
     38      Common/ResolvProtoDump.cpp \
     39      Common/ScopedMap.h \
     40      Common/SemanticError.cc \
     41      Common/SemanticError.h \
     42      Common/Stats.h \
     43      Common/Stats/Base.h \
     44      Common/Stats/Counter.cc \
     45      Common/Stats/Counter.h \
     46      Common/Stats/Heap.cc \
     47      Common/Stats/Heap.h \
     48      Common/Stats/ResolveTime.cc \
     49      Common/Stats/ResolveTime.h \
     50      Common/Stats/Stats.cc \
     51      Common/Stats/Time.cc \
     52      Common/Stats/Time.h \
     53      Common/UnimplementedError.h \
     54      Common/UniqueName.cc \
     55      Common/UniqueName.h \
     56      Common/utility.h \
     57      Common/VectorMap.h
    5958
    60 SRC += $(SRC_COMMON) \
    61         Common/DebugMalloc.cc
    62 
     59SRC += $(SRC_COMMON) Common/DebugMalloc.cc
    6360SRCDEMANGLE += $(SRC_COMMON)
  • src/Concurrency/module.mk

    re5d9274 r015925a  
    1010## Author           : Thierry Delisle
    1111## Created On       : Mon Mar 13 12:48:40 2017
    12 ## Last Modified By : Andrew Beach
    13 ## Last Modified On : Tue May 17 13:28:00 2022
    14 ## Update Count     : 1
     12## Last Modified By :
     13## Last Modified On :
     14## Update Count     : 0
    1515###############################################################################
    1616
    17 SRC += \
     17SRC_CONCURRENCY = \
    1818        Concurrency/KeywordsNew.cpp \
    19         Concurrency/Keywords.cc \
     19        Concurrency/Keywords.cc
     20
     21SRC += $(SRC_CONCURRENCY) \
    2022        Concurrency/Keywords.h \
    2123        Concurrency/Waitfor.cc \
    2224        Concurrency/Waitfor.h
     25
     26SRCDEMANGLE += $(SRC_CONCURRENCY)
     27
  • src/ControlStruct/ExceptDecl.cc

    re5d9274 r015925a  
    99// Author           : Henry Xue
    1010// Created On       : Tue Jul 20 04:10:50 2021
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Wed May 25 16:43:00 2022
    13 // Update Count     : 5
     11// Last Modified By : Henry Xue
     12// Last Modified On : Tue Aug 03 10:42:26 2021
     13// Update Count     : 4
    1414//
    1515
     
    3939}
    4040
    41 StructInstType * makeExceptInstType(
    42         const std::string & exceptionName,
    43         const std::list< Expression *> & parameters
    44 ) {
    45         StructInstType * exceptInstType = new StructInstType(
     41TypeInstType * makeExceptInstType(
     42        const std::string & exceptionName,
     43        const std::list< Expression *> & parameters
     44) {
     45        TypeInstType * exceptInstType = new TypeInstType(
    4646                noQualifiers,
    47                 exceptionName
     47                exceptionName,
     48                false
    4849        );
    4950        cloneAll( parameters, exceptInstType->parameters );
     
    150151                nullptr,
    151152                new PointerType( noQualifiers,
    152                         new StructInstType( Type::Const, "__cfavir_type_info" ) ),
     153                        new TypeInstType( Type::Const, "__cfavir_type_info", false ) ),
    153154                nullptr
    154155        ) );
     
    256257        const std::string & exceptionName,
    257258        const std::list< TypeDecl *> & forallClause,
    258         const std::list< Expression *> & parameters,
     259        const std::list< Expression *> & parameters, 
    259260        const std::list< Declaration *> & members
    260261) {
     
    301302ObjectDecl * ehmExternVtable(
    302303        const std::string & exceptionName,
    303         const std::list< Expression *> & parameters,
     304        const std::list< Expression *> & parameters, 
    304305        const std::string & tableName
    305306) {
     
    456457}
    457458
    458 class VTableCore : public WithDeclsToAdd {
    459 public:
    460         // Remove any remaining vtable type nodes in the tree.
    461         Type * postmutate( VTableType * vtableType );
    462 };
    463 
    464 Type * VTableCore::postmutate( VTableType * vtableType ) {
    465         auto inst = strict_dynamic_cast<ReferenceToType *>( vtableType->base );
    466 
    467         std::string vtableName = Virtual::vtableTypeName( inst->name );
    468         StructInstType * newType = new StructInstType( noQualifiers, vtableName );
    469         cloneAll( inst->parameters, newType->parameters );
    470 
    471         delete vtableType;
    472         return newType;
    473 }
    474 
    475459void translateExcept( std::list< Declaration *> & translationUnit ) {
    476460        PassVisitor<ExceptDeclCore> translator;
    477461        mutateAll( translationUnit, translator );
    478         PassVisitor<VTableCore> typeTranslator;
    479         mutateAll( translationUnit, typeTranslator );
    480 }
    481 
    482 }
     462}
     463
     464}
  • src/ControlStruct/module.mk

    re5d9274 r015925a  
    1010## Author           : Richard C. Bilson
    1111## Created On       : Mon Jun  1 17:49:17 2015
    12 ## Last Modified By : Andrew Beach
    13 ## Last Modified On : Tue May 17 14:30:00 2022
    14 ## Update Count     : 8
     12## Last Modified By : Peter A. Buhr
     13## Last Modified On : Sat Jan 29 12:04:19 2022
     14## Update Count     : 7
    1515###############################################################################
    1616
    17 SRC += \
     17SRC_CONTROLSTRUCT = \
    1818        ControlStruct/ExceptDecl.cc \
    1919        ControlStruct/ExceptDecl.h \
    20         ControlStruct/ExceptTranslateNew.cpp \
    21         ControlStruct/ExceptTranslate.cc \
    22         ControlStruct/ExceptTranslate.h \
    2320        ControlStruct/FixLabels.cpp \
    2421        ControlStruct/FixLabels.hpp \
     
    4037        ControlStruct/Mutate.h
    4138
     39SRC += $(SRC_CONTROLSTRUCT) \
     40        ControlStruct/ExceptTranslateNew.cpp \
     41        ControlStruct/ExceptTranslate.cc \
     42        ControlStruct/ExceptTranslate.h
     43
     44SRCDEMANGLE += $(SRC_CONTROLSTRUCT)
     45
  • src/GenPoly/Lvalue.cc

    re5d9274 r015925a  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Mon May 16 14:09:00 2022
    13 // Update Count     : 8
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Dec 13 23:14:38 2019
     13// Update Count     : 7
    1414//
    1515
     
    125125        } // namespace
    126126
    127         // Stored elsewhere (Lvalue2, initially false).
    128         extern bool referencesEliminated;
     127        static bool referencesEliminated = false;
     128        // used by UntypedExpr::createDeref to determine whether result type of dereference should be ReferenceType or value type.
     129        bool referencesPermissable() {
     130                return ! referencesEliminated;
     131        }
    129132
    130133        void convertLvalue( std::list< Declaration* > & translationUnit ) {
  • src/GenPoly/module.mk

    re5d9274 r015925a  
    1010## Author           : Richard C. Bilson
    1111## Created On       : Mon Jun  1 17:49:17 2015
    12 ## Last Modified By : Andrew Beach
    13 ## Last Modified On : Tue May 17 14:31:00 2022
    14 ## Update Count     : 2
     12## Last Modified By : Peter A. Buhr
     13## Last Modified On : Mon Jun  1 17:52:30 2015
     14## Update Count     : 1
    1515###############################################################################
    1616
    17 SRC_GENPOLY = \
    18         GenPoly/GenPoly.cc \
    19         GenPoly/GenPoly.h \
    20         GenPoly/Lvalue2.cc \
    21         GenPoly/Lvalue.h
     17SRC += GenPoly/Box.cc \
     18       GenPoly/Box.h \
     19       GenPoly/ErasableScopedMap.h \
     20       GenPoly/FindFunction.cc \
     21       GenPoly/FindFunction.h \
     22       GenPoly/GenPoly.cc \
     23       GenPoly/GenPoly.h \
     24       GenPoly/InstantiateGeneric.cc \
     25       GenPoly/InstantiateGeneric.h \
     26       GenPoly/Lvalue.cc \
     27       GenPoly/Lvalue.h \
     28       GenPoly/ScopedSet.h \
     29       GenPoly/ScrubTyVars.cc \
     30       GenPoly/ScrubTyVars.h \
     31       GenPoly/Specialize.cc \
     32       GenPoly/Specialize.h
    2233
    23 SRC += $(SRC_GENPOLY) \
    24         GenPoly/Box.cc \
    25         GenPoly/Box.h \
    26         GenPoly/ErasableScopedMap.h \
    27         GenPoly/FindFunction.cc \
    28         GenPoly/FindFunction.h \
    29         GenPoly/InstantiateGeneric.cc \
    30         GenPoly/InstantiateGeneric.h \
    31         GenPoly/Lvalue.cc \
    32         GenPoly/ScopedSet.h \
    33         GenPoly/ScrubTyVars.cc \
    34         GenPoly/ScrubTyVars.h \
    35         GenPoly/Specialize.cc \
    36         GenPoly/Specialize.h
     34SRCDEMANGLE += GenPoly/GenPoly.cc GenPoly/GenPoly.h GenPoly/Lvalue.cc GenPoly/Lvalue.h
    3735
    38 SRCDEMANGLE += $(SRC_GENPOLY)
  • src/InitTweak/FixInitNew.cpp

    re5d9274 r015925a  
    454454
    455455                auto expr = new ast::ImplicitCopyCtorExpr( appExpr->location, mutExpr );
    456                 // Move the type substitution to the new top-level. The substitution
    457                 // is needed to obtain the type of temporary variables so that copy
    458                 // constructor calls can be resolved.
     456                // Move the type substitution to the new top-level, if it is attached to the appExpr.
     457                // Ensure it is not deleted with the ImplicitCopyCtorExpr by removing it before deletion.
     458                // The substitution is needed to obtain the type of temporary variables so that copy constructor
     459                // calls can be resolved.
    459460                assert( typeSubs );
     461                // assert (mutExpr->env);
    460462                expr->env = tmp;
     463                // mutExpr->env = nullptr;
     464                //std::swap( expr->env, appExpr->env );
    461465                return expr;
    462466        }
    463467
    464468        void ResolveCopyCtors::previsit(const ast::Expr * expr) {
    465                 if ( nullptr == expr->env ) {
    466                         return;
    467                 }
    468                 GuardValue( env ) = expr->env->clone();
    469                 GuardValue( envModified ) = false;
     469                if (expr->env) {
     470                        GuardValue(env);
     471                        GuardValue(envModified);
     472                        env = expr->env->clone();
     473                        envModified = false;
     474                }
    470475        }
    471476
    472477        const ast::Expr * ResolveCopyCtors::postvisit(const ast::Expr * expr) {
    473                 // No local environment, skip.
    474                 if ( nullptr == expr->env ) {
    475                         return expr;
    476                 // Environment was modified, mutate and replace.
    477                 } else if ( envModified ) {
    478                         auto mutExpr = mutate(expr);
    479                         mutExpr->env = env;
    480                         return mutExpr;
    481                 // Environment was not mutated, delete the shallow copy before guard.
    482                 } else {
    483                         delete env;
     478                if (expr->env) {
     479                        if (envModified) {
     480                                auto mutExpr = mutate(expr);
     481                                mutExpr->env = env;
     482                                return mutExpr;
     483                        }
     484                        else {
     485                                // env was not mutated, skip and delete the shallow copy
     486                                delete env;
     487                                return expr;
     488                        }
     489                }
     490                else {
    484491                        return expr;
    485492                }
     
    490497        const ast::Expr * ResolveCopyCtors::makeCtorDtor( const std::string & fname, const ast::ObjectDecl * var, const ast::Expr * cpArg ) {
    491498                assert( var );
    492                 assert( var->isManaged() );
    493                 assert( !cpArg || cpArg->isManaged() );
     499                assert (var->isManaged());
     500                assert (!cpArg || cpArg->isManaged());
    494501                // arrays are not copy constructed, so this should always be an ExprStmt
    495502                ast::ptr< ast::Stmt > stmt = genCtorDtor(var->location, fname, var, cpArg );
     
    497504                auto exprStmt = stmt.strict_as<ast::ImplicitCtorDtorStmt>()->callStmt.strict_as<ast::ExprStmt>();
    498505                ast::ptr<ast::Expr> untyped = exprStmt->expr; // take ownership of expr
     506                // exprStmt->expr = nullptr;
    499507
    500508                // resolve copy constructor
     
    508516                        env->add( *resolved->env );
    509517                        envModified = true;
     518                        // delete resolved->env;
    510519                        auto mut = mutate(resolved.get());
    511520                        assertf(mut == resolved.get(), "newly resolved expression must be unique");
    512521                        mut->env = nullptr;
    513522                } // if
     523                // delete stmt;
    514524                if ( auto assign = resolved.as<ast::TupleAssignExpr>() ) {
    515525                        // fix newly generated StmtExpr
  • src/InitTweak/GenInit.cc

    re5d9274 r015925a  
    368368
    369369        struct ReturnFixer_New final :
    370                         public ast::WithStmtsToAdd<>, ast::WithGuards, ast::WithShortCircuiting {
     370                        public ast::WithStmtsToAdd<>, ast::WithGuards {
    371371                void previsit( const ast::FunctionDecl * decl );
    372372                const ast::ReturnStmt * previsit( const ast::ReturnStmt * stmt );
     
    376376
    377377        void ReturnFixer_New::previsit( const ast::FunctionDecl * decl ) {
    378                 if (decl->linkage == ast::Linkage::Intrinsic) visit_children = false;
    379378                GuardValue( funcDecl ) = decl;
    380379        }
  • src/InitTweak/module.mk

    re5d9274 r015925a  
    1010## Author           : Richard C. Bilson
    1111## Created On       : Mon Jun  1 17:49:17 2015
    12 ## Last Modified By : Andrew Beach
    13 ## Last Modified On : Tue May 17 14:31:00 2022
    14 ## Update Count     : 4
     12## Last Modified By : Rob Schluntz
     13## Last Modified On : Fri May 13 11:36:24 2016
     14## Update Count     : 3
    1515###############################################################################
    1616
    17 SRC_INITTWEAK = \
     17SRC += \
     18        InitTweak/FixGlobalInit.cc \
     19        InitTweak/FixGlobalInit.h \
     20        InitTweak/FixInit.cc \
     21        InitTweak/FixInit.h \
     22        InitTweak/GenInit.cc \
     23        InitTweak/GenInit.h \
     24        InitTweak/InitTweak.cc \
     25        InitTweak/InitTweak.h \
     26        InitTweak/FixInitNew.cpp
     27
     28SRCDEMANGLE += \
    1829        InitTweak/GenInit.cc \
    1930        InitTweak/GenInit.h \
     
    2132        InitTweak/InitTweak.h
    2233
    23 SRC += $(SRC_INITTWEAK) \
    24         InitTweak/FixGlobalInit.cc \
    25         InitTweak/FixGlobalInit.h \
    26         InitTweak/FixInit.cc \
    27         InitTweak/FixInit.h \
    28         InitTweak/FixInitNew.cpp
    29 
    30 SRCDEMANGLE += $(SRC_INITTWEAK)
  • src/Parser/parser.yy

    re5d9274 r015925a  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat May 14 09:16:22 2022
    13 // Update Count     : 5401
     12// Last Modified On : Wed May  4 17:22:48 2022
     13// Update Count     : 5279
    1414//
    1515
     
    5454#include "Common/SemanticError.h"                                               // error_str
    5555#include "Common/utility.h"                                                             // for maybeMoveBuild, maybeBuild, CodeLo...
    56 
    57 #include "SynTree/Attribute.h"     // for Attribute
    5856
    5957extern DeclarationNode * parseTree;
     
    9593} // appendStr
    9694
    97 DeclarationNode * distAttr( DeclarationNode * typeSpec, DeclarationNode * declList ) {
    98         // distribute declaration_specifier across all declared variables, e.g., static, const, but not __attribute__.
    99         assert( declList );
    100 //      printf( "distAttr1 typeSpec %p\n", typeSpec ); typeSpec->print( std::cout );
    101         DeclarationNode * cur = declList, * cl = (new DeclarationNode)->addType( typeSpec );
    102 //      printf( "distAttr2 cl %p\n", cl ); cl->type->print( std::cout );
    103 //      cl->type->aggregate.name = cl->type->aggInst.aggregate->aggregate.name;
    104 
     95DeclarationNode * distAttr( DeclarationNode * specifier, DeclarationNode * declList ) {
     96        // distribute declaration_specifier across all declared variables, e.g., static, const, __attribute__.
     97        DeclarationNode * cur = declList, * cl = (new DeclarationNode)->addType( specifier );
    10598        for ( cur = dynamic_cast<DeclarationNode *>( cur->get_next() ); cur != nullptr; cur = dynamic_cast<DeclarationNode *>( cur->get_next() ) ) {
    10699                cl->cloneBaseType( cur );
    107100        } // for
    108101        declList->addType( cl );
    109 //      printf( "distAttr3 declList %p\n", declList ); declList->print( std::cout, 0 );
    110102        return declList;
    111103} // distAttr
     
    179171                if ( ! ( typeSpec->type && (typeSpec->type->kind == TypeData::Aggregate || typeSpec->type->kind == TypeData::Enum) ) ) {
    180172                        stringstream ss;
    181                         // printf( "fieldDecl1 typeSpec %p\n", typeSpec ); typeSpec->type->print( std::cout );
     173                        typeSpec->type->print( ss );
    182174                        SemanticWarning( yylloc, Warning::SuperfluousDecl, ss.str().c_str() );
    183175                        return nullptr;
    184176                } // if
    185                 // printf( "fieldDecl2 typeSpec %p\n", typeSpec ); typeSpec->type->print( std::cout );
    186177                fieldList = DeclarationNode::newName( nullptr );
    187178        } // if
    188 //      return distAttr( typeSpec, fieldList );                         // mark all fields in list
    189 
    190         // printf( "fieldDecl3 typeSpec %p\n", typeSpec ); typeSpec->print( std::cout, 0 );
    191         DeclarationNode * temp = distAttr( typeSpec, fieldList );                               // mark all fields in list
    192         // printf( "fieldDecl4 temp %p\n", temp ); temp->print( std::cout, 0 );
    193         return temp;
     179        return distAttr( typeSpec, fieldList );                         // mark all fields in list
    194180} // fieldDecl
    195181
     
    16341620declaration:                                                                                    // old & new style declarations
    16351621        c_declaration ';'
    1636                 {
    1637                         // printf( "C_DECLARATION1 %p %s\n", $$, $$->name ? $$->name->c_str() : "(nil)" );
    1638                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    1639                         //   printf( "\tattr %s\n", attr->name.c_str() );
    1640                         // } // for
    1641                 }
    16421622        | cfa_declaration ';'                                                           // CFA
    16431623        | static_assert                                                                         // C11
     
    18451825        basic_type_specifier
    18461826        | sue_type_specifier
    1847                 {
    1848                         // printf( "sue_type_specifier2 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    1849                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    1850                         //   printf( "\tattr %s\n", attr->name.c_str() );
    1851                         // } // for
    1852                 }
    18531827        | type_type_specifier
    18541828        ;
     
    20672041sue_declaration_specifier:                                                              // struct, union, enum + storage class + type specifier
    20682042        sue_type_specifier
    2069                 {
    2070                         // printf( "sue_declaration_specifier %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2071                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    2072                         //   printf( "\tattr %s\n", attr->name.c_str() );
    2073                         // } // for
    2074                 }
    20752043        | declaration_qualifier_list sue_type_specifier
    20762044                { $$ = $2->addQualifiers( $1 ); }
     
    20832051sue_type_specifier:                                                                             // struct, union, enum + type specifier
    20842052        elaborated_type
    2085                 {
    2086                         // printf( "sue_type_specifier %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2087                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    2088                         //   printf( "\tattr %s\n", attr->name.c_str() );
    2089                         // } // for
    2090                 }
    20912053        | type_qualifier_list
    20922054                { if ( $1->type != nullptr && $1->type->forall ) forall = true; } // remember generic type
     
    21612123elaborated_type:                                                                                // struct, union, enum
    21622124        aggregate_type
    2163                 {
    2164                         // printf( "elaborated_type %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2165                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    2166                         //   printf( "\tattr %s\n", attr->name.c_str() );
    2167                         // } // for
    2168                 }
    21692125        | enum_type
    21702126        ;
     
    21862142                }
    21872143          '{' field_declaration_list_opt '}' type_parameters_opt
    2188                 {
    2189                         // printf( "aggregate_type1 %s\n", $3.str->c_str() );
    2190                         // if ( $2 )
    2191                         //      for ( Attribute * attr: reverseIterate( $2->attributes ) ) {
    2192                         //              printf( "copySpecifiers12 %s\n", attr->name.c_str() );
    2193                         //      } // for
    2194                         $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
    2195                         // printf( "aggregate_type2 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2196                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    2197                         //      printf( "aggregate_type3 %s\n", attr->name.c_str() );
    2198                         // } // for
    2199                 }
     2144                { $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); }
    22002145        | aggregate_key attribute_list_opt TYPEDEFname          // unqualified type name
    22012146                {
     
    22052150          '{' field_declaration_list_opt '}' type_parameters_opt
    22062151                {
    2207                         // printf( "AGG3\n" );
    22082152                        DeclarationNode::newFromTypedef( $3 );
    22092153                        $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
     
    22162160          '{' field_declaration_list_opt '}' type_parameters_opt
    22172161                {
    2218                         // printf( "AGG4\n" );
    22192162                        DeclarationNode::newFromTypeGen( $3, nullptr );
    22202163                        $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
     
    22932236field_declaration:
    22942237        type_specifier field_declaring_list_opt ';'
    2295                 {
    2296                         // printf( "type_specifier1 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2297                         $$ = fieldDecl( $1, $2 );
    2298                         // printf( "type_specifier2 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
    2299                         // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
    2300                         //   printf( "\tattr %s\n", attr->name.c_str() );
    2301                         // } // for
    2302                 }
     2238                { $$ = fieldDecl( $1, $2 ); }
    23032239        | EXTENSION type_specifier field_declaring_list_opt ';' // GCC
    23042240                { $$ = fieldDecl( $2, $3 ); distExt( $$ ); }
     
    29092845        // empty
    29102846                { $$ = nullptr; forall = false; }
    2911         | WITH '(' tuple_expression_list ')' attribute_list_opt
    2912                 {
    2913                         $$ = $3; forall = false;
    2914                         if ( $5 ) {
    2915                                 SemanticError( yylloc, "Attributes cannot be associated with function body. Move attribute(s) before \"with\" clause." );
    2916                                 $$ = nullptr;
    2917                         } // if
    2918                 }
     2847        | WITH '(' tuple_expression_list ')'
     2848                { $$ = $3; forall = false; }
    29192849        ;
    29202850
  • src/ResolvExpr/AlternativeFinder.cc

    re5d9274 r015925a  
    4242#include "SymTab/Indexer.h"        // for Indexer
    4343#include "SymTab/Mangler.h"        // for Mangler
    44 #include "SymTab/ValidateType.h"   // for validateType
     44#include "SymTab/Validate.h"       // for validateType
    4545#include "SynTree/Constant.h"      // for Constant
    4646#include "SynTree/Declaration.h"   // for DeclarationWithType, TypeDecl, Dec...
  • src/ResolvExpr/CandidateFinder.cpp

    re5d9274 r015925a  
    899899
    900900                                                if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);
    901                                                 else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) {
    902                                                         const ast::EnumDecl * enumDecl = enumInst->base;
    903                                                         if ( const ast::Type* enumType = enumDecl->base ) {
    904                                                                 // instance of enum (T) is a instance of type (T)
    905                                                                 funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type));
    906                                                         } else {
    907                                                                 // instance of an untyped enum is techically int
    908                                                                 funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type));
    909                                                         }
    910                                                 }
    911901                                                else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type));
    912902                                        }
     
    928918
    929919                        // find function operators
    930                         ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" }; // ??? why not ?{}
     920                        ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" };
    931921                        CandidateFinder opFinder( context, tenv );
    932922                        // okay if there aren't any function operations
  • src/ResolvExpr/CommonType.cc

    re5d9274 r015925a  
    497497                                result = new BasicType( basicType->tq | otherBasic->tq, newType );
    498498                        } // if
    499                 } else if ( dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) {
     499                } else if ( dynamic_cast< EnumInstType * > ( type2 ) || dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) {
    500500                        // use signed int in lieu of the enum/zero/one type
    501501                        BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ BasicType::SignedInt ];
     
    503503                                result = new BasicType( basicType->tq | type2->tq, newType );
    504504                        } // if
    505                 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * > ( type2 ) ) {
    506                         const EnumDecl* enumDecl = enumInst->baseEnum;
    507                         if ( const Type* baseType = enumDecl->base ) {
    508                                 result = baseType->clone();
    509                         } else {
    510                                 BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ BasicType::SignedInt ];
    511                                 if ( ( ( newType == basicType->get_kind() && basicType->tq >= type2->tq ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->tq <= type2->tq ) || widenSecond ) ) {
    512                                         result = new BasicType( basicType->tq | type2->tq, newType );
    513                                 } // if
    514                         }
    515                 }
     505                } // if
    516506        }
    517507
     
    701691                                }
    702692                        } else if (
    703                                 dynamic_cast< const ast::ZeroType * >( type2 )
     693                                dynamic_cast< const ast::EnumInstType * >( type2 )
     694                                || dynamic_cast< const ast::ZeroType * >( type2 )
    704695                                || dynamic_cast< const ast::OneType * >( type2 )
    705696                        ) {
     
    714705                                        result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers };
    715706                                }
    716                         } else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
    717                                 #warning remove casts when `commonTypes` moved to new AST
    718                                 const ast::EnumDecl* enumDecl = enumInst->base;
    719                                 if ( enumDecl->base ) {
    720                                         result = enumDecl->base.get();
    721                                 } else {
    722                                         ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ];
    723                                         if (
    724                                                 ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
    725                                                         || widen.first )
    726                                                 && ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers )
    727                                                         || widen.second )
    728                                         ) {
    729                                                 result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers };
    730                                         }
    731                                 }
    732707                        }
    733708                }
     
    748723                        result = voidPtr;
    749724                        add_qualifiers( result, oPtr->qualifiers );
    750                 }
    751 
    752                 // For a typed enum, we want to unify type1 with the base type of the enum
    753                 bool tryResolveWithTypedEnum( const ast::Type * type1 ) {
    754                         if (auto enumInst = dynamic_cast<const ast::EnumInstType *> (type2) ) {
    755                                 ast::AssertionSet have, need; // unused
    756                                 ast::OpenVarSet newOpen{ open };
    757                                 if (enumInst->base->base
    758                                 && unifyExact(type1, enumInst->base->base, tenv, need, have, newOpen, widen, symtab)) {
    759                                         result = type1;
    760                                         return true;
    761                                 }
    762                         }
    763                         return false;
    764725                }
    765726
     
    807768                                result = pointer;
    808769                                add_qualifiers( result, type2->qualifiers );
    809                         } else {
    810                                 tryResolveWithTypedEnum( pointer );
    811                         }
    812                 }
    813 
    814                 void postvisit( const ast::ArrayType * arr ) {
    815                         // xxx - does it make sense?
    816                         tryResolveWithTypedEnum( arr );
    817                 }
     770                        }
     771                }
     772
     773                void postvisit( const ast::ArrayType * ) {}
    818774
    819775                void postvisit( const ast::ReferenceType * ref ) {
     
    854810                                result = ref;
    855811                                add_qualifiers( result, type2->qualifiers );
    856                         } else {
    857                                 // xxx - does unifying a ref with typed enumInst makes sense?
    858                                 if (!dynamic_cast<const ast::EnumInstType *>(type2))
    859                                         result = commonType( type2, ref, widen, symtab, tenv, open );
    860                         }
    861                 }
    862 
    863                 void postvisit( const ast::FunctionType * func) {
    864                         tryResolveWithTypedEnum( func );
    865                 }
    866 
    867                 void postvisit( const ast::StructInstType * inst ) {
    868                         tryResolveWithTypedEnum( inst );
    869                 }
    870 
    871                 void postvisit( const ast::UnionInstType * inst ) {
    872                         tryResolveWithTypedEnum( inst );
    873                 }
     812                        }
     813                }
     814
     815                void postvisit( const ast::FunctionType * ) {}
     816
     817                void postvisit( const ast::StructInstType * ) {}
     818
     819                void postvisit( const ast::UnionInstType * ) {}
    874820
    875821                void postvisit( const ast::EnumInstType * enumInst ) {
    876                         // reuse BasicType/EnumInstType common type by swapping
    877                         // xxx - is this already handled by unify?
    878                         if (!dynamic_cast<const ast::EnumInstType *>(type2))
     822                        if (
     823                                dynamic_cast< const ast::BasicType * >( type2 )
     824                                || dynamic_cast< const ast::ZeroType * >( type2 )
     825                                || dynamic_cast< const ast::OneType * >( type2 )
     826                        ) {
     827                                // reuse BasicType/EnumInstType common type by swapping
    879828                                result = commonType( type2, enumInst, widen, symtab, tenv, open );
     829                        }
    880830                }
    881831
     
    900850                                                result = type2;
    901851                                                reset_qualifiers( result, q1 | q2 );
    902                                         } else {
    903                                                 tryResolveWithTypedEnum( t1 );
    904852                                        }
    905853                                }
     
    907855                }
    908856
    909                 void postvisit( const ast::TupleType * tuple) {
    910                         tryResolveWithTypedEnum( tuple );
    911                 }
     857                void postvisit( const ast::TupleType * ) {}
    912858
    913859                void postvisit( const ast::VarArgsType * ) {}
     
    915861                void postvisit( const ast::ZeroType * zero ) {
    916862                        if ( ! widen.first ) return;
    917                         if ( dynamic_cast< const ast::BasicType * >( type2 )
    918                                 || dynamic_cast< const ast::PointerType * >( type2 ) ) {
     863                        if (
     864                                dynamic_cast< const ast::BasicType * >( type2 )
     865                                || dynamic_cast< const ast::PointerType * >( type2 )
     866                                || dynamic_cast< const ast::EnumInstType * >( type2 )
     867                        ) {
    919868                                if ( widen.second || zero->qualifiers <= type2->qualifiers ) {
    920869                                        result = type2;
     
    924873                                result = new ast::BasicType{
    925874                                        ast::BasicType::SignedInt, zero->qualifiers | type2->qualifiers };
    926                         } else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
    927                                 const ast::EnumDecl * enumDecl = enumInst->base;
    928                                 if ( enumDecl->base ) {
    929                                         if ( tryResolveWithTypedEnum( zero ) )
    930                                                 add_qualifiers( result, zero->qualifiers );
    931                                 } else {
    932                                         if ( widen.second || zero->qualifiers <= type2->qualifiers ) {
    933                                                 result = type2;
    934                                                 add_qualifiers( result, zero->qualifiers );
    935                                         }
    936                                 }
    937875                        }
    938876                }
     
    940878                void postvisit( const ast::OneType * one ) {
    941879                        if ( ! widen.first ) return;
    942                         if ( dynamic_cast< const ast::BasicType * >( type2 ) ) {
     880                        if (
     881                                dynamic_cast< const ast::BasicType * >( type2 )
     882                                || dynamic_cast< const ast::EnumInstType * >( type2 )
     883                        ) {
    943884                                if ( widen.second || one->qualifiers <= type2->qualifiers ) {
    944885                                        result = type2;
     
    948889                                result = new ast::BasicType{
    949890                                        ast::BasicType::SignedInt, one->qualifiers | type2->qualifiers };
    950                         } else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
    951                                 const ast::EnumDecl * enumBase = enumInst->base;
    952                                 if ( enumBase->base ) {
    953                                         if ( tryResolveWithTypedEnum( one ))
    954                                                 add_qualifiers( result, one->qualifiers );
    955                                 } else {
    956                                         if ( widen.second || one->qualifiers <= type2->qualifiers ) {
    957                                                 result = type2;
    958                                                 add_qualifiers( result, one->qualifiers );
    959                                         }
    960                                 }
    961891                        }
    962892                }
  • src/ResolvExpr/ConversionCost.cc

    re5d9274 r015925a  
    321321        }
    322322
    323         // refactor for code resue
    324         void ConversionCost::conversionCostFromBasicToBasic(const BasicType * src, const BasicType * dest) {
    325                 int tableResult = costMatrix[ src->kind ][ dest->kind ];
    326                 if ( tableResult == -1 ) {
    327                         cost = Cost::unsafe;
    328                 } else {
    329                         cost = Cost::zero;
    330                         cost.incSafe( tableResult );
    331                         cost.incSign( signMatrix[ src->kind ][ dest->kind ] );
    332                 } // if
    333         } // ConversionCost::conversionCostFromBasicToBasic
    334 
    335323        void ConversionCost::postvisit(const BasicType * basicType) {
    336324                if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {
    337                         conversionCostFromBasicToBasic(basicType, destAsBasic);
    338                 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * >( dest ) ) {
    339                         const EnumDecl * base_enum = enumInst->baseEnum;
    340                         if ( const Type * base = base_enum->base ) { // if the base enum has a base (if it is typed)
    341                                 if ( const BasicType * enumBaseAstBasic = dynamic_cast< const BasicType *> (base) ) {
    342                                         conversionCostFromBasicToBasic(basicType, enumBaseAstBasic);
    343                                 } else {
    344                                         cost = Cost::infinity;
    345                                 } // if
     325                        int tableResult = costMatrix[ basicType->kind ][ destAsBasic->kind ];
     326                        if ( tableResult == -1 ) {
     327                                cost = Cost::unsafe;
     328                        } else {
     329                                cost = Cost::zero;
     330                                cost.incSafe( tableResult );
     331                                cost.incSign( signMatrix[ basicType->kind ][ destAsBasic->kind ] );
     332                        } // if
     333                } else if ( dynamic_cast< const EnumInstType * >( dest ) ) {
     334                        // xxx - not positive this is correct, but appears to allow casting int => enum
     335                        // TODO
     336                        EnumDecl * decl = dynamic_cast< const EnumInstType * >( dest )->baseEnum;
     337                        if ( decl->base ) {
     338                                cost = Cost::infinity;
    346339                        } else {
    347340                                cost = Cost::unsafe;
     
    405398        void ConversionCost::postvisit( const FunctionType * ) {}
    406399
    407         void ConversionCost::postvisit( const EnumInstType * enumInst) {
    408                 const EnumDecl * enumDecl = enumInst -> baseEnum;
    409                 if ( const Type * enumType = enumDecl -> base ) { // if it is a typed enum
    410                         cost = costFunc( enumType, dest, srcIsLvalue, indexer, env );
    411                 } else {
    412                         static Type::Qualifiers q;
    413                         static BasicType integer( q, BasicType::SignedInt );
    414                         cost = costFunc( &integer, dest, srcIsLvalue, indexer, env );  // safe if dest >= int
    415                 } // if
     400        void ConversionCost::postvisit( const EnumInstType * ) {
     401                static Type::Qualifiers q;
     402                static BasicType integer( q, BasicType::SignedInt );
     403                cost = costFunc( &integer, dest, srcIsLvalue, indexer, env );  // safe if dest >= int
    416404                if ( cost < Cost::unsafe ) {
    417                                 cost.incSafe();
     405                        cost.incSafe();
    418406                } // if
    419407        }
     
    616604}
    617605
    618 void ConversionCost_new::conversionCostFromBasicToBasic( const ast::BasicType * src, const ast::BasicType* dest ) {
    619         int tableResult = costMatrix[ src->kind ][ dest->kind ];
    620         if ( tableResult == -1 ) {
    621                 cost = Cost::unsafe;
    622         } else {
    623                 cost = Cost::zero;
    624                 cost.incSafe( tableResult );
    625                 cost.incSign( signMatrix[ src->kind ][ dest->kind ] );
    626         }
    627 }
    628 
    629606void ConversionCost_new::postvisit( const ast::BasicType * basicType ) {
    630607        if ( const ast::BasicType * dstAsBasic = dynamic_cast< const ast::BasicType * >( dst ) ) {
    631                 conversionCostFromBasicToBasic( basicType, dstAsBasic );
    632         } else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( dst ) ) {
    633                 const ast::EnumDecl * enumDecl = enumInst->base.get();
    634                 if ( const ast::Type * enumType = enumDecl->base.get() ) {
    635                         if ( const ast::BasicType * enumTypeAsBasic = dynamic_cast<const ast::BasicType *>(enumType) ) {
    636                                 conversionCostFromBasicToBasic( basicType, enumTypeAsBasic );
    637                         } else {
    638                                 cost = Cost::infinity;
    639                         }
    640                 } else {
    641             cost = Cost::unsafe;
    642                 }
     608                int tableResult = costMatrix[ basicType->kind ][ dstAsBasic->kind ];
     609                if ( tableResult == -1 ) {
     610                        cost = Cost::unsafe;
     611                } else {
     612                        cost = Cost::zero;
     613                        cost.incSafe( tableResult );
     614                        cost.incSign( signMatrix[ basicType->kind ][ dstAsBasic->kind ] );
     615                }
     616        } else if ( dynamic_cast< const ast::EnumInstType * >( dst ) ) {
     617                // xxx - not positive this is correct, but appears to allow casting int => enum
     618                const ast::EnumDecl * decl = (dynamic_cast< const ast::EnumInstType * >( dst ))->base.get();
     619                if ( decl->base ) {
     620                        cost = Cost::infinity;
     621                } else {
     622                        cost = Cost::unsafe;
     623                } // if
    643624        }
    644625}
     
    692673
    693674void ConversionCost_new::postvisit( const ast::EnumInstType * enumInstType ) {
    694         const ast::EnumDecl * baseEnum = enumInstType->base;
    695         if ( const ast::Type * baseType = baseEnum->base ) {
    696                 cost = costCalc( baseType, dst, srcIsLvalue, symtab, env );
    697         } else {
    698                 (void)enumInstType;
    699                 static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
    700                 cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
    701         }
     675        (void)enumInstType;
     676        static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
     677        cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
    702678        if ( cost < Cost::unsafe ) {
    703679                cost.incSafe();
  • src/ResolvExpr/ConversionCost.h

    re5d9274 r015925a  
    6565                const TypeEnvironment &env;
    6666                CostFunction costFunc;
    67           private:
    68                 // refactor for code resue
    69                 void conversionCostFromBasicToBasic( const BasicType * src, const BasicType* dest );
    7067        };
    7168
     
    114111        void postvisit( const ast::ZeroType * zeroType );
    115112        void postvisit( const ast::OneType * oneType );
    116 private:
    117         // refactor for code resue
    118         void conversionCostFromBasicToBasic( const ast::BasicType * src, const ast::BasicType* dest );
    119113};
    120114
  • src/SymTab/Autogen.h

    re5d9274 r015925a  
    2121
    2222#include "AST/Decl.hpp"
     23#include "AST/Eval.hpp"
    2324#include "AST/Expr.hpp"
    2425#include "AST/Init.hpp"
     
    7071        template< typename OutIter >
    7172        ast::ptr< ast::Stmt > genCall(
    72                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
    73                 const CodeLocation & loc, const std::string & fname, OutIter && out,
     73                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 
     74                const CodeLocation & loc, const std::string & fname, OutIter && out, 
    7475                const ast::Type * type, const ast::Type * addCast, LoopDirection forward = LoopForward );
    7576
     
    127128        }
    128129
    129         /// inserts into out a generated call expression to function fname with arguments dstParam and
     130        /// inserts into out a generated call expression to function fname with arguments dstParam and 
    130131        /// srcParam. Should only be called with non-array types.
    131         /// optionally returns a statement which must be inserted prior to the containing loop, if
     132        /// optionally returns a statement which must be inserted prior to the containing loop, if 
    132133        /// there is one
    133134        template< typename OutIter >
    134         ast::ptr< ast::Stmt > genScalarCall(
    135                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
    136                 const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type,
     135        ast::ptr< ast::Stmt > genScalarCall( 
     136                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 
     137                const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type, 
    137138                const ast::Type * addCast = nullptr
    138139        ) {
     
    152153
    153154                if ( addCast ) {
    154                         // cast to T& with qualifiers removed, so that qualified objects can be constructed and
    155                         // destructed with the same functions as non-qualified objects. Unfortunately, lvalue
    156                         // is considered a qualifier - for AddressExpr to resolve, its argument must have an
     155                        // cast to T& with qualifiers removed, so that qualified objects can be constructed and 
     156                        // destructed with the same functions as non-qualified objects. Unfortunately, lvalue 
     157                        // is considered a qualifier - for AddressExpr to resolve, its argument must have an 
    157158                        // lvalue-qualified type, so remove all qualifiers except lvalue.
    158159                        // xxx -- old code actually removed lvalue too...
    159160                        ast::ptr< ast::Type > guard = addCast;  // prevent castType from mutating addCast
    160161                        ast::ptr< ast::Type > castType = addCast;
    161                         ast::remove_qualifiers(
    162                                 castType,
     162                        ast::remove_qualifiers( 
     163                                castType, 
    163164                                ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Atomic );
    164165                        dstParam = new ast::CastExpr{ dstParam, new ast::ReferenceType{ castType } };
     
    180181
    181182                srcParam.clearArrayIndices();
    182 
     183               
    183184                return listInit;
    184185        }
     
    248249        }
    249250
    250         /// Store in out a loop which calls fname on each element of the array with srcParam and
     251        /// Store in out a loop which calls fname on each element of the array with srcParam and 
    251252        /// dstParam as arguments. If forward is true, loop goes from 0 to N-1, else N-1 to 0
    252253        template< typename OutIter >
    253254        void genArrayCall(
    254                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
    255                 const CodeLocation & loc, const std::string & fname, OutIter && out,
    256                 const ast::ArrayType * array, const ast::Type * addCast = nullptr,
    257                 LoopDirection forward = LoopForward
     255                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 
     256                const CodeLocation & loc, const std::string & fname, OutIter && out, 
     257                const ast::ArrayType * array, const ast::Type * addCast = nullptr, 
     258                LoopDirection forward = LoopForward 
    258259        ) {
    259260                static UniqueName indexName( "_index" );
     
    278279                } else {
    279280                        // generate: for ( int i = N-1; i >= 0; --i )
    280                         begin = ast::UntypedExpr::createCall( loc, "?-?",
    281                                 { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } );
     281                        begin = ast::call(
     282                                loc, "?-?", array->dimension, ast::ConstantExpr::from_int( loc, 1 ) );
    282283                        end = ast::ConstantExpr::from_int( loc, 0 );
    283284                        cmp = "?>=?";
     
    285286                }
    286287
    287                 ast::ptr< ast::DeclWithType > index = new ast::ObjectDecl{
    288                         loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt },
     288                ast::ptr< ast::DeclWithType > index = new ast::ObjectDecl{ 
     289                        loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt }, 
    289290                        new ast::SingleInit{ loc, begin } };
    290291                ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index };
    291 
    292                 ast::ptr< ast::Expr > cond = ast::UntypedExpr::createCall(
    293                         loc, cmp, { indexVar, end } );
    294 
    295                 ast::ptr< ast::Expr > inc = ast::UntypedExpr::createCall(
    296                         loc, update, { indexVar } );
    297 
    298                 ast::ptr< ast::Expr > dstIndex = ast::UntypedExpr::createCall(
    299                         loc, "?[?]", { dstParam, indexVar } );
    300 
    301                 // srcParam must keep track of the array indices to build the source parameter and/or
     292               
     293                ast::ptr< ast::Expr > cond = ast::call( loc, cmp, indexVar, end );
     294               
     295                ast::ptr< ast::Expr > inc = ast::call( loc, update, indexVar );
     296               
     297                ast::ptr< ast::Expr > dstIndex = ast::call( loc, "?[?]", dstParam, indexVar );
     298               
     299                // srcParam must keep track of the array indices to build the source parameter and/or
    302300                // array list initializer
    303301                srcParam.addArrayIndex( indexVar, array->dimension );
     
    305303                // for stmt's body, eventually containing call
    306304                ast::CompoundStmt * body = new ast::CompoundStmt{ loc };
    307                 ast::ptr< ast::Stmt > listInit = genCall(
    308                         srcParam, dstIndex, loc, fname, std::back_inserter( body->kids ), array->base, addCast,
     305                ast::ptr< ast::Stmt > listInit = genCall( 
     306                        srcParam, dstIndex, loc, fname, std::back_inserter( body->kids ), array->base, addCast, 
    309307                        forward );
    310 
     308               
    311309                // block containing the stmt and index variable
    312310                ast::CompoundStmt * block = new ast::CompoundStmt{ loc };
     
    330328        template< typename OutIter >
    331329        ast::ptr< ast::Stmt > genCall(
    332                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
    333                 const CodeLocation & loc, const std::string & fname, OutIter && out,
     330                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 
     331                const CodeLocation & loc, const std::string & fname, OutIter && out, 
    334332                const ast::Type * type, const ast::Type * addCast, LoopDirection forward
    335333        ) {
    336334                if ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
    337                         genArrayCall(
    338                                 srcParam, dstParam, loc, fname, std::forward< OutIter >(out), at, addCast,
     335                        genArrayCall( 
     336                                srcParam, dstParam, loc, fname, std::forward< OutIter >(out), at, addCast, 
    339337                                forward );
    340338                        return {};
    341339                } else {
    342                         return genScalarCall(
     340                        return genScalarCall( 
    343341                                srcParam, dstParam, loc, fname, std::forward< OutIter >( out ), type, addCast );
    344342                }
     
    379377        }
    380378
    381         static inline ast::ptr< ast::Stmt > genImplicitCall(
    382                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
    383                 const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj,
    384                 LoopDirection forward = LoopForward
     379        static inline ast::ptr< ast::Stmt > genImplicitCall( 
     380                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 
     381                const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj, 
     382                LoopDirection forward = LoopForward 
    385383        ) {
    386384                // unnamed bit fields are not copied as they cannot be accessed
     
    394392
    395393                std::vector< ast::ptr< ast::Stmt > > stmts;
    396                 genCall(
     394                genCall( 
    397395                        srcParam, dstParam, loc, fname, back_inserter( stmts ), obj->type, addCast, forward );
    398396
     
    402400                        const ast::Stmt * callStmt = stmts.front();
    403401                        if ( addCast ) {
    404                                 // implicitly generated ctor/dtor calls should be wrapped so that later passes are
     402                                // implicitly generated ctor/dtor calls should be wrapped so that later passes are 
    405403                                // aware they were generated.
    406404                                callStmt = new ast::ImplicitCtorDtorStmt{ callStmt->location, callStmt };
     
    419417// compile-command: "make install" //
    420418// End: //
     419
  • src/SymTab/Demangle.cc

    re5d9274 r015925a  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // Demangle.cc -- Convert a mangled name into a human readable name.
     7// Demangler.cc --
    88//
    99// Author           : Rob Schluntz
  • src/SymTab/Mangler.h

    re5d9274 r015925a  
    111111}
    112112
     113extern "C" {
     114        char * cforall_demangle(const char *, int);
     115}
     116
    113117// Local Variables: //
    114118// tab-width: 4 //
  • src/SymTab/Validate.cc

    re5d9274 r015925a  
    1010// Created On       : Sun May 17 21:50:04 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue May 17 14:36:00 2022
    13 // Update Count     : 366
     12// Last Modified On : Fri Apr 29  9:45:00 2022
     13// Update Count     : 365
    1414//
    1515
     
    7474#include "ResolvExpr/ResolveTypeof.h"  // for resolveTypeof
    7575#include "SymTab/Autogen.h"            // for SizeType
    76 #include "SymTab/ValidateType.h"       // for decayEnumsAndPointers, decayFo...
    7776#include "SynTree/LinkageSpec.h"       // for C
    7877#include "SynTree/Attribute.h"         // for noAttributes, Attribute
     
    135134        };
    136135
     136        /// Replaces enum types by int, and function or array types in function parameter and return lists by appropriate pointers.
     137        struct EnumAndPointerDecay_old {
     138                void previsit( EnumDecl * aggregateDecl );
     139                void previsit( FunctionType * func );
     140        };
     141
     142        /// Associates forward declarations of aggregates with their definitions
     143        struct LinkReferenceToTypes_old final : public WithIndexer, public WithGuards, public WithVisitorRef<LinkReferenceToTypes_old>, public WithShortCircuiting {
     144                LinkReferenceToTypes_old( const Indexer * indexer );
     145
     146                void postvisit( TypeInstType * typeInst );
     147
     148                void postvisit( EnumInstType * enumInst );
     149                void postvisit( StructInstType * structInst );
     150                void postvisit( UnionInstType * unionInst );
     151                void postvisit( TraitInstType * traitInst );
     152                void previsit( QualifiedType * qualType );
     153                void postvisit( QualifiedType * qualType );
     154
     155                void postvisit( EnumDecl * enumDecl );
     156                void postvisit( StructDecl * structDecl );
     157                void postvisit( UnionDecl * unionDecl );
     158                void postvisit( TraitDecl * traitDecl );
     159
     160                void previsit( StructDecl * structDecl );
     161                void previsit( UnionDecl * unionDecl );
     162
     163                void renameGenericParams( std::list< TypeDecl * > & params );
     164
     165          private:
     166                const Indexer * local_indexer;
     167
     168                typedef std::map< std::string, std::list< EnumInstType * > > ForwardEnumsType;
     169                typedef std::map< std::string, std::list< StructInstType * > > ForwardStructsType;
     170                typedef std::map< std::string, std::list< UnionInstType * > > ForwardUnionsType;
     171                ForwardEnumsType forwardEnums;
     172                ForwardStructsType forwardStructs;
     173                ForwardUnionsType forwardUnions;
     174                /// true if currently in a generic type body, so that type parameter instances can be renamed appropriately
     175                bool inGeneric = false;
     176        };
     177
    137178        /// Does early resolution on the expressions that give enumeration constants their values
    138179        struct ResolveEnumInitializers final : public WithIndexer, public WithGuards, public WithVisitorRef<ResolveEnumInitializers>, public WithShortCircuiting {
     
    152193                void previsit( StructDecl * aggrDecl );
    153194                void previsit( UnionDecl * aggrDecl );
     195        };
     196
     197        // These structs are the sub-sub-passes of ForallPointerDecay_old.
     198
     199        struct TraitExpander_old final {
     200                void previsit( FunctionType * );
     201                void previsit( StructDecl * );
     202                void previsit( UnionDecl * );
     203        };
     204
     205        struct AssertionFixer_old final {
     206                void previsit( FunctionType * );
     207                void previsit( StructDecl * );
     208                void previsit( UnionDecl * );
     209        };
     210
     211        struct CheckOperatorTypes_old final {
     212                void previsit( ObjectDecl * );
     213        };
     214
     215        struct FixUniqueIds_old final {
     216                void previsit( DeclarationWithType * );
    154217        };
    155218
     
    295358
    296359        void validate_A( std::list< Declaration * > & translationUnit ) {
     360                PassVisitor<EnumAndPointerDecay_old> epc;
    297361                PassVisitor<HoistTypeDecls> hoistDecls;
    298362                {
     
    303367                        ReplaceTypedef::replaceTypedef( translationUnit );
    304368                        ReturnTypeFixer::fix( translationUnit ); // must happen before autogen
    305                         decayEnumsAndPointers( translationUnit ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes_old because it is an indexer and needs correct types for mangling
    306                 }
     369                        acceptAll( translationUnit, epc ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes_old because it is an indexer and needs correct types for mangling
     370                }
     371        }
     372
     373        void linkReferenceToTypes( std::list< Declaration * > & translationUnit ) {
     374                PassVisitor<LinkReferenceToTypes_old> lrt( nullptr );
     375                acceptAll( translationUnit, lrt ); // must happen before autogen, because sized flag needs to propagate to generated functions
    307376        }
    308377
     
    343412                        });
    344413                }
     414        }
     415
     416        static void decayForallPointers( std::list< Declaration * > & translationUnit ) {
     417                PassVisitor<TraitExpander_old> te;
     418                acceptAll( translationUnit, te );
     419                PassVisitor<AssertionFixer_old> af;
     420                acceptAll( translationUnit, af );
     421                PassVisitor<CheckOperatorTypes_old> cot;
     422                acceptAll( translationUnit, cot );
     423                PassVisitor<FixUniqueIds_old> fui;
     424                acceptAll( translationUnit, fui );
    345425        }
    346426
     
    421501        }
    422502
     503        void validateType( Type * type, const Indexer * indexer ) {
     504                PassVisitor<EnumAndPointerDecay_old> epc;
     505                PassVisitor<LinkReferenceToTypes_old> lrt( indexer );
     506                PassVisitor<TraitExpander_old> te;
     507                PassVisitor<AssertionFixer_old> af;
     508                PassVisitor<CheckOperatorTypes_old> cot;
     509                PassVisitor<FixUniqueIds_old> fui;
     510                type->accept( epc );
     511                type->accept( lrt );
     512                type->accept( te );
     513                type->accept( af );
     514                type->accept( cot );
     515                type->accept( fui );
     516        }
     517
    423518        void HoistTypeDecls::handleType( Type * type ) {
    424519                // some type declarations are buried in expressions and not easy to hoist during parsing; hoist them here
     
    613708        }
    614709
     710        void EnumAndPointerDecay_old::previsit( EnumDecl * enumDecl ) {
     711                // Set the type of each member of the enumeration to be EnumConstant
     712                for ( std::list< Declaration * >::iterator i = enumDecl->members.begin(); i != enumDecl->members.end(); ++i ) {
     713                        ObjectDecl * obj = dynamic_cast< ObjectDecl * >( * i );
     714                        assert( obj );
     715                        obj->set_type( new EnumInstType( Type::Qualifiers( Type::Const ), enumDecl->name ) );
     716                } // for
     717        }
     718
     719        namespace {
     720                template< typename DWTList >
     721                void fixFunctionList( DWTList & dwts, bool isVarArgs, FunctionType * func ) {
     722                        auto nvals = dwts.size();
     723                        bool containsVoid = false;
     724                        for ( auto & dwt : dwts ) {
     725                                // fix each DWT and record whether a void was found
     726                                containsVoid |= fixFunction( dwt );
     727                        }
     728
     729                        // the only case in which "void" is valid is where it is the only one in the list
     730                        if ( containsVoid && ( nvals > 1 || isVarArgs ) ) {
     731                                SemanticError( func, "invalid type void in function type " );
     732                        }
     733
     734                        // one void is the only thing in the list; remove it.
     735                        if ( containsVoid ) {
     736                                delete dwts.front();
     737                                dwts.clear();
     738                        }
     739                }
     740        }
     741
     742        void EnumAndPointerDecay_old::previsit( FunctionType * func ) {
     743                // Fix up parameters and return types
     744                fixFunctionList( func->parameters, func->isVarArgs, func );
     745                fixFunctionList( func->returnVals, false, func );
     746        }
     747
     748        LinkReferenceToTypes_old::LinkReferenceToTypes_old( const Indexer * other_indexer ) : WithIndexer( false ) {
     749                if ( other_indexer ) {
     750                        local_indexer = other_indexer;
     751                } else {
     752                        local_indexer = &indexer;
     753                } // if
     754        }
     755
     756        void LinkReferenceToTypes_old::postvisit( EnumInstType * enumInst ) {
     757                const EnumDecl * st = local_indexer->lookupEnum( enumInst->name );
     758                // it's not a semantic error if the enum is not found, just an implicit forward declaration
     759                if ( st ) {
     760                        enumInst->baseEnum = const_cast<EnumDecl *>(st); // Just linking in the node
     761                } // if
     762                if ( ! st || ! st->body ) {
     763                        // use of forward declaration
     764                        forwardEnums[ enumInst->name ].push_back( enumInst );
     765                } // if
     766        }
     767        void LinkReferenceToTypes_old::postvisit( StructInstType * structInst ) {
     768                const StructDecl * st = local_indexer->lookupStruct( structInst->name );
     769                // it's not a semantic error if the struct is not found, just an implicit forward declaration
     770                if ( st ) {
     771                        structInst->baseStruct = const_cast<StructDecl *>(st); // Just linking in the node
     772                } // if
     773                if ( ! st || ! st->body ) {
     774                        // use of forward declaration
     775                        forwardStructs[ structInst->name ].push_back( structInst );
     776                } // if
     777        }
     778
     779        void LinkReferenceToTypes_old::postvisit( UnionInstType * unionInst ) {
     780                const UnionDecl * un = local_indexer->lookupUnion( unionInst->name );
     781                // it's not a semantic error if the union is not found, just an implicit forward declaration
     782                if ( un ) {
     783                        unionInst->baseUnion = const_cast<UnionDecl *>(un); // Just linking in the node
     784                } // if
     785                if ( ! un || ! un->body ) {
     786                        // use of forward declaration
     787                        forwardUnions[ unionInst->name ].push_back( unionInst );
     788                } // if
     789        }
     790
     791        void LinkReferenceToTypes_old::previsit( QualifiedType * ) {
     792                visit_children = false;
     793        }
     794
     795        void LinkReferenceToTypes_old::postvisit( QualifiedType * qualType ) {
     796                // linking only makes sense for the 'oldest ancestor' of the qualified type
     797                qualType->parent->accept( * visitor );
     798        }
     799
     800        template< typename Decl >
     801        void normalizeAssertions( std::list< Decl * > & assertions ) {
     802                // ensure no duplicate trait members after the clone
     803                auto pred = [](Decl * d1, Decl * d2) {
     804                        // only care if they're equal
     805                        DeclarationWithType * dwt1 = dynamic_cast<DeclarationWithType *>( d1 );
     806                        DeclarationWithType * dwt2 = dynamic_cast<DeclarationWithType *>( d2 );
     807                        if ( dwt1 && dwt2 ) {
     808                                if ( dwt1->name == dwt2->name && ResolvExpr::typesCompatible( dwt1->get_type(), dwt2->get_type(), SymTab::Indexer() ) ) {
     809                                        // std::cerr << "=========== equal:" << std::endl;
     810                                        // std::cerr << "d1: " << d1 << std::endl;
     811                                        // std::cerr << "d2: " << d2 << std::endl;
     812                                        return false;
     813                                }
     814                        }
     815                        return d1 < d2;
     816                };
     817                std::set<Decl *, decltype(pred)> unique_members( assertions.begin(), assertions.end(), pred );
     818                // if ( unique_members.size() != assertions.size() ) {
     819                //      std::cerr << "============different" << std::endl;
     820                //      std::cerr << unique_members.size() << " " << assertions.size() << std::endl;
     821                // }
     822
     823                std::list< Decl * > order;
     824                order.splice( order.end(), assertions );
     825                std::copy_if( order.begin(), order.end(), back_inserter( assertions ), [&]( Decl * decl ) {
     826                        return unique_members.count( decl );
     827                });
     828        }
     829
    615830        // expand assertions from trait instance, performing the appropriate type variable substitutions
    616831        template< typename Iterator >
     
    623838                // substitute trait decl parameters for instance parameters
    624839                applySubstitution( inst->baseTrait->parameters.begin(), inst->baseTrait->parameters.end(), inst->parameters.begin(), asserts.begin(), asserts.end(), out );
     840        }
     841
     842        void LinkReferenceToTypes_old::postvisit( TraitDecl * traitDecl ) {
     843                if ( traitDecl->name == "sized" ) {
     844                        // "sized" is a special trait - flick the sized status on for the type variable
     845                        assertf( traitDecl->parameters.size() == 1, "Built-in trait 'sized' has incorrect number of parameters: %zd", traitDecl->parameters.size() );
     846                        TypeDecl * td = traitDecl->parameters.front();
     847                        td->set_sized( true );
     848                }
     849
     850                // move assertions from type parameters into the body of the trait
     851                for ( TypeDecl * td : traitDecl->parameters ) {
     852                        for ( DeclarationWithType * assert : td->assertions ) {
     853                                if ( TraitInstType * inst = dynamic_cast< TraitInstType * >( assert->get_type() ) ) {
     854                                        expandAssertions( inst, back_inserter( traitDecl->members ) );
     855                                } else {
     856                                        traitDecl->members.push_back( assert->clone() );
     857                                }
     858                        }
     859                        deleteAll( td->assertions );
     860                        td->assertions.clear();
     861                } // for
     862        }
     863
     864        void LinkReferenceToTypes_old::postvisit( TraitInstType * traitInst ) {
     865                // handle other traits
     866                const TraitDecl * traitDecl = local_indexer->lookupTrait( traitInst->name );
     867                if ( ! traitDecl ) {
     868                        SemanticError( traitInst->location, "use of undeclared trait " + traitInst->name );
     869                } // if
     870                if ( traitDecl->parameters.size() != traitInst->parameters.size() ) {
     871                        SemanticError( traitInst, "incorrect number of trait parameters: " );
     872                } // if
     873                traitInst->baseTrait = const_cast<TraitDecl *>(traitDecl); // Just linking in the node
     874
     875                // need to carry over the 'sized' status of each decl in the instance
     876                for ( auto p : group_iterate( traitDecl->parameters, traitInst->parameters ) ) {
     877                        TypeExpr * expr = dynamic_cast< TypeExpr * >( std::get<1>(p) );
     878                        if ( ! expr ) {
     879                                SemanticError( std::get<1>(p), "Expression parameters for trait instances are currently unsupported: " );
     880                        }
     881                        if ( TypeInstType * inst = dynamic_cast< TypeInstType * >( expr->get_type() ) ) {
     882                                TypeDecl * formalDecl = std::get<0>(p);
     883                                TypeDecl * instDecl = inst->baseType;
     884                                if ( formalDecl->get_sized() ) instDecl->set_sized( true );
     885                        }
     886                }
     887                // normalizeAssertions( traitInst->members );
     888        }
     889
     890        void LinkReferenceToTypes_old::postvisit( EnumDecl * enumDecl ) {
     891                // visit enum members first so that the types of self-referencing members are updated properly
     892                // Replace the enum base; right now it works only for StructEnum
     893                if ( enumDecl->base && dynamic_cast<TypeInstType*>(enumDecl->base) ) {
     894                        std::string baseName = static_cast<TypeInstType*>(enumDecl->base)->name;
     895                        const StructDecl * st = local_indexer->lookupStruct( baseName );
     896                        if ( st ) {
     897                                enumDecl->base = new StructInstType(Type::Qualifiers(),const_cast<StructDecl *>(st)); // Just linking in the node
     898                        }
     899                }
     900                if ( enumDecl->body ) {
     901                        ForwardEnumsType::iterator fwds = forwardEnums.find( enumDecl->name );
     902                        if ( fwds != forwardEnums.end() ) {
     903                                for ( std::list< EnumInstType * >::iterator inst = fwds->second.begin(); inst != fwds->second.end(); ++inst ) {
     904                                        (* inst)->baseEnum = enumDecl;
     905                                } // for
     906                                forwardEnums.erase( fwds );
     907                        } // if
     908                } // if
     909        }
     910
     911        void LinkReferenceToTypes_old::renameGenericParams( std::list< TypeDecl * > & params ) {
     912                // rename generic type parameters uniquely so that they do not conflict with user-defined function forall parameters, e.g.
     913                //   forall(otype T)
     914                //   struct Box {
     915                //     T x;
     916                //   };
     917                //   forall(otype T)
     918                //   void f(Box(T) b) {
     919                //     ...
     920                //   }
     921                // The T in Box and the T in f are different, so internally the naming must reflect that.
     922                GuardValue( inGeneric );
     923                inGeneric = ! params.empty();
     924                for ( TypeDecl * td : params ) {
     925                        td->name = "__" + td->name + "_generic_";
     926                }
     927        }
     928
     929        void LinkReferenceToTypes_old::previsit( StructDecl * structDecl ) {
     930                renameGenericParams( structDecl->parameters );
     931        }
     932
     933        void LinkReferenceToTypes_old::previsit( UnionDecl * unionDecl ) {
     934                renameGenericParams( unionDecl->parameters );
     935        }
     936
     937        void LinkReferenceToTypes_old::postvisit( StructDecl * structDecl ) {
     938                // visit struct members first so that the types of self-referencing members are updated properly
     939                // xxx - need to ensure that type parameters match up between forward declarations and definition (most importantly, number of type parameters and their defaults)
     940                if ( structDecl->body ) {
     941                        ForwardStructsType::iterator fwds = forwardStructs.find( structDecl->name );
     942                        if ( fwds != forwardStructs.end() ) {
     943                                for ( std::list< StructInstType * >::iterator inst = fwds->second.begin(); inst != fwds->second.end(); ++inst ) {
     944                                        (* inst)->baseStruct = structDecl;
     945                                } // for
     946                                forwardStructs.erase( fwds );
     947                        } // if
     948                } // if
     949        }
     950
     951        void LinkReferenceToTypes_old::postvisit( UnionDecl * unionDecl ) {
     952                if ( unionDecl->body ) {
     953                        ForwardUnionsType::iterator fwds = forwardUnions.find( unionDecl->name );
     954                        if ( fwds != forwardUnions.end() ) {
     955                                for ( std::list< UnionInstType * >::iterator inst = fwds->second.begin(); inst != fwds->second.end(); ++inst ) {
     956                                        (* inst)->baseUnion = unionDecl;
     957                                } // for
     958                                forwardUnions.erase( fwds );
     959                        } // if
     960                } // if
     961        }
     962
     963        void LinkReferenceToTypes_old::postvisit( TypeInstType * typeInst ) {
     964                // ensure generic parameter instances are renamed like the base type
     965                if ( inGeneric && typeInst->baseType ) typeInst->name = typeInst->baseType->name;
     966                if ( const NamedTypeDecl * namedTypeDecl = local_indexer->lookupType( typeInst->name ) ) {
     967                        if ( const TypeDecl * typeDecl = dynamic_cast< const TypeDecl * >( namedTypeDecl ) ) {
     968                                typeInst->set_isFtype( typeDecl->kind == TypeDecl::Ftype );
     969                        } // if
     970                } // if
    625971        }
    626972
     
    651997                                                }
    652998                                        }
     999                                       
    6531000                                }
    6541001                        }
     
    7381085        void ForallPointerDecay_old::previsit( UnionDecl * aggrDecl ) {
    7391086                forallFixer( aggrDecl->parameters, aggrDecl );
     1087        }
     1088
     1089        void TraitExpander_old::previsit( FunctionType * ftype ) {
     1090                expandTraits( ftype->forall );
     1091        }
     1092
     1093        void TraitExpander_old::previsit( StructDecl * aggrDecl ) {
     1094                expandTraits( aggrDecl->parameters );
     1095        }
     1096
     1097        void TraitExpander_old::previsit( UnionDecl * aggrDecl ) {
     1098                expandTraits( aggrDecl->parameters );
     1099        }
     1100
     1101        void AssertionFixer_old::previsit( FunctionType * ftype ) {
     1102                fixAssertions( ftype->forall, ftype );
     1103        }
     1104
     1105        void AssertionFixer_old::previsit( StructDecl * aggrDecl ) {
     1106                fixAssertions( aggrDecl->parameters, aggrDecl );
     1107        }
     1108
     1109        void AssertionFixer_old::previsit( UnionDecl * aggrDecl ) {
     1110                fixAssertions( aggrDecl->parameters, aggrDecl );
     1111        }
     1112
     1113        void CheckOperatorTypes_old::previsit( ObjectDecl * object ) {
     1114                // ensure that operator names only apply to functions or function pointers
     1115                if ( CodeGen::isOperator( object->name ) && ! dynamic_cast< FunctionType * >( object->type->stripDeclarator() ) ) {
     1116                        SemanticError( object->location, toCString( "operator ", object->name.c_str(), " is not a function or function pointer." )  );
     1117                }
     1118        }
     1119
     1120        void FixUniqueIds_old::previsit( DeclarationWithType * decl ) {
     1121                decl->fixUniqueId();
    7401122        }
    7411123
  • src/SymTab/Validate.h

    re5d9274 r015925a  
    1010// Author           : Richard C. Bilson
    1111// Created On       : Sun May 17 21:53:34 2015
    12 // Last Modified By : Andrew Beach
    13 // Last Modified On : Tue May 17 14:35:00 2022
    14 // Update Count     : 5
     12// Last Modified By : Peter A. Buhr
     13// Last Modified On : Sat Jul 22 09:46:07 2017
     14// Update Count     : 4
    1515//
    1616
     
    3333        /// Normalizes struct and function declarations
    3434        void validate( std::list< Declaration * > &translationUnit, bool doDebug = false );
     35        void validateType( Type *type, const Indexer *indexer );
    3536
    3637        // Sub-passes of validate.
     
    4142        void validate_E( std::list< Declaration * > &translationUnit );
    4243        void validate_F( std::list< Declaration * > &translationUnit );
     44        void linkReferenceToTypes( std::list< Declaration * > &translationUnit );
     45
     46        const ast::Type * validateType(
     47                const CodeLocation & loc, const ast::Type * type, const ast::SymbolTable & symtab );
    4348} // namespace SymTab
    4449
  • src/SymTab/demangler.cc

    re5d9274 r015925a  
    1 #include "Demangle.h"
     1#include "Mangler.h"
    22#include <iostream>
    33#include <fstream>
  • src/SymTab/module.mk

    re5d9274 r015925a  
    1111## Created On       : Mon Jun  1 17:49:17 2015
    1212## Last Modified By : Andrew Beach
    13 ## Last Modified On : Tue May 17 14:46:00 2022
    14 ## Update Count     : 5
     13## Last Modified On : Thr Aug 10 16:08:00 2017
     14## Update Count     : 4
    1515###############################################################################
    1616
    1717SRC_SYMTAB = \
    18         SymTab/Autogen.cc \
    19         SymTab/Autogen.h \
    20         SymTab/FixFunction.cc \
    21         SymTab/FixFunction.h \
    22         SymTab/Indexer.cc \
    23         SymTab/Indexer.h \
    24         SymTab/Mangler.cc \
    25         SymTab/ManglerCommon.cc \
    26         SymTab/Mangler.h \
    27         SymTab/ValidateType.cc \
    28         SymTab/ValidateType.h
     18      SymTab/Autogen.cc \
     19      SymTab/Autogen.h \
     20      SymTab/FixFunction.cc \
     21      SymTab/FixFunction.h \
     22      SymTab/Indexer.cc \
     23      SymTab/Indexer.h \
     24      SymTab/Mangler.cc \
     25      SymTab/ManglerCommon.cc \
     26      SymTab/Mangler.h \
     27      SymTab/Validate.cc \
     28      SymTab/Validate.h
    2929
    30 SRC += $(SRC_SYMTAB) \
    31         SymTab/Validate.cc \
    32         SymTab/Validate.h
    33 
    34 SRCDEMANGLE += $(SRC_SYMTAB) \
    35         SymTab/Demangle.cc \
    36         SymTab/Demangle.h
     30SRC += $(SRC_SYMTAB)
     31SRCDEMANGLE += $(SRC_SYMTAB) SymTab/Demangle.cc
  • src/SynTree/module.mk

    re5d9274 r015925a  
    2424      SynTree/AttrType.cc \
    2525      SynTree/BaseSyntaxNode.h \
    26       SynTree/BaseSyntaxNode.cc \
    2726      SynTree/BasicType.cc \
    2827      SynTree/CommaExpr.cc \
  • src/Tuples/TupleExpansion.cc

    re5d9274 r015925a  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue May 17 15:02:00 2022
    13 // Update Count     : 25
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Dec 13 23:45:51 2019
     13// Update Count     : 24
    1414//
    1515
     
    367367                return nullptr;
    368368        }
     369
     370        namespace {
     371                /// determines if impurity (read: side-effects) may exist in a piece of code. Currently gives a very crude approximation, wherein any function call expression means the code may be impure
     372                struct ImpurityDetector : public WithShortCircuiting {
     373                        ImpurityDetector( bool ignoreUnique ) : ignoreUnique( ignoreUnique ) {}
     374
     375                        void previsit( const ApplicationExpr * appExpr ) {
     376                                visit_children = false;
     377                                if ( const DeclarationWithType * function = InitTweak::getFunction( appExpr ) ) {
     378                                        if ( function->linkage == LinkageSpec::Intrinsic ) {
     379                                                if ( function->name == "*?" || function->name == "?[?]" ) {
     380                                                        // intrinsic dereference, subscript are pure, but need to recursively look for impurity
     381                                                        visit_children = true;
     382                                                        return;
     383                                                }
     384                                        }
     385                                }
     386                                maybeImpure = true;
     387                        }
     388                        void previsit( const UntypedExpr * ) { maybeImpure = true; visit_children = false; }
     389                        void previsit( const UniqueExpr * ) {
     390                                if ( ignoreUnique ) {
     391                                        // bottom out at unique expression.
     392                                        // The existence of a unique expression doesn't change the purity of an expression.
     393                                        // That is, even if the wrapped expression is impure, the wrapper protects the rest of the expression.
     394                                        visit_children = false;
     395                                        return;
     396                                }
     397                        }
     398
     399                        bool maybeImpure = false;
     400                        bool ignoreUnique;
     401                };
     402        } // namespace
     403
     404        bool maybeImpure( const Expression * expr ) {
     405                PassVisitor<ImpurityDetector> detector( false );
     406                expr->accept( detector );
     407                return detector.pass.maybeImpure;
     408        }
     409
     410        bool maybeImpureIgnoreUnique( const Expression * expr ) {
     411                PassVisitor<ImpurityDetector> detector( true );
     412                expr->accept( detector );
     413                return detector.pass.maybeImpure;
     414        }
    369415} // namespace Tuples
    370416
  • src/Tuples/Tuples.cc

    re5d9274 r015925a  
    1010// Created On       : Mon Jun 17 14:41:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon May 16 16:15:00 2022
    13 // Update Count     : 2
     12// Last Modified On : Tue Jun 18  9:31:00 2019
     13// Update Count     : 1
    1414//
    1515
     
    1818#include "AST/Pass.hpp"
    1919#include "AST/LinkageSpec.hpp"
    20 #include "Common/PassVisitor.h"
    2120#include "InitTweak/InitTweak.h"
    2221
     
    2423
    2524namespace {
    26         /// Checks if impurity (read: side-effects) may exist in a piece of code.
    27         /// Currently gives a very crude approximation, wherein any function
    28         /// call expression means the code may be impure.
    29         struct ImpurityDetector_old : public WithShortCircuiting {
    30                 bool const ignoreUnique;
    31                 bool maybeImpure;
    32 
    33                 ImpurityDetector_old( bool ignoreUnique ) :
    34                         ignoreUnique( ignoreUnique ), maybeImpure( false )
    35                 {}
    36 
    37                 void previsit( const ApplicationExpr * appExpr ) {
    38                         visit_children = false;
    39                         if ( const DeclarationWithType * function =
    40                                         InitTweak::getFunction( appExpr ) ) {
    41                                 if ( function->linkage == LinkageSpec::Intrinsic ) {
    42                                         if ( function->name == "*?" || function->name == "?[?]" ) {
    43                                                 // intrinsic dereference, subscript are pure,
    44                                                 // but need to recursively look for impurity
    45                                                 visit_children = true;
    46                                                 return;
    47                                         }
    48                                 }
    49                         }
    50                         maybeImpure = true;
    51                 }
    52 
    53                 void previsit( const UntypedExpr * ) {
    54                         maybeImpure = true;
    55                         visit_children = false;
    56                 }
    57 
    58                 void previsit( const UniqueExpr * ) {
    59                         if ( ignoreUnique ) {
    60                                 // bottom out at unique expression.
    61                                 // The existence of a unique expression doesn't change the purity of an expression.
    62                                 // That is, even if the wrapped expression is impure, the wrapper protects the rest of the expression.
    63                                 visit_children = false;
    64                                 return;
    65                         }
    66                 }
    67         };
    68 
    69         bool detectImpurity( const Expression * expr, bool ignoreUnique ) {
    70                 PassVisitor<ImpurityDetector_old> detector( ignoreUnique );
    71                 expr->accept( detector );
    72                 return detector.pass.maybeImpure;
    73         }
    74 
    7525        /// Determines if impurity (read: side-effects) may exist in a piece of code. Currently gives
    7626        /// a very crude approximation, wherein any function call expression means the code may be
    7727        /// impure.
    7828    struct ImpurityDetector : public ast::WithShortCircuiting {
    79                 bool result = false;
     29                bool maybeImpure = false;
    8030
    8131                void previsit( ast::ApplicationExpr const * appExpr ) {
     
    8636                                }
    8737                        }
    88                         result = true; visit_children = false;
     38                        maybeImpure = true; visit_children = false;
    8939                }
    9040                void previsit( ast::UntypedExpr const * ) {
    91                         result = true; visit_children = false;
     41                        maybeImpure = true; visit_children = false;
    9242                }
    9343        };
    94 
    9544        struct ImpurityDetectorIgnoreUnique : public ImpurityDetector {
    9645                using ImpurityDetector::previsit;
     
    9948                }
    10049        };
     50
     51        template<typename Detector>
     52        bool detectImpurity( const ast::Expr * expr ) {
     53                ast::Pass<Detector> detector;
     54                expr->accept( detector );
     55                return detector.core.maybeImpure;
     56        }
    10157} // namespace
    10258
    10359bool maybeImpure( const ast::Expr * expr ) {
    104         return ast::Pass<ImpurityDetector>::read( expr );
     60        return detectImpurity<ImpurityDetector>( expr );
    10561}
    10662
    10763bool maybeImpureIgnoreUnique( const ast::Expr * expr ) {
    108         return ast::Pass<ImpurityDetectorIgnoreUnique>::read( expr );
    109 }
    110 
    111 bool maybeImpure( const Expression * expr ) {
    112         return detectImpurity( expr, false );
    113 }
    114 
    115 bool maybeImpureIgnoreUnique( const Expression * expr ) {
    116         return detectImpurity( expr, true );
     64        return detectImpurity<ImpurityDetectorIgnoreUnique>( expr );
    11765}
    11866
  • src/Tuples/module.mk

    re5d9274 r015925a  
    1010## Author           : Richard C. Bilson
    1111## Created On       : Mon Jun  1 17:49:17 2015
    12 ## Last Modified By : Andrew Beach
    13 ## Last Modified On : Mon May 17 15:00:00 2022
    14 ## Update Count     : 3
     12## Last Modified By : Henry Xue
     13## Last Modified On : Mon Aug 23 15:36:09 2021
     14## Update Count     : 2
    1515###############################################################################
    1616
     
    2424        Tuples/Tuples.h
    2525
     26
    2627SRC += $(SRC_TUPLES)
    27 
    2828SRCDEMANGLE += $(SRC_TUPLES)
  • src/Validate/Autogen.cpp

    re5d9274 r015925a  
    402402        auto retval = srcParam();
    403403        retval->name = "_ret";
    404         // xxx - Adding this unused attribute can slience unused variable warning
    405         // However, some code might not be compiled as expected
    406         // Temporarily disabled
    407         // retval->attributes.push_back(new ast::Attribute("unused"));
    408404        return genProto( "?=?", { dstParam(), srcParam() }, { retval } );
    409405}
  • src/Validate/module.mk

    re5d9274 r015925a  
    1010## Author           : Rob Schluntz
    1111## Created On       : Fri Jul 27 10:10:10 2018
    12 ## Last Modified By : Andrew Beach
    13 ## Last Modified On : Tue May 17 14:59:00 2022
    14 ## Update Count     : 3
     12## Last Modified By : Rob Schluntz
     13## Last Modified On : Fri Jul 27 10:10:26 2018
     14## Update Count     : 2
    1515###############################################################################
    1616
    1717SRC_VALIDATE = \
    18         Validate/FindSpecialDecls.cc \
    19         Validate/FindSpecialDecls.h
    20 
    21 SRC += $(SRC_VALIDATE) \
    2218        Validate/Autogen.cpp \
    2319        Validate/Autogen.hpp \
     
    2622        Validate/EliminateTypedef.cpp \
    2723        Validate/EliminateTypedef.hpp \
    28         Validate/FindSpecialDeclsNew.cpp \
    2924        Validate/FixQualifiedTypes.cpp \
    3025        Validate/FixQualifiedTypes.hpp \
     
    4338        Validate/NoIdSymbolTable.hpp \
    4439        Validate/ReturnCheck.cpp \
    45         Validate/ReturnCheck.hpp
     40        Validate/ReturnCheck.hpp \
     41        Validate/FindSpecialDeclsNew.cpp \
     42        Validate/FindSpecialDecls.cc \
     43        Validate/FindSpecialDecls.h
    4644
     45SRC += $(SRC_VALIDATE)
    4746SRCDEMANGLE += $(SRC_VALIDATE)
  • src/Virtual/module.mk

    re5d9274 r015925a  
    1111## Created On       : Tus Jul 25 10:18:00 2017
    1212## Last Modified By : Andrew Beach
    13 ## Last Modified On : Tus May 17 14:59:00 2022
    14 ## Update Count     : 1
     13## Last Modified On : Tus Jul 25 10:18:00 2017
     14## Update Count     : 0
    1515###############################################################################
    1616
    17 SRC += \
    18         Virtual/ExpandCasts.cc \
    19         Virtual/ExpandCasts.h \
    20         Virtual/Tables.cc \
    21         Virtual/Tables.h
     17SRC += Virtual/ExpandCasts.cc Virtual/ExpandCasts.h \
     18        Virtual/Tables.cc Virtual/Tables.h
     19
     20SRCDEMANGLE += Virtual/Tables.cc
  • src/main.cc

    re5d9274 r015925a  
    7070#include "ResolvExpr/Resolver.h"            // for resolve
    7171#include "SymTab/Validate.h"                // for validate
    72 #include "SymTab/ValidateType.h"            // for linkReferenceToTypes
    7372#include "SynTree/LinkageSpec.h"            // for Spec, Cforall, Intrinsic
    7473#include "SynTree/Declaration.h"            // for Declaration
  • tests/.expect/attributes.nast.x64.txt

    re5d9274 r015925a  
    13391339        }
    13401340
    1341         return (*_X4_dstM12__anonymous4_2);
     1341        {
     1342            ((void)(_X4_retM12__anonymous4_2=(*_X4_dstM12__anonymous4_2)) /* ?{} */);
     1343        }
     1344
     1345        return _X4_retM12__anonymous4_2;
    13421346    }
    13431347    {
  • tests/.expect/attributes.nast.x86.txt

    re5d9274 r015925a  
    13391339        }
    13401340
    1341         return (*_X4_dstM12__anonymous4_2);
     1341        {
     1342            ((void)(_X4_retM12__anonymous4_2=(*_X4_dstM12__anonymous4_2)) /* ?{} */);
     1343        }
     1344
     1345        return _X4_retM12__anonymous4_2;
    13421346    }
    13431347    {
  • tests/.expect/attributes.oast.x64.txt

    re5d9274 r015925a  
    13391339        }
    13401340
    1341         return (*_X4_dstM12__anonymous4_2);
     1341        {
     1342            ((void)(_X4_retM12__anonymous4_2=(*_X4_dstM12__anonymous4_2)) /* ?{} */);
     1343        }
     1344
     1345        return _X4_retM12__anonymous4_2;
    13421346    }
    13431347    {
  • tests/.expect/attributes.oast.x86.txt

    re5d9274 r015925a  
    13391339        }
    13401340
     1341        {
     1342            ((void)(_X4_retM12__anonymous4_2=(*_X4_dstM12__anonymous4_2)) /* ?{} */);
     1343        }
     1344
    13411345        return _X4_retM12__anonymous4_2;
    13421346    }
  • tests/.expect/quasiKeyword.txt

    re5d9274 r015925a  
    1 quasiKeyword.cfa:52:25: warning: Compiled
     1quasiKeyword.cfa:54:25: warning: Compiled
  • tests/exceptions/defaults.cfa

    re5d9274 r015925a  
    22
    33#include <string.h>
     4#include <exception.hfa>
    45
    56exception log_message {
     
    78};
    89
    9 // Manually define the virtual table and helper functions.
    10 void copy(log_message * this, log_message * that) {
    11         *this = *that;
    12 }
    13 
     10_EHM_DEFINE_COPY(log_message, )
    1411const char * msg(log_message * this) {
    1512        return this->msg;
    1613}
    17 
    18 const struct log_message_vtable log_vt @= {
    19         .__cfavir_typeid : &__cfatid_log_message,
    20         .size : sizeof(struct log_message),
    21         .copy : copy,
    22         .^?{} : ^?{},
    23         .msg : msg,
    24 };
     14_EHM_VIRTUAL_TABLE(log_message, , log_vt);
    2515
    2616// Logging messages don't have to be handled.
  • tests/include/.expect/includes.nast.txt

    re5d9274 r015925a  
    1 include/includes.cfa:173:25: warning: Compiled
     1include/includes.cfa:169:25: warning: Compiled
  • tests/include/includes.cfa

    re5d9274 r015925a  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun May 22 08:27:20 2022
    13 // Update Count     : 779
     12// Last Modified On : Tue May 10 16:36:44 2022
     13// Update Count     : 776
    1414//
    1515
     
    4747#endif
    4848#include <execinfo.h>
    49 #if __has_include( "expat.h" )
    50 #include <expat.h>                                                                              // may not be installed
     49#include <expat.h>
    5150#include <expat_external.h>
    52 #endif
    5351#include <fcntl.h>
    5452#include <features.h>
     
    8179//#include <link.h>                                                                             // CFA bug #240 nested anonymous enum fails
    8280#include <locale.h>
    83 #if __has_include( "ltdl.h" )
    84 #include <ltdl.h>                                                                               // may not be installed
    85 #endif
     81#include <ltdl.h>
    8682//#include <malloc.h>                                                                   // cannot include in extern "C" because of CFA #include_next
    8783#include <math.h>
  • tests/linking/exception-nothreads.cfa

    re5d9274 r015925a  
    1515
    1616#include <stdlib.hfa>
     17#include <exception.hfa>
    1718
    18 exception ping {};
    19 vtable(ping) ping_vt;
     19EHM_EXCEPTION(ping)();
     20EHM_VIRTUAL_TABLE(ping, ping_vt);
    2021
    2122int main(void) {
  • tests/linking/exception-withthreads.cfa

    re5d9274 r015925a  
    1515
    1616#include <stdlib.hfa>
     17#include <exception.hfa>
    1718#include "../exceptions/with-threads.hfa"
    1819
    19 exception ping {};
    20 vtable(ping) ping_vt;
     20EHM_EXCEPTION(ping)();
     21EHM_VIRTUAL_TABLE(ping, ping_vt);
    2122
    2223int main(void) {
  • tests/pybin/settings.py

    re5d9274 r015925a  
    201201        global output_width
    202202        output_width = max(map(lambda t: len(t.target()), tests))
    203         # 35 is the maximum width of the name field before we get line wrapping.
    204         output_width = min(output_width, 35)
  • tests/pybin/test_run.py

    re5d9274 r015925a  
    4343                return os.path.normpath( os.path.join(settings.BUILDDIR, self.path, self.name) )
    4444
    45         def format_target(self, width):
    46                 target = self.target()
    47                 length = len(target)
    48                 if length < width:
    49                         return '{0:{width}}'.format(target, width=width)
    50                 elif length == width:
    51                         return target
    52                 else:
    53                         return '...' + target[3-width:]
    54 
    5545        @staticmethod
    5646        def valid_name(name):
  • tests/quasiKeyword.cfa

    re5d9274 r015925a  
    44// quasiKeyword.cfa -- test that quasi-keywords can be used for variable and functions names, as well as keywords in
    55//                                         control structures.
    6 //
     6// 
    77// Author           : Peter A. Buhr
    88// Created On       : Wed Feb 17 10:33:49 2021
     
    1010// Last Modified On : Sat Jun  5 10:07:59 2021
    1111// Update Count     : 8
    12 //
     12// 
    1313
    14 exception E {};
     14#include <exception.hfa>
     15
     16EHM_EXCEPTION( E )();
    1517
    1618void catch( int i ) {}
     
    4749                } fixup ( E * ) {
    4850                } finally {
    49                 }
     51                } 
    5052        else catch = 3;
    5153
  • tests/test.py

    re5d9274 r015925a  
    132132        parser.add_argument('--install', help='Run all tests based on installed binaries or tree binaries', type=comma_separated(yes_no), default='no')
    133133        parser.add_argument('--continue', help='When multiple specifications are passed (debug/install/arch), sets whether or not to continue if the last specification failed', type=yes_no, default='yes', dest='continue_')
    134         parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=180)
     134        parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=120)
    135135        parser.add_argument('--global-timeout', help='Maximum cumulative duration in seconds after the ALL tests are considered to have timed out', type=int, default=7200)
    136136        parser.add_argument('--timeout-with-gdb', help='Instead of killing the command when it times out, orphan it and print process id to allow gdb to attach', type=yes_no, default="no")
     
    252252        try :
    253253                # print formated name
    254                 name_txt = t.format_target(width=settings.output_width) + '  '
     254                name_txt = '{0:{width}}  '.format(t.target(), width=settings.output_width)
    255255
    256256                retcode, error, duration = run_single_test(t)
Note: See TracChangeset for help on using the changeset viewer.