Changes in / [9e1eabc:65d6de4]


Ignore:
Files:
2 added
3 deleted
31 edited

Legend:

Unmodified
Added
Removed
  • Jenkinsfile

    r9e1eabc r65d6de4  
    1515        arch_name               = ''
    1616        architecture    = ''
    17 
     17       
    1818        do_alltests             = false
    1919        do_benchmark    = false
     
    183183                sh 'make clean > /dev/null'
    184184                sh 'make > /dev/null 2>&1'
    185         }
     185        } 
    186186        catch (Exception caughtError) {
    187187                err = caughtError //rethrow error later
     
    257257def build() {
    258258        build_stage('Build') {
    259 
     259       
    260260                def install_dir = pwd tmp: true
    261 
     261               
    262262                //Configure the conpilation (Output is not relevant)
    263263                //Use the current directory as the installation target so nothing
     
    290290                if( !do_benchmark ) return
    291291
     292                //Write the commit id to Benchmark
     293                writeFile  file: 'bench.csv', text:'data=' + gitRefNewValue + ',' + arch_name + ','
     294 
    292295                //Append bench results
    293                 sh 'make -C src/benchmark --no-print-directory jenkins githash=' + gitRefNewValue + ' arch=' + arch_name + ' | tee bench.json'
     296                sh 'make -C src/benchmark --no-print-directory csv-data >> bench.csv'
    294297        }
    295298}
     
    324327
    325328                //Then publish the results
    326                 sh 'curl -H "Content-Type: application/json" --silent --data @bench.json http://plg2:8082/jenkins/publish > /dev/null || true'
     329                sh 'curl --silent --data @bench.csv http://plg2:8082/jenkins/publish > /dev/null || true'
    327330        }
    328331}
  • doc/proposals/concurrency/Makefile

    r9e1eabc r65d6de4  
    3232PICTURES = ${addprefix build/, ${addsuffix .pstex, \
    3333        system \
    34         monitor_structs \
    3534}}
    3635
     
    8483        dvips $< -o $@
    8584
    86 build/${basename ${DOCUMENT}}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${basename ${DOCUMENT}}.tex ../../LaTeXmacros/common.tex ../../LaTeXmacros/indexstyle annex/local.bib
     85build/${basename ${DOCUMENT}}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${basename ${DOCUMENT}}.tex ../../LaTeXmacros/common.tex ../../LaTeXmacros/indexstyle
    8786
    8887        @ if [ ! -r ${basename $@}.ind ] ; then touch ${basename $@}.ind ; fi                           # Conditionally create an empty *.ind (index) file for inclusion until makeindex is run.
     
    9594        @ -${BibTeX} ${basename $@}
    9695        @ echo "Glossary"
    97         @ makeglossaries -q -s ${basename $@}.ist ${basename $@}                                                # Make index from *.aux entries and input index at end of document
     96        makeglossaries -q -s ${basename $@}.ist ${basename $@}                                          # Make index from *.aux entries and input index at end of document
    9897        @ echo ".dvi generation"
    9998        @ -build/bump_ver.sh
  • doc/proposals/concurrency/annex/local.bib

    r9e1eabc r65d6de4  
    5252        year            = 2017
    5353}
    54 
    55 @manual{Cpp-Transactions,
    56         keywords        = {C++, Transactional Memory},
    57         title           = {Technical Specification for C++ Extensions for Transactional Memory},
    58         organization= {International Standard ISO/IEC TS 19841:2015 },
    59         publisher   = {American National Standards Institute},
    60         address = {http://www.iso.org},
    61         year            = 2015,
    62 }
    63 
    64 @article{BankTransfer,
    65         keywords        = {Bank Transfer},
    66         title   = {Bank Account Transfer Problem},
    67         publisher       = {Wiki Wiki Web},
    68         address = {http://wiki.c2.com},
    69         year            = 2010
    70 }
    71 
    72 @misc{2FTwoHardThings,
    73         keywords        = {Hard Problem},
    74         title   = {TwoHardThings},
    75         author  = {Martin Fowler},
    76         address = {https://martinfowler.com/bliki/TwoHardThings.html},
    77         year            = 2009
    78 }
    79 
    80 @article{IntrusiveData,
    81         title           = {Intrusive Data Structures},
    82         author  = {Jiri Soukup},
    83         journal = {CppReport},
    84         year            = 1998,
    85         month           = May,
    86         volume  = {10/No5.},
    87         page            = 22
    88 }
    89 
    90 @misc{affinityLinux,
    91         title           = "{Linux man page - sched\_setaffinity(2)}"
    92 }
    93 
    94 @misc{affinityWindows,
    95         title           = "{Windows (vs.85) - SetThreadAffinityMask function}"
    96 }
    97 
    98 @misc{affinityFreebsd,
    99         title           = "{FreeBSD General Commands Manual - CPUSET(1)}"
    100 }
    101 
    102 @misc{affinityNetbsd,
    103         title           = "{NetBSD Library Functions Manual - AFFINITY(3)}"
    104 }
    105 
    106 @misc{affinityMacosx,
    107         title           = "{Affinity API Release Notes for OS X v10.5}"
    108 }
  • doc/proposals/concurrency/figures/int_monitor.fig

    r9e1eabc r65d6de4  
    88-2
    991200 2
    10 5 1 0 1 0 7 50 -1 -1 0.000 0 1 0 0 675.000 2700.000 675 2400 375 2700 675 3000
    11 6 4533 2866 4655 3129
    12 5 1 0 1 0 7 50 -1 -1 0.000 0 1 0 0 4657.017 2997.000 4655 2873 4533 2997 4655 3121
    13 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    14          4655 2866 4655 3129
     105 1 0 1 0 7 50 -1 -1 0.000 0 1 0 0 600.000 2625.000 600 2325 300 2625 600 2925
     116 3225 4500 7425 4800
     121 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3375 4650 80 80 3375 4650 3455 4730
     131 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4725 4650 105 105 4725 4650 4830 4755
     141 3 0 1 -1 -1 0 0 4 0.000 1 0.0000 6225 4650 105 105 6225 4650 6330 4755
     154 0 -1 0 0 0 12 0.0000 2 135 1035 4950 4725 blocked task\001
     164 0 -1 0 0 0 12 0.0000 2 135 870 3525 4725 active task\001
     174 0 -1 0 0 0 12 0.0000 2 180 930 6450 4725 routine ptrs\001
    1518-6
    16 6 4725 2866 4847 3129
    17 5 1 0 1 0 7 50 -1 -1 0.000 0 1 0 0 4849.017 2997.000 4847 2873 4725 2997 4847 3121
    18 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    19          4847 2866 4847 3129
     196 8445 1695 8655 1905
     201 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 8550 1800 105 105 8550 1800 8655 1905
     214 1 -1 0 0 0 10 0.0000 2 75 75 8550 1860 a\001
    2022-6
    21 6 4911 2866 5033 3129
    22 5 1 0 1 0 7 50 -1 -1 0.000 0 1 0 0 5035.017 2997.000 5033 2873 4911 2997 5033 3121
    23 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    24          5033 2866 5033 3129
     236 8445 1395 8655 1605
     241 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 8550 1500 105 105 8550 1500 8655 1605
     254 1 -1 0 0 0 10 0.0000 2 105 90 8550 1560 b\001
    2526-6
    26 6 9027 2866 9149 3129
    27 5 1 0 1 0 7 50 -1 -1 0.000 0 0 0 0 9024.983 2997.000 9027 2873 9149 2997 9027 3121
    28 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    29          9027 2866 9027 3129
     276 3945 1695 4155 1905
     281 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4050 1800 105 105 4050 1800 4155 1905
     294 1 -1 0 0 0 10 0.0000 2 75 75 4050 1860 a\001
    3030-6
    31 6 9253 2866 9375 3129
    32 5 1 0 1 0 7 50 -1 -1 0.000 0 0 0 0 9250.983 2997.000 9253 2873 9375 2997 9253 3121
    33 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    34          9253 2866 9253 3129
    35 -6
    36 6 9478 2866 9600 3129
    37 5 1 0 1 0 7 50 -1 -1 0.000 0 0 0 0 9475.983 2997.000 9478 2873 9600 2997 9478 3121
    38 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    39          9478 2866 9478 3129
     316 3945 1395 4155 1605
     321 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4050 1500 105 105 4050 1500 4155 1605
     334 1 -1 0 0 0 10 0.0000 2 105 90 4050 1560 b\001
    4034-6
    41351 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7650 3675 80 80 7650 3675 7730 3755
    42361 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3150 3675 80 80 3150 3675 3230 3755
    43 1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 4047 1793 125 125 4047 1793 3929 1752
    44 1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 4050 1500 125 125 4050 1500 3932 1459
    45 1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 8550 1500 125 125 8550 1500 8432 1459
    46 1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 8550 1800 125 125 8550 1800 8432 1759
    47 1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 1200 2850 125 125 1200 2850 1082 2809
    48 1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 900 2850 125 125 900 2850 782 2809
    49 1 3 0 1 -1 -1 0 0 4 0.000 1 0.0000 6225 4650 105 105 6225 4650 6330 4755
    50 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3150 4650 80 80 3150 4650 3230 4730
    51 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4575 4650 105 105 4575 4650 4680 4755
    52372 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    5338         3900 1950 4200 2100
     
    7762         3000 4050 3300 4200
    78632 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    79          675 3000 1425 3000
     64         600 2925 1350 2925
    80652 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    81          675 2400 1425 2400
     66         600 2325 1350 2325
    82672 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    83          1425 2700 1500 2925
     68         1350 2625 1425 2850
    84692 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    85          1425 2400 1350 2625
     70         1350 2325 1275 2550
    86712 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    87          675 2700 1425 2700
     72         600 2625 1350 2625
     732 3 0 1 0 7 50 -1 -1 0.000 0 0 0 0 0 7
     74         1350 2775 1275 2645 1125 2645 1050 2775 1125 2905 1275 2905
     75         1350 2775
     762 3 0 1 0 7 50 -1 -1 0.000 0 0 0 0 0 7
     77         975 2775 900 2645 750 2645 675 2775 750 2905 900 2905
     78         975 2775
     792 3 0 1 0 7 50 -1 -1 0.000 0 0 0 0 0 7
     80         4800 3000 4725 2870 4575 2870 4500 3000 4575 3130 4725 3130
     81         4800 3000
     822 3 0 1 0 7 50 -1 -1 0.000 0 0 0 0 0 7
     83         5100 3000 5025 2870 4875 2870 4800 3000 4875 3130 5025 3130
     84         5100 3000
     852 3 0 1 0 7 50 -1 -1 0.000 0 0 0 0 0 7
     86         9300 3000 9225 2870 9075 2870 9000 3000 9075 3130 9225 3130
     87         9300 3000
     882 3 0 1 0 7 50 -1 -1 0.000 0 0 0 0 0 7
     89         9600 3000 9525 2870 9375 2870 9300 3000 9375 3130 9525 3130
     90         9600 3000
     912 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     92         675 2775 975 2775
     932 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     94         1050 2775 1350 2775
     952 3 0 1 0 7 50 -1 -1 0.000 0 0 0 0 0 7
     96         4875 4950 4800 4820 4650 4820 4575 4950 4650 5080 4800 5080
     97         4875 4950
     982 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     99         4575 4950 4875 4950
     1002 3 0 1 0 7 50 -1 -1 0.000 0 0 0 0 0 7
     101         3525 4970 3450 4840 3300 4840 3225 4970 3300 5100 3450 5100
     102         3525 4970
    881034 1 -1 0 0 0 12 0.0000 2 135 315 2850 4275 exit\001
    891044 1 -1 0 0 0 12 0.0000 2 135 315 7350 4275 exit\001
     
    1061214 1 -1 0 0 0 12 0.0000 2 135 495 4050 1275 queue\001
    1071224 1 -1 0 0 0 12 0.0000 2 165 420 4050 1050 entry\001
    108 4 0 0 50 -1 0 11 0.0000 2 120 705 600 2325 Condition\001
    109 4 0 -1 0 0 0 12 0.0000 2 180 930 6450 4725 routine ptrs\001
    110 4 0 -1 0 0 0 12 0.0000 2 135 1050 3300 4725 active thread\001
    111 4 0 -1 0 0 0 12 0.0000 2 135 1215 4725 4725 blocked thread\001
     1234 0 0 50 -1 0 11 0.0000 2 120 705 450 2250 Condition\001
     1244 0 0 50 -1 0 11 0.0000 2 165 630 3600 5025 signalled\001
     1254 0 0 50 -1 0 11 0.0000 2 165 525 4950 5025 waiting\001
  • doc/proposals/concurrency/text/basics.tex

    r9e1eabc r65d6de4  
    1111Execution with a single thread and multiple stacks where the thread is self-scheduling deterministically across the stacks is called coroutining. Execution with a single and multiple stacks but where the thread is scheduled by an oracle (non-deterministic from the thread perspective) across the stacks is called concurrency.
    1212
    13 Therefore, a minimal concurrency system can be achieved by creating coroutines, which instead of context switching among each other, always ask an oracle where to context switch next. While coroutines can execute on the caller's stack-frame, stackfull coroutines allow full generality and are sufficient as the basis for concurrency. The aforementioned oracle is a scheduler and the whole system now follows a cooperative threading-model (a.k.a non-preemptive scheduling). The oracle/scheduler can either be a stackless or stackfull entity and correspondingly require one or two context switches to run a different coroutine. In any case, a subset of concurrency related challenges start to appear. For the complete set of concurrency challenges to occur, the only feature missing is preemption.
    14 
    15 A scheduler introduces order of execution uncertainty, while preemption introduces uncertainty about where context-switches occur. Mutual-exclusion and synchronisation are ways of limiting non-determinism in a concurrent system. Now it is important to understand that uncertainty is desireable; uncertainty can be used by runtime systems to significantly increase performance and is often the basis of giving a user the illusion that tasks are running in parallel. Optimal performance in concurrent applications is often obtained by having as much non-determinism as correctness allows.
     13Therefore, a minimal concurrency system can be achieved by creating coroutines, which instead of context switching among each other, always ask an oracle where to context switch next. While coroutines can execute on the caller's stack-frame, stackfull coroutines allow full generality and are sufficient as the basis for concurrency. The aforementioned oracle is a scheduler and the whole system now follows a cooperative threading-model \cit. The oracle/scheduler can either be a stackless or stackfull entity and correspondingly require one or two context switches to run a different coroutine. In any case, a subset of concurrency related challenges start to appear. For the complete set of concurrency challenges to occur, the only feature missing is preemption.
     14
     15A scheduler introduces order of execution uncertainty, while preemption introduces uncertainty about where context-switches occur. Mutual-exclusion and synchronisation are ways of limiting non-determinism in a concurrent system. Now it is important to understand that uncertainty is desireable; uncertainty can be used by runtime systems to significantly increase performance and is often the basis of giving a user the illusion that tasks are running in parallel. Optimal performance in concurrent applications is often obtained by having as much non-determinism as correctness allows\cit.
    1616
    1717\section{\protect\CFA 's Thread Building Blocks}
     
    307307\subsection{Alternative: Lamda Objects}
    308308
    309 For coroutines as for threads, many implementations are based on routine pointers or function objects\cite{Butenhof97, ANSI14:C++, MS:VisualC++, BoostCoroutines15}. For example, Boost implements coroutines in terms of four functor object types:
     309For coroutines as for threads, many implementations are based on routine pointers or function objects\cit. For example, Boost implements coroutines in terms of four functor object types:
    310310\begin{cfacode}
    311311asymmetric_coroutine<>::pull_type
  • doc/proposals/concurrency/text/concurrency.tex

    r9e1eabc r65d6de4  
    88Approaches based on shared memory are more closely related to non-concurrent paradigms since they often rely on basic constructs like routine calls and shared objects. At the lowest level, concurrent paradigms are implemented as atomic operations and locks. Many such mechanisms have been proposed, including semaphores~\cite{Dijkstra68b} and path expressions~\cite{Campbell74}. However, for productivity reasons it is desireable to have a higher-level construct be the core concurrency paradigm~\cite{HPP:Study}.
    99
    10 An approach that is worth mentioning because it is gaining in popularity is transactionnal memory~\cite{Dice10}[Check citation]. While this approach is even pursued by system languages like \CC\cite{Cpp-Transactions}, the performance and feature set is currently too restrictive to be the main concurrency paradigm for systems language, which is why it was rejected as the core paradigm for concurrency in \CFA.
     10An approach that is worth mentioning because it is gaining in popularity is transactionnal memory~\cite{Dice10}[Check citation]. While this approach is even pursued by system languages like \CC\cit, the performance and feature set is currently too restrictive to be the main concurrency paradigm for systems language, which is why it was rejected as the core paradigm for concurrency in \CFA.
    1111
    1212One of the most natural, elegant, and efficient mechanisms for synchronization and communication, especially for shared-memory systems, is the \emph{monitor}. Monitors were first proposed by Brinch Hansen~\cite{Hansen73} and later described and extended by C.A.R.~Hoare~\cite{Hoare74}. Many programming languages---e.g., Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Modula~\cite{Modula-2}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, NeWS~\cite{NeWS}, Emerald~\cite{Emerald}, \uC~\cite{Buhr92a} and Java~\cite{Java}---provide monitors as explicit language constructs. In addition, operating-system kernels and device drivers have a monitor-like structure, although they often use lower-level primitives such as semaphores or locks to simulate monitors. For these reasons, this project proposes monitors as the core concurrency-construct.
     
    139139The \gls{multi-acq} monitor lock allows a monitor lock to be acquired by both \code{bar} or \code{baz} and acquired again in \code{foo}. In the calls to \code{bar} and \code{baz} the monitors are acquired in opposite order.
    140140
    141 However, such use leads to the lock acquiring order problem. In the example above, the user uses implicit ordering in the case of function \code{foo} but explicit ordering in the case of \code{bar} and \code{baz}. This subtle mistake means that calling these routines concurrently may lead to deadlock and is therefore undefined behavior. As shown\cite{Lister77}, solving this problem requires:
     141However, such use leads to the lock acquiring order problem. In the example above, the user uses implicit ordering in the case of function \code{foo} but explicit ordering in the case of \code{bar} and \code{baz}. This subtle mistake means that calling these routines concurrently may lead to deadlock and is therefore undefined behavior. As shown\cit, solving this problem requires:
    142142\begin{enumerate}
    143143        \item Dynamically tracking of the monitor-call order.
    144144        \item Implement rollback semantics.
    145145\end{enumerate}
    146 While the first requirement is already a significant constraint on the system, implementing a general rollback semantics in a C-like language is still prohibitively complex \cite{Dice10}. In \CFA, users simply need to be carefull when acquiring multiple monitors at the same time or only use \gls{bulk-acq} of all the monitors. While \CFA provides only a partial solution, many system provide no solution and the \CFA partial solution handles many useful cases.
     146While the first requirement is already a significant constraint on the system, implementing a general rollback semantics in a C-like language is prohibitively complex \cit. In \CFA, users simply need to be carefull when acquiring multiple monitors at the same time or only use \gls{bulk-acq} of all the monitors. While \CFA provides only a partial solution, many system provide no solution and the \CFA partial solution handles many useful cases.
    147147
    148148For example, \gls{multi-acq} and \gls{bulk-acq} can be used together in interesting ways:
     
    157157}
    158158\end{cfacode}
    159 This example shows a trivial solution to the bank-account transfer-problem\cite{BankTransfer}. Without \gls{multi-acq} and \gls{bulk-acq}, the solution to this problem is much more involved and requires carefull engineering.
     159This example shows a trivial solution to the bank-account transfer-problem\cit. Without \gls{multi-acq} and \gls{bulk-acq}, the solution to this problem is much more involved and requires carefull engineering.
    160160
    161161\subsection{\code{mutex} statement} \label{mutex-stmt}
    162162
    163 The call semantics discussed aboved have one software engineering issue, only a named routine can acquire the mutual-exclusion of a set of monitor. \CFA offers the \code{mutex} statement to workaround the need for unnecessary names, avoiding a major software engineering problem\cite{2FTwoHardThings}. Listing \ref{lst:mutex-stmt} shows an example of the \code{mutex} statement, which introduces a new scope in which the mutual-exclusion of a set of monitor is acquired. Beyond naming, the \code{mutex} statement has no semantic difference from a routine call with \code{mutex} parameters.
     163The call semantics discussed aboved have one software engineering issue, only a named routine can acquire the mutual-exclusion of a set of monitor. \CFA offers the \code{mutex} statement to workaround the need for unnecessary names, avoiding a major software engineering problem\cit. Listing \ref{lst:mutex-stmt} shows an example of the \code{mutex} statement, which introduces a new scope in which the mutual-exclusion of a set of monitor is acquired. Beyond naming, the \code{mutex} statement has no semantic difference from a routine call with \code{mutex} parameters.
    164164
    165165\begin{figure}
     
    232232% ======================================================================
    233233% ======================================================================
    234 In addition to mutual exclusion, the monitors at the core of \CFA's concurrency can also be used to achieve synchronisation. With monitors, this capability is generally achieved with internal or external scheduling as in \cite{Hoare74}. Since internal scheduling within a single monitor is mostly a solved problem, this thesis concentrates on extending internal scheduling to multiple monitors. Indeed, like the \gls{bulk-acq} semantics, internal scheduling extends to multiple monitors in a way that is natural to the user but requires additional complexity on the implementation side.
     234In addition to mutual exclusion, the monitors at the core of \CFA's concurrency can also be used to achieve synchronisation. With monitors, this capability is generally achieved with internal or external scheduling as in\cit. Since internal scheduling within a single monitor is mostly a solved problem, this thesis concentrates on extending internal scheduling to multiple monitors. Indeed, like the \gls{bulk-acq} semantics, internal scheduling extends to multiple monitors in a way that is natural to the user but requires additional complexity on the implementation side.
    235235
    236236First, here is a simple example of such a technique:
     
    305305This version uses \gls{bulk-acq} (denoted using the {\sf\&} symbol), but the presence of multiple monitors does not add a particularly new meaning. Synchronization happens between the two threads in exactly the same way and order. The only difference is that mutual exclusion covers more monitors. On the implementation side, handling multiple monitors does add a degree of complexity as the next few examples demonstrate.
    306306
    307 While deadlock issues can occur when nesting monitors, these issues are only a symptom of the fact that locks, and by extension monitors, are not perfectly composable. For monitors, a well known deadlock problem is the Nested Monitor Problem \cite{Lister77}, which occurs when a \code{wait} is made by a thread that holds more than one monitor. For example, the following pseudo-code runs into the nested-monitor problem :
     307While deadlock issues can occur when nesting monitors, these issues are only a symptom of the fact that locks, and by extension monitors, are not perfectly composable. For monitors, a well known deadlock problem is the Nested Monitor Problem\cit, which occurs when a \code{wait} is made by a thread that holds more than one monitor. For example, the following pseudo-code runs into the nested-monitor problem :
    308308\begin{multicols}{2}
    309309\begin{pseudo}
     
    771771For the first two conditions, it is easy to implement a check that can evaluate the condition in a few instruction. However, a fast check for \pscode{monitor accepts me} is much harder to implement depending on the constraints put on the monitors. Indeed, monitors are often expressed as an entry queue and some acceptor queue as in the following figure:
    772772
    773 \begin{figure}[H]
    774773\begin{center}
    775774{\resizebox{0.4\textwidth}{!}{\input{monitor}}}
    776775\end{center}
    777 \label{fig:monitor}
    778 \end{figure}
    779776
    780777There are other alternatives to these pictures, but in the case of this picture, implementing a fast accept check is relatively easy. Restricted to a fixed number of mutex members, N, the accept check reduces to updating a bitmask when the acceptor queue changes, a check that executes in a single instruction even with a fairly large number (e.g., 128) of mutex members. This technique cannot be used in \CFA because it relies on the fact that the monitor type enumerates (declares) all the acceptable routines. For OO languages this does not compromise much since monitors already have an exhaustive list of member routines. However, for \CFA this is not the case; routines can be added to a type anywhere after its declaration. It is important to note that the bitmask approach does not actually require an exhaustive list of routines, but it requires a dense unique ordering of routines with an upper-bound and that ordering must be consistent across translation units.
  • doc/proposals/concurrency/text/future.tex

    r9e1eabc r65d6de4  
    66
    77\section{Flexible Scheduling} \label{futur:sched}
    8 An important part of concurrency is scheduling. Different scheduling algorithm can affact peformance (both in terms of average and variation). However, no single scheduler is optimal for all workloads and therefore there is value in being able to change the scheduler for given programs. One solution is to offer various tweaking options to users, allowing the scheduler to be adjusted the to requirements of the workload. However, in order to be truly flexible, it would be interesting to allow users to add arbitrary data and arbirary scheduling algorithms to the scheduler. For example, a web server could attach Type-of-Service information to threads and have a ``ToS aware'' scheduling algorithm tailored to this specific web server. This path of flexible schedulers will be explored for \CFA.
     8
    99
    1010\section{Non-Blocking IO} \label{futur:nbio}
    1111While most of the parallelism tools
    12 However, many modern workloads are not bound on computation but on IO operations, an common case being webservers and XaaS (anything as a service). These type of workloads often require significant engineering around amortising costs of blocking IO operations. While improving throughtput of these operations is outside what \CFA can do as a language, it can help users to make better use of the CPU time otherwise spent waiting on IO operations. The current trend is to use asynchronous programming using tools like callbacks and/or futurs and promises\cite. However, while these are valid solutions, they lead to code that is harder to read and maintain because it is much less linear
     12However, many modern workloads are not bound on computation but on IO operations, an common case being webservers and XaaS (anything as a service). These type of workloads often require significant engineering around amortising costs of blocking IO operations. While improving throughtput of these operations is outside what \CFA can do as a language, it can help users to make better use of the CPU time otherwise spent waiting on IO operations. The current trend is to use asynchronous programming using tools like callbacks and/or futurs and promises\cit. However, while these are valid solutions, they lead to code that is harder to read and maintain because it is much less linear
     13
     14
    1315
    1416\section{Other concurrency tools} \label{futur:tools}
    15 While monitors offer a flexible and powerful concurent core for \CFA, other concurrency tools are also necessary for a complete multi-paradigm concurrency package. Example of such tools can include simple locks and condition variables, futures and promises\cite{promises}, and executors. These additional features are useful when monitors offer a level of abstraction which is indaquate for certain tasks.
     17
    1618
    1719\section{Implicit threading} \label{futur:implcit}
    18 Simpler applications can benefit greatly from having implicit parallelism. That is, parallelism that does not rely on the user to write concurrency. This type of parallelism can be achieved both at the language level and at the library level. The cannonical example of implcit parallelism is parallel for loops, which are the simplest example of a divide and conquer algorithm\cite{uC++book}. Listing \ref{lst:parfor} shows three different code examples that accomplish pointwise sums of large arrays. Note that none of these example explicitly declare any concurrency or parallelism objects.
     20Simpler applications can benefit greatly from having implicit parallelism. That is, parallelism that does not rely on the user to write concurrency. This type of parallelism can be achieved both at the language level and at the library level. The cannonical example of implcit parallelism is parallel for loops, which are the simplest example of a divide and conquer algorithm\cit. Listing \ref{lst:parfor} shows three different code examples that accomplish pointwise sums of large arrays. Note that none of these example explicitly declare any concurrency or parallelism objects.
    1921
    2022\begin{figure}
     
    101103\end{figure}
    102104
    103 Implicit parallelism is a general solution and therefore has its limitations. However, it is a quick and simple approach to parallelism which may very well be sufficient for smaller applications and reduces the amount of boiler-plate that is needed to start benefiting from parallelism in modern CPUs.
     105Implicit parallelism is a general solution and therefore is
     106
     107\section{Multiple Paradigms} \label{futur:paradigms}
    104108
    105109
     110\section{Transactions} \label{futur:transaction}
     111Concurrency and parallelism is still a very active field that strongly benefits from hardware advances. As such certain features that aren't necessarily mature enough in their current state could become relevant in the lifetime of \CFA.
  • doc/proposals/concurrency/text/internals.tex

    r9e1eabc r65d6de4  
    11
    22\chapter{Behind the scene}
    3 There are several challenges specific to \CFA when implementing concurrency. These challenges are a direct result of \gls{bulk-acq} and loose object-definitions. These two constraints are the root cause of most design decisions in the implementation. Furthermore, to avoid contention from dynamically allocating memory in a concurrent environment, the internal-scheduling design is (almost) entirely free of mallocs. This is to avoid the chicken and egg problem \cite{Chicken} of having a memory allocator that relies on the threading system and a threading system that relies on the runtime. This extra goal, means that memory management is a constant concern in the design of the system.
    4 
    5 The main memory concern for concurrency is queues. All blocking operations are made by parking threads onto queues. The queue design needs to be intrusive\cite{IntrusiveData} to avoid the need for memory allocation, which entails that all the nodes need specific fields to keep track of all needed information. Since many concurrency operations can use an unbound amount of memory (depending on \gls{bulk-acq}), statically defining information in the intrusive fields of threads is insufficient. The only variable sized container that does not require memory allocation is the callstack, which is heavily used in the implementation of internal scheduling. Particularly variable length arrays, which are used extensively.
     3There are several challenges specific to \CFA when implementing concurrency. These challenges are direct results of \gls{bulk-acq} and loose object definitions. These two constraints are to root cause of most design decisions in the implementation. Furthermore, to avoid the head-aches of dynamically allocating memory in a concurrent environment, the internal-scheduling design is (almost) entirely free of mallocs and other dynamic memory allocation scheme. This is to avoid the chicken and egg problem \cite{Chicken} of having a memory allocator that relies on the threading system and a threading system that relies on the runtime. This extra goal, means that memory management is a constant concern in the design of the system.
     4
     5The main memory concern for concurrency is queues. All blocking operations are made by parking threads onto queues. These queues need to be intrinsic\cit to avoid the need memory allocation. This entails that all the fields needed to keep track of all needed information. Since many conconcurrency operations can use an unbound amount of memory (depending on \gls{bulk-acq}) statically defining information in the intrusive fields of threads is insufficient. The only variable sized container that does not require memory allocation is the callstack, which is heavily used in the implementation of internal scheduling. Particularly the GCC extension variable length arrays which is used extensively.
    66
    77Since stack allocation is based around scope, the first step of the implementation is to identify the scopes that are available to store the information, and which of these can have a variable length. The threads and the condition both allow a fixed amount of memory to be stored, while mutex-routines and the actual blocking call allow for an unbound amount (though the later is preferable in terms of performance).
    88
    9 Note that since the major contributions of this thesis are extending monitor semantics to \gls{bulk-acq} and loose object definitions, any challenges that are not resulting of these characteristiques of \CFA are considered as solved problems and therefore not discussed further.
     9Note that since the major contributions of this thesis are extending monitor semantics to \gls{bulk-acq} and loose object definitions, any challenges that are not resulting of these characteristiques of \CFA are consired as problems which have already been solved and therefore will not be discussed further.
    1010
    1111% ======================================================================
     
    1515% ======================================================================
    1616
    17 The first step towards the monitor implementation is simple mutex-routines using monitors. In the single monitor case, this is done using the entry/exit procedure highlighted in listing \ref{lst:entry1}. This entry/exit procedure does not actually have to be extended to support multiple monitors, indeed it is sufficient to enter/leave monitors one-by-one as long as the order is correct to prevent deadlocks\cite{Havender68}. In \CFA, ordering of monitor relies on memory ordering, this is sufficient because all objects are guaranteed to have distinct non-overlaping memory layouts and mutual-exclusion for a monitor is only defined for its lifetime, meaning that destroying a monitor while it is acquired is undefined behavior. When a mutex call is made, the concerned monitors are agregated into a variable-length pointer array and sorted based on pointer values. This array presists for the entire duration of the mutual-exclusion and its ordering reused extensively.
     17The first step towards the monitor implementation is simple mutex-routines using monitors. In the single monitor case, this is done using the entry/exit procedure highlighted in listing \ref{lst:entry1}. This entry/exit procedure doesn't actually have to be extended to support multiple monitors, indeed it is sufficient to enter/leave monitors one-by-one as long as the order is correct to prevent deadlocks\cit. In \CFA, ordering of monitor relies on memory ordering, this is sufficient because all objects are guaranteed to have distinct non-overlaping memory layouts and mutual-exclusion for a monitor is only defined for its lifetime, meaning that destroying a monitor while it is acquired is undefined behavior. When a mutex call is made, the concerned monitors are agregated into an variable-length pointer array and sorted based on pointer values. This array is concerved during the entire duration of the mutual-exclusion and it's ordering reused extensively.
    1818\begin{figure}
    1919\begin{multicols}{2}
     
    9696\end{tabular}
    9797\end{center}
    98 \caption{Call-site vs entry-point locking for mutex calls}
     98\caption{Callsite vs entry-point locking for mutex calls}
    9999\label{fig:locking-site}
    100100\end{figure}
    101101
    102 Note the \code{mutex} keyword relies on the type system, which means that in cases where a generic monitor routine is desired, writing the mutex routine is possible with the proper trait, for example:
     102Note the \code{mutex} keyword relies on the type system, which means that in cases where a generic monitor routine is actually desired, writing a mutex routine is possible with the proper trait, for example:
    103103\begin{cfacode}
    104 //Incorrect: T may not be monitor
     104//Incorrect: T is not a monitor
    105105forall(dtype T)
    106106void foo(T * mutex t);
     
    111111\end{cfacode}
    112112
    113 Both entry-point and callsite locking are feasible implementations. The current \CFA implementations uses entry-point locking because it requires less work when using \gls{raii}, effectively transferring the burden of implementation to object construction/destruction. The same could be said of callsite locking, the difference being that the later does not necessarily have an existing scope that matches exactly the scope of the mutual exclusion, i.e.: the function body. Furthermore, entry-point locking requires less code generation since any useful routine is called at least as often as it is define, there can be only one entry-point but many callsites.
     113Both entry-point and callsite locking are valid implementations. The current \CFA implementations uses entry-point locking because it seems to require less work if done using \gls{raii}, effectively transferring the burden of implementation to object construction/destruction. The same could be said of callsite locking, the difference being that the later does not necessarily have an existing scope that matches exactly the scope of the mutual exclusion, i.e.: the function body.
    114114
    115115% ======================================================================
     
    119119% ======================================================================
    120120
    121 Figure \ref{fig:system1} shows a high-level picture if the \CFA runtime system in regards to concurrency. Each component of the picture is explained in details in the fllowing sections.
     121Figure \ref{fig:system1} shows a high-level picture if the \CFA runtime system in regards to concurrency.
    122122
    123123\begin{figure}
     
    130130
    131131\subsection{Context Switching}
    132 As mentionned in section \ref{coroutine}, coroutines are a stepping stone for implementing threading. This is because they share the same mechanism for context-switching between different stacks. To improve performance and simplicity, context-switching is implemented using the following assumption: all context-switches happen inside a specific function call. This assumption means that the context-switch only has to copy the callee-saved registers onto the stack and then switch the stack registers with the ones of the target coroutine/thread. Note that the instruction pointer can be left untouched since the context-switch is always inside the same function. Threads however do not context-switch between each other directly. They context-switch to the scheduler. This method is called a 2-step context-switch and has the advantage of having a clear distinction between user code and the kernel where scheduling and other system operation happen. Obiously, this has the cost of doubling the context-switch cost because threads must context-switch to an intermediate stack. However, the performance of the 2-step context-switch is still superior to a \code{pthread_yield}(see section \ref{results}). additionally, for users in need for optimal performance, it is important to note that having a 2-step context-switch as the default does not prevent \CFA from offering a 1-step context-switch to use manually (or as part of monitors). This option is not currently present in \CFA but the changes required to add it are strictly additive.
     132As mentionned in section \ref{coroutine}, coroutines are a stepping stone for implementing threading. This is because they share the same mechanism for context-switching between different stacks. To improve performance and simplicity, context-switching is implemented using the following assumption: all context-switches happen inside a specific function call. This assumptions means that the basic recipe for context-switch is only to copy all callee-saved registers unto the stack and then switch the stack registers with the ones of the target coroutine/thread. Note that instruction pointer can be left untouched since the context-switch always inside the same function. In the case of coroutines, that is the entire story. Threads however do not simply context-switch between each other directly. The context-switch to processors which is where the scheduling happens. This method is called a 2-step context-switch and has the advantage of having a clear distinction between user code and the "kernel" where scheduling and other system operation happen. Obiously, this has the cost of doubling the context-switch cost from because threads must context-switch to an intermediate stack. However, the performance of the 2-step context-switch is still superior to a \code{pthread_yield}(see section \ref{results}). additionally, for users in need for optimal performance, it is important to note that having a 2-step context-switch as the default does not prevent \CFA from offering a 1-step context-switch to use manually (or as part of monitors). This option is not currently present in \CFA but the changes required to add it are strictly additive.
    133133
    134134\subsection{Processors}
    135 Parallelism in \CFA is built around using processors to specify how much parallelism is desired. \CFA processors are object wrappers around kernel threads, specifically pthreads in the current implementation of \CFA. Indeed, any parallelism must go through operating-system librairies. However, \glspl{uthread} are still the main source of concurrency, processors are simply the underlying source of parallelism. Indeed, processor \glspl{kthread} simply fetch a \glspl{uthread} from the scheduler and run, they are effectively executers for user-threads. The main benefit of this approach is that it offers a well defined boundary between kernel code and user code, for example, kernel thread quiescing, scheduling and interrupt handling. Processors internally use coroutines to take advantage of the existing context-switching semantics.
     135Parallelism in \CFA are built around using processors to specify how much parallelism is desired. \CFA processors are object wrappers around kernel threads, specifically pthreads in the current implementation of \CFA. Indeed, any parallelism must go through operatiing system librairies. However, \gls{cfathread} are still the main source of concurrency, processors are simply the underlying source of parallelism. Indeed, processor kernel threads simply fetch a user-level thread from the scheduler and run, they are effectively executers for user-threads. The main benefit of this approach is that it offers a well defined boundary between kernel code and user-code, for example kernel thread quiescing, scheduling and interrupt handling. Processors internally use coroutines to take advantage of the existing context-switching semantics.
    136136
    137137\subsection{Stack management}
    138138One of the challenges of this system is to reduce the footprint as much as possible. Specifically, all pthreads created also have a stack created with them, which should be used as much as possible. Normally, coroutines also create there own stack to run on, however, in the case of the coroutines used for processors, these coroutines run directly on the kernel thread stack, effectively stealing the processor stack. The exception to this rule is the Main Processor, i.e. the initial kernel thread that is given to any program. In order to respect user expectations, the stack of the initial kernel thread, the main stack of the program, is used by the main user thread rather than the main processor.
    139139
    140 \subsection{Preemption} \label{preemption}
    141 Finally, an important aspect for any complete threading system is preemption. As mentionned in chapter \ref{basics}, preemption introduces an extra degree of uncertainty, which enables users to have multiple threads interleave transparently, rather than having to cooperate among threads for proper scheduling and CPU distribution. Indeed, preemption is desireable because it adds a degree of isolation among threads. In a fully cooperative system, any thread that runs into a long loop can starve other threads, while in a preemptive system starvation can still occur but it does not rely on every thread having to yield or block on a regular basis, which reduces significantly a programmer burden. Obviously, preemption is not optimal for every workload, however any preemptive system can become a cooperative system by making the time-slices extremely large. Which is why \CFA uses a preemptive threading system.
    142 
    143 Preemption in \CFA is based on kernel timers, which are used to run a discrete-event simulation. Every processor keeps track of the current time and registers an expiration time with the preemption system. When the preemption system receives a change in preemption, it sorts these expiration times in a list and sets a kernel timer for the closest one, effectively stepping between preemption events on each signals sent by the timer. These timers use the linux signal {\tt SIGALRM}, which is delivered to the process rather than the kernel-thread. This results in an implementation problem,because when delivering signals to a process, the kernel documentation states that the signal can be delivered to any kernel thread for which the signal is not blocked i.e. :
     140\subsection{Preemption}
     141Finally, an important aspect for any complete threading system is preemption. As mentionned in chapter \ref{basics}, preemption introduces an extra degree of unceretainty, which enables users to have multiple threads interleave transparrently between eachother, rather than having to cooperate between thread for proper scheduling and CPU distribution. Indeed, preemption is desireable because it adds a degree of isolation between tasks. In a fully cooperative system, any thread that runs into a long loop can starve other threads, while in a preemptive system starvation can still occur but it does not rely on every thread having to yield or block on a regular basis, which reduces significantly programmer burden. Obviously, preemption is not optimal for every workload, however any preemptive system can become a cooperative system by making the time-slices extremely large. Which is why \CFA uses a preemptive threading system.
     142
     143Preemption in \CFA is based on kernel timers which are used to run a discreet event simulation. Every processor keeps track of the current time and registers an expiration time with the preemption system. When the preemption system receives a change in preemption it sorts these expiration times in a list and sets a kernel timer for the closest one, effectiveling stepping between preemption events on each signals sent by the timer. These timers use the linux signal {\tt SIGALRM}, which is delivered to the process. This is important because when delivering signals to a process, the kernel documentation states that the signal can be delivered to any kernel thread for which the signal isn't block i.e. :
    144144\begin{quote}
    145145A process-directed signal may be delivered to any one of the threads that does not currently have the signal blocked. If more than one of the threads has the signal unblocked, then the kernel chooses an arbitrary thread to which to deliver the signal.
     
    148148For the sake of simplicity and in order to prevent the case of having two threads receiving alarms simultaneously, \CFA programs block the {\tt SIGALRM} signal on every thread except one. Now because of how involontary context-switches are handled, the kernel thread handling {\tt SIGALRM} cannot also be a processor thread.
    149149
    150 Involuntary context-switching is done by sending signal {\tt SIGUSER1} to the corresponding processor and having the thread yield from inside the signal handler. Effectively context-switching away from the signal-handler back to the kernel and the signal-handler frame is eventually unwound when the thread is scheduled again. This approach means that a signal-handler can start on one kernel thread and terminate on a second kernel thread (but the same user thread). It is important to note that signal-handlers save and restore signal masks because user-thread migration can cause signal mask to migrate from one kernel thread to another. This behaviour is only a problem if all kernel threads among which a user thread can migrate differ in terms of signal masks\footnote{Sadly, official POSIX documentation is silent on what distiguishes ``async-signal-safe'' functions from other functions}. However, since the kernel thread hanlding preemption requires a different signal mask, executing user threads on the kernel alarm thread can cause deadlocks. For this reason, the alarm thread is on a tight loop around a system call to \code{sigwaitinfo}, requiring very little CPU time for preemption. One final detail about the alarm thread is how to wake it when additional communication is required (e.g., on thread termination). This unblocking is also done using {\tt SIGALRM}, but sent throught the \code{pthread_sigqueue}. Indeed, \code{sigwait} can differentiate signals sent from \code{pthread_sigqueue} from signals sent from alarms or the kernel.
    151 
    152 \subsection{Scheduler}
    153 Finally, an aspect that was not mentionned yet is the scheduling algorithm. Currently, the \CFA scheduler uses a single ready queue for all processors, which is the simplest approach to scheduling. Further discussion on scheduling is present in section \label{futur:sched}.
     150Involontary context-switching is done by sending {\tt SIGUSER1} to the corresponding processor and having the thread yield from inside the signal handler. Effectively context-switch away from the signal-handler back to the kernel and the signal-handler frame will be unwound when the thread is scheduled again. This means that a signal-handler can start on one kernel thread and terminate on a second kernel thread (but the same user thread). It is important to note that signal-handlers save and restore signal masks because user-thread migration can cause signal mask to migrate from one kernel thread to another. This is only a problem if all kernel threads among which a user thread can migrate differ in terms of signal masks. However, since the kernel thread hanlding preemption requires a different signal mask, executing user threads on the kernel alarm thread can cause deadlocks. For this reason, the alarm thread is on a tight loop around a system call to \code{sigwait} or more specifically \code{sigwaitinfo}, requiring very little CPU time for preemption. One final detail about the alarm thread is how to wake it when additional communication is required (e.g. on thread termination). This is also done using {\tt SIGALRM}, but sent throught the \code{pthread_sigqueue}. Indeed, \code{sigwait} can differentiate signals sent from \code{pthread_sigqueue} from signals sent from alarms or the kernel.
     151
     152\subsection{Scheduler} \footnote{ I'm not sure what to write here, is this section even needed. }
     153Finally, an aspect that was not mentionned yet is the scheduling algorithm. Currently, the \CFA scheduler uses a single ready queue for all processors. Will this is not the highest performance algorithm, it has the significant advantage of being robust to heterogenous workloads. This is a very simple scheduling approach but is sufficient to for the context of this thesis.
     154
     155What to do here?
     156
     157However, when
     158As will be mentionned \ref{futur:sched} it needs to be updated when clusters will be
     159
     160clusters
     161
     162
     163
     164Among the most pressing updates to the \CFA
     165uses single queue
     166in future should move to multiple queues with workstealing
     167general purpouse means robust > fast
     168worksharing can higher standard deviation in performance
     169
    154170
    155171% ======================================================================
     
    158174% ======================================================================
    159175% ======================================================================
    160 The following figure is the traditional illustration of a monitor (repeated from page~\pageref{fig:monitor} for convenience) :
    161 
    162 \begin{figure}[H]
     176To ease the understanding of monitors, like many other concepts, they are generelly represented graphically. While non-scheduled monitors are simple enough for a graphical representation to be useful, internal scheduling is complex enough to justify a visual representation. The following figure is the traditionnal illustration of a monitor :
     177
    163178\begin{center}
    164179{\resizebox{0.4\textwidth}{!}{\input{monitor}}}
    165180\end{center}
    166 \caption{Traditional illustration of a monitor}
    167 \label{fig:monitor}
    168 \end{figure}
    169 
    170 This picture has several components, the two most important being the entry-queue and the AS-stack. The entry-queue is an (almost) FIFO list where threads waiting to enter are parked, while the acceptor-signalor (AS) stack is a FILO list used for threads that have been signalled or otherwise marked as running next.
    171 
    172 For \CFA, this picture does not have support for blocking multiple monitors on a single condition. To support \gls{bulk-acq} two changes to this picture are required. First, it is non longer helpful to attach the condition to a single monitor. Secondly, the thread waiting on the conditions has to be seperated multiple monitors, which yields :
    173 
    174 \begin{figure}[H]
     181
     182This picture has several components, the two most important being the entry-queue and the AS-stack. The entry-queue is a (almost) FIFO list where threads waiting to enter are parked, while the AS-stack is a FILO list used for threads that have been signaled or otherwise marked as running next. For \CFA, the previous picture does not have support for blocking multiple monitors on a single condition. To support \gls{bulk-acq} two changes to this picture are required. First, it doesn't make sense to tie the condition to a single monitor since blocking two monitors as one would require arbitrarily picking a monitor to hold the condition. Secondly, the object waiting on the conditions and AS-stack cannot simply contain the waiting thread since a single thread can potentially wait on multiple monitors. As mentionned in section \ref{intsched}, the handling in multiple monitors is done by partially passing, which entails that each concerned monitor needs to have a node object. However, for waiting on the condition, since all threads need to wait together, a single object needs to be queued in the condition. Moving out the condition and updating the node types yields :
     183
    175184\begin{center}
    176185{\resizebox{0.8\textwidth}{!}{\input{int_monitor}}}
    177186\end{center}
    178 \caption{Illustration of \CFA monitor}
    179 \label{fig:monitor_cfa}
    180 \end{figure}
    181 
    182 This picture and the proper entry and leave algorithms is the fundamental implementation of internal scheduling (see listing \ref{lst:entry2}). Note that when threads are moved from the condition to the AS-stack, it splits the thread into to pieces. The thread is woken up when all the pieces have moved from the AS-stacks to the active thread seat. In this picture, the threads are split into halves but this is only because there are two monitors in this picture. For a specific signaling operation every monitor needs a piece of thread on its AS-stack.
     187
     188This picture and the proper entry and leave algorithms is the fundamental implementation of internal scheduling (see listing \ref{lst:entry2}).
    183189
    184190\begin{figure}[b]
     
    213219\end{figure}
    214220
    215 Some important things to notice about the exit routine. The solution discussed in \ref{intsched} can be seen in the exit routine of listing \ref{lst:entry2}. Basically, the solution boils down to having a seperate data structure for the condition queue and the AS-stack, and unconditionally transferring ownership of the monitors but only unblocking the thread when the last monitor has transferred ownership. This solution is deadlock safe as well as preventing any potential barging. The data structure used for the AS-stack are reused extensively for external scheduling, but in the case of internal scheduling, the data is allocated using variable-length arrays on the callstack of the \code{wait} and \code{signal_block} routines.
    216 
    217 \begin{figure}[H]
    218 \begin{center}
    219 {\resizebox{0.8\textwidth}{!}{\input{monitor_structs.pstex_t}}}
    220 \end{center}
    221 \caption{Data structures involved in internal/external scheduling}
    222 \label{fig:structs}
    223 \end{figure}
    224 
    225 Figure \ref{fig:structs} shows a high level representation of these data-structures. The main idea behind them is that, while figure \ref{fig:monitor_cfa} is a nice illustration in theory, in practice breaking a threads into multiple pieces to put unto intrusive stacks does not make sense. The \code{condition node} is the data structure that is queued into a condition variable and, when signaled, the condition queue is popped and each \code{condition criterion} are moved to the AS-stack. Once all the criterion have be popped from their respective AS-stacks, the thread is woken-up, which is what is shown in listing \ref{lst:entry2}.
     221Some important things to notice about the exit routine. The solution discussed in \ref{intsched} can be seen in the exit routine of listing \ref{lst:entry2}. Basically, the solution boils down to having a seperate data structure for the condition queue and the AS-stack, and unconditionally transferring ownership of the monitors but only unblocking the thread when the last monitor has transferred ownership. This solution is deadlock safe as well as preventing any potential barging.
     222
     223The data structure used for the AS-stack are reused extensively for external scheduling, but in the case of internal scheduling, the data is allocated using variable-length arrays on the callstack of the \code{wait} and \code{signal_block} routines.
    226224
    227225% ======================================================================
     
    230228% ======================================================================
    231229% ======================================================================
    232 Similarly to internal scheduling, external scheduling for multiple monitors relies on the idea that waiting-thread queues are no longer specific to a single monitor, as mentionned in section \ref{extsched}. For internal scheduling, these queues are part of condition variables which are still unique for a given scheduling operation (e.g., no single statment uses multiple conditions). However, in the case of external scheduling, there is no equivalent object which is associated with \code{waitfor} statements. This absence means the queues holding the waiting threads must be stored inside at least one of the monitors that is acquired. The monitors being the only objects that have sufficient lifetime and are available on both sides of the \code{waitfor} statment. This requires an algorithm to choose which monitor holds the relevant queue. It is also important that said algorithm be independent of the order in which users list parameters. The proposed algorithm is to fall back on monitor lock ordering and specify that the monitor that is acquired first is the one with the relevant wainting queue. This assumes that the lock acquiring order is static for the lifetime of all concerned objects but that is a reasonable constraint.
    233 
    234 This algorithm choice has two consequences :
    235 \begin{itemize}
    236         \item The queue of the highest priority monitor is no longer a true FIFO queue because threads can be moved to the front of the queue. These queues need to contain a set of monitors for each of the waiting threads. Therefore, another thread whose set contains the same highest priority monitor but different lower priority monitors may arrive first but enter the critical section after a thread with the correct pairing.
    237         \item The queue of the lowest priority monitor is both required and potentially unused. Indeed, since it is not known at compile time which monitor will be the lowest priority monitor, every monitor needs to have the correct queues even though it is possible that some queues will go unused for the entire duration of the program, for example if a monitor is only used in a specific pair.
    238 \end{itemize}
     230Similarly to internal scheduling, external scheduling for multiple monitors relies on the idea that entry-queues are no longer specific to a single monitor, as mentionned in section \ref{extsched}. This means that some kind of entry-queues must be used that is aware of both monitors and which holds threads that are currently waiting to enter the critical section. This challenge is solved for internal scheduling by having the entry-queues in conditions no longer be tied to a monitor, effectively allowing conditions to be moved outside of monitors. However, in the case of external scheduling, acceptable routines must be aware of the entry queues, which means they must be stored inside at least one of the monitors that will be acquired. This in turn adds the requirement that a systematic algorithm of disambiguating which monitor holds the relevant queue regardless of user ordering. The proposed algorithm is to fall back on monitor lock ordering and specify that the monitor that is acquired first is the one with the relevant entry queue. This assumes that the lock acquiring order is static for the lifetime of all concerned objects but that is a reasonable constraint.
     231
     232This algorithm choice has two consequences, the entry queue of the highest priority monitor is no longer a true FIFO queue and the queue of the lowest priority monitor is both required and probably unused. The queue can no longer be a FIFO queue because instead of simply containing the waiting threads in order of arrival, they also contain a set of monitors. Therefore, another thread whos set contains the same highest priority monitor but different lower priority monitors may arrive first but enter the critical section after a thread with the correct pairing. Secondly, since it is not known at compile time which monitor will be the lowest priority monitor, every monitor needs to have the correct queues even though it is probable that some queues will go unused for the entire duration of the program, for example if a monitor is only used in a pair.
    239233
    240234Therefore, the following modifications need to be made to support external scheduling :
    241235\begin{itemize}
    242         \item The threads waiting on the entry-queue need to keep track of which routine is trying to enter, and using which set of monitors. The \code{mutex} routine already has all the required information on its stack so the thread only needs to keep a pointer to that information.
     236        \item The threads waiting on the entry-queue need to keep track of which routine is trying to enter, and using which set of monitors. The \code{mutex} routine already has all the required information on it's stack so the thread only needs to keep a pointer to that information.
    243237        \item The monitors need to keep a mask of acceptable routines. This mask contains for each acceptable routine, a routine pointer and an array of monitors to go with it. It also needs storage to keep track of which routine was accepted. Since this information is not specific to any monitor, the monitors actually contain a pointer to an integer on the stack of the waiting thread. Note that the complete mask can be pushed to any owned monitors, regardless of \code{when} statements, the \code{waitfor} statement is used in a context where the thread already has full ownership of (at least) every concerned monitor and therefore monitors will refuse all calls no matter what.
    244238        \item The entry/exit routine need to be updated as shown in listing \ref{lst:entry3}.
    245239\end{itemize}
    246240
    247 \subsection{External scheduling - destructors}
    248241Finally, to support the ordering inversion of destructors, the code generation needs to be modified to use a special entry routine. This routine is needed because of the storage requirements of the call order inversion. Indeed, when waiting for the destructors, storage is need for the waiting context and the lifetime of said storage needs to outlive the waiting operation it is needed for. For regular \code{waitfor} statements, the callstack of the routine itself matches this requirement but it is no longer the case when waiting for the destructor since it is pushed on to the AS-stack for later. The waitfor semantics can then be adjusted correspondingly, as seen in listing \ref{lst:entry-dtor}
    249242
     
    257250        continue
    258251elif matches waitfor mask
    259         push criterions to AS-stack
     252        push waiter to AS-stack
    260253        continue
    261254else
     
    272265                if all monitors ready
    273266                        wake-up thread
    274                 endif
    275         endif
    276267
    277268        if entry queue not empty
    278269                wake-up thread
    279         endif
    280270\end{pseudo}
    281271\end{multicols}
     
    305295Waitfor
    306296\begin{pseudo}
     297lock all monitors
    307298if matching thread is already there
    308299        if found destructor
     
    312303                push self to AS-stack
    313304                baton pass
    314         endif
    315305        return
    316 endif
     306
    317307if non-blocking
    318308        Unlock all monitors
    319309        Return
    320 endif
    321310
    322311push self to AS-stack
  • doc/proposals/concurrency/text/parallelism.tex

    r9e1eabc r65d6de4  
    1515Examples of languages that support \glspl{uthread} are Erlang~\cite{Erlang} and \uC~\cite{uC++book}.
    1616
    17 \subsection{Fibers : user-level threads without preemption} \label{fibers}
     17\subsection{Fibers : user-level threads without preemption}
    1818A popular varient of \glspl{uthread} is what is often refered to as \glspl{fiber}. However, \glspl{fiber} do not present meaningful semantical differences with \glspl{uthread}. The significant difference between \glspl{uthread} and \glspl{fiber} is the lack of \gls{preemption} in the later one. Advocates of \glspl{fiber} list their high performance and ease of implementation as majors strenghts of \glspl{fiber} but the performance difference between \glspl{uthread} and \glspl{fiber} is controversial, and the ease of implementation, while true, is a weak argument in the context of language design. Therefore this proposal largely ignores fibers.
    1919
     
    3333
    3434\subsection{Future Work: Machine setup}\label{machine}
    35 While this was not done in the context of this thesis, another important aspect of clusters is affinity. While many common desktop and laptop PCs have homogeneous CPUs, other devices often have more heteregenous setups. For example, system using \acrshort{numa} configurations may benefit from users being able to tie clusters and\/or kernel threads to certains CPU cores. OS support for CPU affinity is now common \cite{affinityLinux, affinityWindows, affinityFreebsd, affinityNetbsd, affinityMacosx} which means it is both possible and desirable for \CFA to offer an abstraction mechanism for portable CPU affinity.
     35While this was not done in the context of this thesis, another important aspect of clusters is affinity. While many common desktop and laptop PCs have homogeneous CPUs, other devices often have more heteregenous setups. For example, system using \acrshort{numa} configurations may benefit from users being able to tie clusters and/or kernel threads to certains CPU cores. OS support for CPU affinity is now common \cit, which means it is both possible and desirable for \CFA to offer an abstraction mechanism for portable CPU affinity.
    3636
    37 % \subsection{Paradigms}\label{cfaparadigms}
    38 % Given these building blocks, it is possible to reproduce all three of the popular paradigms. Indeed, \glspl{uthread} is the default paradigm in \CFA. However, disabling \gls{preemption} on the \gls{cfacluster} means \glspl{cfathread} effectively become \glspl{fiber}. Since several \glspl{cfacluster} with different scheduling policy can coexist in the same application, this allows \glspl{fiber} and \glspl{uthread} to coexist in the runtime of an application. Finally, it is possible to build executors for thread pools from \glspl{uthread} or \glspl{fiber}.
     37\subsection{Paradigms}\label{cfaparadigms}
     38Given these building blocks, it is possible to reproduce all three of the popular paradigms. Indeed, \glspl{uthread} is the default paradigm in \CFA. However, disabling \gls{preemption} on the \gls{cfacluster} means \glspl{cfathread} effectively become \glspl{fiber}. Since several \glspl{cfacluster} with different scheduling policy can coexist in the same application, this allows \glspl{fiber} and \glspl{uthread} to coexist in the runtime of an application. Finally, it is possible to build executors for thread pools from \glspl{uthread} or \glspl{fiber}.
  • doc/proposals/concurrency/text/results.tex

    r9e1eabc r65d6de4  
    11% ======================================================================
    22% ======================================================================
    3 \chapter{Performance results} \label{results}
     3\chapter{Performance results}
    44% ======================================================================
    55% ======================================================================
     6
    67\section{Machine setup}
    7 Table \ref{tab:machine} shows the characteristiques of the machine used to run the benchmarks. All tests where made on this machine.
    8 \begin{figure}[H]
     8
     9\begin{figure}
    910\begin{center}
    1011\begin{tabular}{| l | r | l | r |}
     
    3637
    3738\section{Micro benchmarks}
    38 All benchmarks are run using the same harness to produce the results, seen as the \code{BENCH()} macro in the following examples. This macro uses the following logic to benchmark the code :
    39 \begin{pseudo}
    40 #define BENCH(run, result)
    41         gettime();
    42         run;
    43         gettime();
    44         result = (after - before) / N;
    45 \end{pseudo}
    46 The method used to get time is \code{clock_gettime(CLOCK_THREAD_CPUTIME_ID);}. Each benchmark is using many interations of a simple call to measure the cost of the call. The specific number of interation dependes on the specific benchmark.
    47 
    48 \subsection{Context-switching}
    49 The first interesting benchmark is to measure how long context-switches take. The simplest approach to do this is to yield on a thread, which executes a 2-step context switch. In order to make the comparison fair, coroutines also execute a 2-step context-switch, which is a resume/suspend cycle instead of a yield. Listing \ref{lst:ctx-switch} shows the code for coroutines and threads. All omitted tests are functionally identical to one of these tests. The results can be shown in table \ref{tab:ctx-switch}.
    50 \begin{figure}
    51 \begin{multicols}{2}
    52 \CFA Coroutines
    53 \begin{cfacode}
    54 coroutine GreatSuspender {};
    55 void main(GreatSuspender& this) {
    56         while(true) { suspend(); }
    57 }
    58 int main() {
    59         GreatSuspender s;
    60         resume(s);
    61         BENCH(
    62                 for(size_t i=0; i<n; i++) {
    63                         resume(s);
    64                 },
    65                 result
    66         )
    67         printf("%llu\n", result);
    68 }
    69 \end{cfacode}
    70 \columnbreak
    71 \CFA Threads
    72 \begin{cfacode}
    73 
    74 
    75 
    76 
    77 int main() {
    78 
    79 
    80         BENCH(
    81                 for(size_t i=0; i<n; i++) {
    82                         yield();
    83                 },
    84                 result
    85         )
    86         printf("%llu\n", result);
    87 }
    88 \end{cfacode}
    89 \end{multicols}
    90 \caption{\CFA benchmark code used to measure context-switches for coroutines and threads.}
    91 \label{lst:ctx-switch}
    92 \end{figure}
    9339
    9440\begin{figure}
     
    10854\caption{Context Switch comparaison. All numbers are in nanoseconds(\si{\nano\second})}
    10955\label{tab:ctx-switch}
    110 \end{figure}
    111 
    112 \subsection{Mutual-exclusion}
    113 The next interesting benchmark is to measure the overhead to enter/leave a critical-section. For monitors, the simplest appraoch is to measure how long it takes enter and leave a monitor routine. Listing \ref{lst:mutex} shows the code for \CFA. To put the results in context, the cost of entering a non-inline function and the cost of acquiring and releasing a pthread mutex lock are also mesured. The results can be shown in table \ref{tab:mutex}.
    114 
    115 \begin{figure}
    116 \begin{cfacode}
    117 monitor M {};
    118 void __attribute__((noinline)) call( M & mutex m /*, m2, m3, m4*/ ) {}
    119 
    120 int main() {
    121         M m/*, m2, m3, m4*/;
    122         BENCH(
    123                 for(size_t i=0; i<n; i++) {
    124                         call(m/*, m2, m3, m4*/);
    125                 },
    126                 result
    127         )
    128         printf("%llu\n", result);
    129 }
    130 \end{cfacode}
    131 \caption{\CFA benchmark code used to measure mutex routines.}
    132 \label{lst:mutex}
    13356\end{figure}
    13457
     
    15275\end{figure}
    15376
    154 \subsection{Internal scheduling}
    155 The Internal scheduling benchmark measures the cost of waiting on and signaling a condition variable. Listing \ref{lst:int-sched} shows the code for \CFA. The results can be shown in table \ref{tab:int-sched}. As with all other benchmarks, all omitted tests are functionally identical to one of these tests.
    156 
    157 \begin{figure}
    158 \begin{cfacode}
    159 volatile int go = 0;
    160 condition c;
    161 monitor M {};
    162 M m1;
    163 
    164 void __attribute__((noinline)) do_call( M & mutex a1 ) { signal(c); }
    165 
    166 thread T {};
    167 void ^?{}( T & mutex this ) {}
    168 void main( T & this ) {
    169         while(go == 0) { yield(); }
    170         while(go == 1) { do_call(m1); }
    171 }
    172 int  __attribute__((noinline)) do_wait( M & mutex a1 ) {
    173         go = 1;
    174         BENCH(
    175                 for(size_t i=0; i<n; i++) {
    176                         wait(c);
    177                 },
    178                 result
    179         )
    180         printf("%llu\n", result);
    181         go = 0;
    182         return 0;
    183 }
    184 int main() {
    185         T t;
    186         return do_wait(m1);
    187 }
    188 \end{cfacode}
    189 \caption{Benchmark code for internal scheduling}
    190 \label{lst:int-sched}
    191 \end{figure}
    192 
    19377\begin{figure}
    19478\begin{center}
     
    20690\caption{Internal scheduling comparaison. All numbers are in nanoseconds(\si{\nano\second})}
    20791\label{tab:int-sched}
    208 \end{figure}
    209 
    210 \subsection{External scheduling}
    211 The Internal scheduling benchmark measures the cost of the \code{waitfor} statement (\code{_Accept} in \uC). Listing \ref{lst:ext-sched} shows the code for \CFA. The results can be shown in table \ref{tab:ext-sched}. As with all other benchmarks, all omitted tests are functionally identical to one of these tests.
    212 
    213 \begin{figure}
    214 \begin{cfacode}
    215 volatile int go = 0;
    216 monitor M {};
    217 M m1;
    218 thread T {};
    219 
    220 void __attribute__((noinline)) do_call( M & mutex a1 ) {}
    221 
    222 void ^?{}( T & mutex this ) {}
    223 void main( T & this ) {
    224         while(go == 0) { yield(); }
    225         while(go == 1) { do_call(m1); }
    226 }
    227 int  __attribute__((noinline)) do_wait( M & mutex a1 ) {
    228         go = 1;
    229         BENCH(
    230                 for(size_t i=0; i<n; i++) {
    231                         waitfor(call, a1);
    232                 },
    233                 result
    234         )
    235         printf("%llu\n", result);
    236         go = 0;
    237         return 0;
    238 }
    239 int main() {
    240         T t;
    241         return do_wait(m1);
    242 }
    243 \end{cfacode}
    244 \caption{Benchmark code for external scheduling}
    245 \label{lst:ext-sched}
    24692\end{figure}
    24793
     
    263109\end{figure}
    264110
    265 \subsection{Object creation}
    266 Finaly, the last benchmark measured is the cost of creation for concurrent objects. Listing \ref{lst:creation} shows the code for pthreads and \CFA threads. The results can be shown in table \ref{tab:creation}. As with all other benchmarks, all omitted tests are functionally identical to one of these tests. The only note here is that the callstacks of \CFA coroutines are lazily created, therefore without priming the coroutine, the creation cost is very low.
    267 
    268 \begin{figure}
    269 \begin{multicols}{2}
    270 pthread
    271 \begin{cfacode}
    272 int main() {
    273         BENCH(
    274                 for(size_t i=0; i<n; i++) {
    275                         pthread_t thread;
    276                         if(pthread_create(
    277                                 &thread,
    278                                 NULL,
    279                                 foo,
    280                                 NULL
    281                         ) < 0) {
    282                                 perror( "failure" );
    283                                 return 1;
    284                         }
    285 
    286                         if(pthread_join(
    287                                 thread,
    288                                 NULL
    289                         ) < 0) {
    290                                 perror( "failure" );
    291                                 return 1;
    292                         }
    293                 },
    294                 result
    295         )
    296         printf("%llu\n", result);
    297 }
    298 \end{cfacode}
    299 \columnbreak
    300 \CFA Threads
    301 \begin{cfacode}
    302 int main() {
    303         BENCH(
    304                 for(size_t i=0; i<n; i++) {
    305                         MyThread m;
    306                 },
    307                 result
    308         )
    309 
    310         printf("%llu\n", result);
    311 }
    312 \end{cfacode}
    313 \end{multicols}
    314 \caption{Bechmark code for pthreads and \CFA to measure object creation}
    315 \label{lst:creation}
    316 \end{figure}
    317 
    318111\begin{figure}
    319112\begin{center}
     
    322115\multicolumn{1}{c |}{} & \multicolumn{1}{c |}{ Median } &\multicolumn{1}{c |}{ Average } & \multicolumn{1}{c |}{ Standard Deviation} \\
    323116\hline
    324 Pthreads                        & 26974.5       & 26977 & 124.12 \\
    325 \CFA Coroutines Lazy    & 5             & 5             & 0      \\
    326 \CFA Coroutines Eager   & 335.0 & 357.67        & 34.2   \\
    327 \CFA Threads            & 1122.5        & 1109.86       & 36.54  \\
    328 \uC Coroutines          & 106           & 107.04        & 1.61   \\
    329 \uC Threads                     & 525.5 & 533.04        & 11.14  \\
     117Pthreads                & 26974.5       & 26977 & 124.12 \\
     118\CFA Coroutines & 5             & 5             & 0      \\
     119\CFA Threads    & 1122.5        & 1109.86       & 36.54  \\
     120\uC Coroutines  & 106           & 107.04        & 1.61   \\
     121\uC Threads             & 525.5 & 533.04        & 11.14  \\
    330122\hline
    331123\end{tabular}
  • doc/proposals/concurrency/text/together.tex

    r9e1eabc r65d6de4  
    77
    88\section{Threads as monitors}
    9 As it was subtely alluded in section \ref{threads}, \code{threads} in \CFA are in fact monitors, which means that all monitor features are available when using threads. For example, here is a very simple two thread pipeline that could be used for a simulator of a game engine :
     9As it was subtely alluded in section \ref{threads}, \code{threads} in \CFA are in fact monitors. This means that all the monitors features are available when using threads. For example, here is a very simple two thread pipeline that could be used for a simulator of a game engine :
    1010\begin{cfacode}
    1111// Visualization declaration
     
    7272        }
    7373}
    74 
    75 // Call destructor for simulator once simulator finishes
    76 // Call destructor for renderer to signify shutdown
    7774\end{cfacode}
    7875
    7976\section{Fibers \& Threads}
    80 As mentionned in section \ref{preemption}, \CFA uses preemptive threads by default but can use fibers on demand. Currently, using fibers is done by adding the following line of code to the program~:
    81 \begin{cfacode}
    82 unsigned int default_preemption() {
    83         return 0;
    84 }
    85 \end{cfacode}
    86 This function is called by the kernel to fetch the default preemption rate, where 0 signifies an infinite time-slice i.e. no preemption. However, once clusters are fully implemented, it will be possible to create fibers and uthreads in on the same system :
    87 \begin{figure}
    88 \begin{cfacode}
    89 //Cluster forward declaration
    90 struct cluster;
    91 
    92 //Processor forward declaration
    93 struct processor;
    94 
    95 //Construct clusters with a preemption rate
    96 void ?{}(cluster& this, unsigned int rate);
    97 //Construct processor and add it to cluster
    98 void ?{}(processor& this, cluster& cluster);
    99 //Construct thread and schedule it on cluster
    100 void ?{}(thread& this, cluster& cluster);
    101 
    102 //Declare two clusters
    103 cluster thread_cluster = { 10`ms };                     //Preempt every 10 ms
    104 cluster fibers_cluster = { 0 };                         //Never preempt
    105 
    106 //Construct 4 processors
    107 processor processors[4] = {
    108         //2 for the thread cluster
    109         thread_cluster;
    110         thread_cluster;
    111         //2 for the fibers cluster
    112         fibers_cluster;
    113         fibers_cluster;
    114 };
    115 
    116 //Declares thread
    117 thread UThread {};
    118 void ?{}(UThread& this) {
    119         //Construct underlying thread to automatically
    120         //be scheduled on the thread cluster
    121         (this){ thread_cluster }
    122 }
    123 
    124 void main(UThread & this);
    125 
    126 //Declares fibers
    127 thread Fiber {};
    128 void ?{}(Fiber& this) {
    129         //Construct underlying thread to automatically
    130         //be scheduled on the fiber cluster
    131         (this.__thread){ fibers_cluster }
    132 }
    133 
    134 void main(Fiber & this);
    135 \end{cfacode}
    136 \end{figure}
  • doc/proposals/concurrency/version

    r9e1eabc r65d6de4  
    1 0.11.129
     10.11.47
  • src/Common/Debug.h

    r9e1eabc r65d6de4  
    2424#include "SynTree/Declaration.h"
    2525
    26 #define DEBUG
     26/// debug codegen a translation unit
     27static inline void debugCodeGen( const std::list< Declaration * > & translationUnit, const std::string & label ) {
     28        std::list< Declaration * > decls;
    2729
    28 namespace Debug {
    29         /// debug codegen a translation unit
    30         static inline void codeGen( __attribute__((unused)) const std::list< Declaration * > & translationUnit, __attribute__((unused)) const std::string & label ) {
    31         #ifdef DEBUG
    32                 std::list< Declaration * > decls;
     30        filter( translationUnit.begin(), translationUnit.end(), back_inserter( decls ), []( Declaration * decl ) {
     31                return ! LinkageSpec::isBuiltin( decl->get_linkage() );
     32        });
    3333
    34                 filter( translationUnit.begin(), translationUnit.end(), back_inserter( decls ), []( Declaration * decl ) {
    35                         return ! LinkageSpec::isBuiltin( decl->get_linkage() );
    36                 });
    37 
    38                 std::cerr << "======" << label << "======" << std::endl;
    39                 CodeGen::generate( decls, std::cerr, false, true );
    40         #endif
    41         } // dump
    42 
    43         static inline void treeDump( __attribute__((unused)) const std::list< Declaration * > & translationUnit, __attribute__((unused)) const std::string & label ) {
    44         #ifdef DEBUG
    45                 std::list< Declaration * > decls;
    46 
    47                 filter( translationUnit.begin(), translationUnit.end(), back_inserter( decls ), []( Declaration * decl ) {
    48                         return ! LinkageSpec::isBuiltin( decl->get_linkage() );
    49                 });
    50 
    51                 std::cerr << "======" << label << "======" << std::endl;
    52                 printAll( decls, std::cerr );
    53         #endif
    54         } // dump
    55 }
     34        std::cerr << "======" << label << "======" << std::endl;
     35        CodeGen::generate( decls, std::cerr, false, true );
     36} // dump
    5637
    5738// Local Variables: //
  • src/ResolvExpr/AlternativeFinder.cc

    r9e1eabc r65d6de4  
    581581                std::vector<unsigned> tupleEls;  /// Number of elements in current tuple element(s)
    582582
    583                 ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have,
     583                ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have, 
    584584                                const OpenVarSet& openVars)
    585585                        : actuals(), env(env), need(need), have(have), openVars(openVars), nextArg(0),
    586586                          expls(), nextExpl(0), tupleEls() {}
    587 
     587               
    588588                /// Starts a new tuple expression
    589589                void beginTuple() {
     
    620620
    621621        /// Instantiates an argument to match a formal, returns false if no results left
    622         bool instantiateArgument( Type* formalType, Initializer* initializer,
    623                         const std::vector< AlternativeFinder >& args,
    624                         std::vector<ArgPack>& results, std::vector<ArgPack>& nextResults,
     622        bool instantiateArgument( Type* formalType, Initializer* initializer, 
     623                        const std::vector< AlternativeFinder >& args, 
     624                        std::vector<ArgPack>& results, std::vector<ArgPack>& nextResults, 
    625625                        const SymTab::Indexer& indexer ) {
    626626                if ( TupleType* tupleType = dynamic_cast<TupleType*>( formalType ) ) {
     
    629629                        for ( Type* type : *tupleType ) {
    630630                                // xxx - dropping initializer changes behaviour from previous, but seems correct
    631                                 if ( ! instantiateArgument( type, nullptr, args, results, nextResults, indexer ) )
     631                                if ( ! instantiateArgument( type, nullptr, args, results, nextResults, indexer ) ) 
    632632                                        return false;
    633633                        }
     
    658658                                                Type* argType = result.actuals.back().expr->get_result();
    659659                                                if ( result.tupleEls.back() == 1 && Tuples::isTtype( argType ) ) {
    660                                                         // the case where a ttype value is passed directly is special, e.g. for
     660                                                        // the case where a ttype value is passed directly is special, e.g. for 
    661661                                                        // argument forwarding purposes
    662662                                                        // xxx - what if passing multiple arguments, last of which is ttype?
    663                                                         // xxx - what would happen if unify was changed so that unifying tuple
     663                                                        // xxx - what would happen if unify was changed so that unifying tuple 
    664664                                                        // types flattened both before unifying lists? then pass in TupleType
    665665                                                        // (ttype) below.
     
    671671                                                }
    672672                                                // check unification for ttype before adding to final
    673                                                 if ( unify( ttype, argType, result.env, result.need, result.have,
     673                                                if ( unify( ttype, argType, result.env, result.need, result.have, 
    674674                                                                result.openVars, indexer ) ) {
    675675                                                        finalResults.push_back( std::move(result) );
     
    684684                                                aResult.env.addActual( actual.env, aResult.openVars );
    685685                                                Cost cost = actual.cost;
    686 
     686               
    687687                                                // explode argument
    688688                                                std::vector<Alternative> exploded;
    689689                                                Tuples::explode( actual, indexer, back_inserter( exploded ) );
    690 
     690                                               
    691691                                                // add exploded argument to tuple
    692692                                                for ( Alternative& aActual : exploded ) {
     
    706706                        return ! results.empty();
    707707                }
    708 
     708               
    709709                // iterate each current subresult
    710710                for ( unsigned iResult = 0; iResult < results.size(); ++iResult ) {
     
    724724                                        std::cerr << std::endl;
    725725                                )
    726 
    727                                 if ( unify( formalType, actualType, result.env, result.need, result.have,
     726                               
     727                                if ( unify( formalType, actualType, result.env, result.need, result.have, 
    728728                                                result.openVars, indexer ) ) {
    729729                                        ++result.nextExpl;
     
    736736                                if ( ConstantExpr* cnstExpr = getDefaultValue( initializer ) ) {
    737737                                        if ( Constant* cnst = dynamic_cast<Constant*>( cnstExpr->get_constant() ) ) {
    738                                                 if ( unify( formalType, cnst->get_type(), result.env, result.need,
     738                                                if ( unify( formalType, cnst->get_type(), result.env, result.need, 
    739739                                                                result.have, result.openVars, indexer ) ) {
    740740                                                        nextResults.push_back( std::move(result.withArg( cnstExpr )) );
     
    791791                results.swap( nextResults );
    792792                nextResults.clear();
    793 
     793               
    794794                return ! results.empty();
    795         }
     795        }       
    796796
    797797        template<typename OutputIterator>
    798         void AlternativeFinder::makeFunctionAlternatives( const Alternative &func,
    799                         FunctionType *funcType, const std::vector< AlternativeFinder > &args,
     798        void AlternativeFinder::makeFunctionAlternatives( const Alternative &func, 
     799                        FunctionType *funcType, const std::vector< AlternativeFinder > &args, 
    800800                        OutputIterator out ) {
    801801                OpenVarSet funcOpenVars;
     
    803803                TypeEnvironment funcEnv( func.env );
    804804                makeUnifiableVars( funcType, funcOpenVars, funcNeed );
    805                 // add all type variables as open variables now so that those not used in the parameter
     805                // add all type variables as open variables now so that those not used in the parameter 
    806806                // list are still considered open.
    807807                funcEnv.add( funcType->get_forall() );
    808 
     808               
    809809                if ( targetType && ! targetType->isVoid() && ! funcType->get_returnVals().empty() ) {
    810810                        // attempt to narrow based on expected target type
    811811                        Type * returnType = funcType->get_returnVals().front()->get_type();
    812                         if ( ! unify( returnType, targetType, funcEnv, funcNeed, funcHave, funcOpenVars,
     812                        if ( ! unify( returnType, targetType, funcEnv, funcNeed, funcHave, funcOpenVars, 
    813813                                        indexer ) ) {
    814814                                // unification failed, don't pursue this function alternative
     
    822822                for ( DeclarationWithType* formal : funcType->get_parameters() ) {
    823823                        ObjectDecl* obj = strict_dynamic_cast< ObjectDecl* >( formal );
    824                         if ( ! instantiateArgument(
     824                        if ( ! instantiateArgument( 
    825825                                        obj->get_type(), obj->get_init(), args, results, nextResults, indexer ) )
    826826                                return;
     
    904904
    905905                std::vector< AlternativeFinder > argAlternatives;
    906                 findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(),
     906                findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(), 
    907907                        back_inserter( argAlternatives ) );
    908908
     
    934934                                                Alternative newFunc( *func );
    935935                                                referenceToRvalueConversion( newFunc.expr );
    936                                                 makeFunctionAlternatives( newFunc, function, argAlternatives,
     936                                                makeFunctionAlternatives( newFunc, function, argAlternatives, 
    937937                                                        std::back_inserter( candidates ) );
    938938                                        }
     
    943943                                                        Alternative newFunc( *func );
    944944                                                        referenceToRvalueConversion( newFunc.expr );
    945                                                         makeFunctionAlternatives( newFunc, function, argAlternatives,
     945                                                        makeFunctionAlternatives( newFunc, function, argAlternatives, 
    946946                                                                std::back_inserter( candidates ) );
    947947                                                } // if
    948948                                        } // if
    949                                 }
     949                                }                       
    950950                        } catch ( SemanticError &e ) {
    951951                                errors.append( e );
     
    962962                                try {
    963963                                        // check if type is a pointer to function
    964                                         if ( PointerType* pointer = dynamic_cast<PointerType*>(
     964                                        if ( PointerType* pointer = dynamic_cast<PointerType*>( 
    965965                                                        funcOp->expr->get_result()->stripReferences() ) ) {
    966                                                 if ( FunctionType* function =
     966                                                if ( FunctionType* function = 
    967967                                                                dynamic_cast<FunctionType*>( pointer->get_base() ) ) {
    968968                                                        Alternative newFunc( *funcOp );
    969969                                                        referenceToRvalueConversion( newFunc.expr );
    970                                                         makeFunctionAlternatives( newFunc, function, argAlternatives,
     970                                                        makeFunctionAlternatives( newFunc, function, argAlternatives, 
    971971                                                                std::back_inserter( candidates ) );
    972972                                                }
     
    10071007                candidates.splice( candidates.end(), alternatives );
    10081008
    1009                 // use a new list so that alternatives are not examined by addAnonConversions twice.
    1010                 AltList winners;
    1011                 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( winners ) );
     1009                findMinCost( candidates.begin(), candidates.end(), std::back_inserter( alternatives ) );
    10121010
    10131011                // function may return struct or union value, in which case we need to add alternatives for implicit
    10141012                // conversions to each of the anonymous members, must happen after findMinCost since anon conversions
    10151013                // are never the cheapest expression
    1016                 for ( const Alternative & alt : winners ) {
     1014                for ( const Alternative & alt : alternatives ) {
    10171015                        addAnonConversions( alt );
    10181016                }
    1019                 alternatives.splice( alternatives.begin(), winners );
    10201017
    10211018                if ( alternatives.empty() && targetType && ! targetType->isVoid() ) {
  • src/ResolvExpr/RenameVars.cc

    r9e1eabc r65d6de4  
    2929        RenameVars global_renamer;
    3030
    31         RenameVars::RenameVars() : level( 0 ), resetCount( 0 ) {
     31        RenameVars::RenameVars() : level( 0 ) {
    3232                mapStack.push_front( std::map< std::string, std::string >() );
    3333        }
     
    3535        void RenameVars::reset() {
    3636                level = 0;
    37                 resetCount++;
    3837        }
    3938
     
    131130                        for ( Type::ForallList::iterator i = type->get_forall().begin(); i != type->get_forall().end(); ++i ) {
    132131                                std::ostringstream output;
    133                                 output << "_" << resetCount << "_" << level << "_" << (*i)->get_name();
     132                                output << "_" << level << "_" << (*i)->get_name();
    134133                                std::string newname( output.str() );
    135134                                mapStack.front()[ (*i)->get_name() ] = newname;
  • src/ResolvExpr/RenameVars.h

    r9e1eabc r65d6de4  
    4848                void typeBefore( Type *type );
    4949                void typeAfter( Type *type );
    50                 int level, resetCount;
     50                int level;
    5151                std::list< std::map< std::string, std::string > > mapStack;
    5252        };
  • src/benchmark/Makefile.am

    r9e1eabc r65d6de4  
    2323STATS    = ${TOOLSDIR}stat.py
    2424repeats  = 30
    25 TIME_FORMAT = "%E"
    26 PRINT_FORMAT = %20s: #Comments needed for spacing
    2725
    2826.NOTPARALLEL:
     
    3230all : ctxswitch$(EXEEXT) mutex$(EXEEXT) signal$(EXEEXT) waitfor$(EXEEXT) creation$(EXEEXT)
    3331
    34 %.run : %$(EXEEXT) ${REPEAT}
    35         @rm -f .result.log
    36         @echo "------------------------------------------------------"
    37         @echo $<
    38         @${REPEAT} ${repeats} ./a.out | tee -a .result.log
    39         @${STATS} .result.log
    40         @echo "------------------------------------------------------"
    41         @rm -f a.out .result.log
     32bench$(EXEEXT) :
     33        @for ccflags in "-debug" "-nodebug"; do \
     34                echo ${CC} ${AM_CFLAGS} ${CFLAGS} ${ccflags} @CFA_FLAGS@ -lrt bench.c;\
     35                ${CC} ${AM_CFLAGS} ${CFLAGS} $${ccflags} -lrt bench.c;\
     36                ./a.out ; \
     37        done ; \
     38        rm -f ./a.out ;
    4239
    43 %.runquiet :
    44         @+make $(basename $@)
     40csv-data$(EXEEXT):
     41        @${CC} ${AM_CFLAGS} ${CFLAGS} ${ccflags} @CFA_FLAGS@ -nodebug -lrt -quiet -DN=50000000 csv-data.c
    4542        @./a.out
    46         @rm -f a.out
    47 
    48 %.make :
    49         @printf "${PRINT_FORMAT}" $(basename $(subst compile-,,$@))
    50         @+/usr/bin/time -f ${TIME_FORMAT} make $(basename $@) 2>&1
    51 
    52 ${REPEAT} :
    53         @+make -C ${TOOLSDIR} repeat
    54 
    55 ## =========================================================================================================
    56 
    57 jenkins$(EXEEXT):
    58         @echo "{"
    59         @echo -e '\t"githash": "'${githash}'",'
    60         @echo -e '\t"arch": "'   ${arch}   '",'
    61         @echo -e '\t"compile": {'
    62         @+make compile TIME_FORMAT='%e,' PRINT_FORMAT='\t\t\"%s\" :'
    63         @echo -e '\t\t"dummy" : {}'
    64         @echo -e '\t},'
    65         @echo -e '\t"ctxswitch": {'
    66         @echo -en '\t\t"coroutine":'
    67         @+make ctxswitch-cfa_coroutine.runquiet
    68         @echo -en '\t\t,"thread":'
    69         @+make ctxswitch-cfa_thread.runquiet
    70         @echo -e '\t},'
    71         @echo -e '\t"mutex": ['
    72         @echo -en '\t\t'
    73         @+make mutex-cfa1.runquiet
    74         @echo -en '\t\t,'
    75         @+make mutex-cfa2.runquiet
    76         @echo -e '\t],'
    77         @echo -e '\t"scheduling": ['
    78         @echo -en '\t\t'
    79         @+make signal-cfa1.runquiet
    80         @echo -en '\t\t,'
    81         @+make signal-cfa2.runquiet
    82         @echo -en '\t\t,'
    83         @+make waitfor-cfa1.runquiet
    84         @echo -en '\t\t,'
    85         @+make waitfor-cfa2.runquiet
    86         @echo -e '\n\t],'
    87         @echo -e '\t"epoch": ' $(shell date +%s)
    88         @echo "}"
     43        @rm -f ./a.out
    8944
    9045## =========================================================================================================
     
    9752
    9853ctxswitch-cfa_coroutine$(EXEEXT):
    99         @${CC}        ctxswitch/cfa_cor.c   -DBENCH_N=50000000  -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     54        ${CC}        ctxswitch/cfa_cor.c   -DBENCH_N=50000000  -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    10055
    10156ctxswitch-cfa_thread$(EXEEXT):
    102         @${CC}        ctxswitch/cfa_thrd.c  -DBENCH_N=50000000  -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     57        ${CC}        ctxswitch/cfa_thrd.c  -DBENCH_N=50000000  -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    10358
    10459ctxswitch-upp_coroutine$(EXEEXT):
    105         @u++          ctxswitch/upp_cor.cc  -DBENCH_N=50000000  -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     60        u++          ctxswitch/upp_cor.cc  -DBENCH_N=50000000  -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    10661
    10762ctxswitch-upp_thread$(EXEEXT):
    108         @u++          ctxswitch/upp_thrd.cc -DBENCH_N=50000000  -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     63        u++          ctxswitch/upp_thrd.cc -DBENCH_N=50000000  -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    10964
    11065ctxswitch-pthread$(EXEEXT):
    111         @@BACKEND_CC@ ctxswitch/pthreads.c  -DBENCH_N=50000000  -I. -lrt -pthread                    ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     66        @BACKEND_CC@ ctxswitch/pthreads.c  -DBENCH_N=50000000  -I. -lrt -pthread                    ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    11267
    11368## =========================================================================================================
     
    12176
    12277mutex-function$(EXEEXT):
    123         @@BACKEND_CC@ mutex/function.c    -DBENCH_N=500000000   -I. -lrt -pthread                    ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     78        @BACKEND_CC@ mutex/function.c    -DBENCH_N=500000000   -I. -lrt -pthread                    ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    12479
    12580mutex-pthread_lock$(EXEEXT):
    126         @@BACKEND_CC@ mutex/pthreads.c    -DBENCH_N=50000000    -I. -lrt -pthread                    ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     81        @BACKEND_CC@ mutex/pthreads.c    -DBENCH_N=50000000    -I. -lrt -pthread                    ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    12782
    12883mutex-upp$(EXEEXT):
    129         @u++          mutex/upp.cc        -DBENCH_N=50000000    -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     84        u++          mutex/upp.cc        -DBENCH_N=50000000    -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    13085
    13186mutex-cfa1$(EXEEXT):
    132         @${CC}        mutex/cfa1.c        -DBENCH_N=5000000     -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     87        ${CC}        mutex/cfa1.c        -DBENCH_N=5000000     -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    13388
    13489mutex-cfa2$(EXEEXT):
    135         @${CC}        mutex/cfa2.c        -DBENCH_N=5000000     -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     90        ${CC}        mutex/cfa2.c        -DBENCH_N=5000000     -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    13691
    13792mutex-cfa4$(EXEEXT):
    138         @${CC}        mutex/cfa4.c        -DBENCH_N=5000000     -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     93        ${CC}        mutex/cfa4.c        -DBENCH_N=5000000     -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    13994
    14095## =========================================================================================================
     
    146101
    147102signal-upp$(EXEEXT):
    148         @u++          schedint/upp.cc     -DBENCH_N=5000000     -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     103        u++          schedint/upp.cc     -DBENCH_N=5000000     -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    149104
    150105signal-cfa1$(EXEEXT):
    151         @${CC}        schedint/cfa1.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     106        ${CC}        schedint/cfa1.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    152107
    153108signal-cfa2$(EXEEXT):
    154         @${CC}        schedint/cfa2.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     109        ${CC}        schedint/cfa2.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    155110
    156111signal-cfa4$(EXEEXT):
    157         @${CC}        schedint/cfa4.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     112        ${CC}        schedint/cfa4.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    158113
    159114## =========================================================================================================
     
    165120
    166121waitfor-upp$(EXEEXT):
    167         @u++          schedext/upp.cc     -DBENCH_N=5000000     -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     122        u++          schedext/upp.cc     -DBENCH_N=5000000     -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    168123
    169124waitfor-cfa1$(EXEEXT):
    170         @${CC}        schedext/cfa1.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     125        ${CC}        schedext/cfa1.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    171126
    172127waitfor-cfa2$(EXEEXT):
    173         @${CC}        schedext/cfa2.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     128        ${CC}        schedext/cfa2.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    174129
    175130waitfor-cfa4$(EXEEXT):
    176         @${CC}        schedext/cfa4.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     131        ${CC}        schedext/cfa4.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    177132
    178133## =========================================================================================================
     
    186141
    187142creation-cfa_coroutine$(EXEEXT):
    188         @${CC}        creation/cfa_cor.c   -DBENCH_N=10000000   -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     143        ${CC}        creation/cfa_cor.c   -DBENCH_N=10000000   -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    189144
    190145creation-cfa_coroutine_eager$(EXEEXT):
    191         @${CC}        creation/cfa_cor.c   -DBENCH_N=10000000   -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} -DEAGER
     146        ${CC}        creation/cfa_cor.c   -DBENCH_N=10000000   -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} -DEAGER
    192147
    193148creation-cfa_thread$(EXEEXT):
    194         @${CC}        creation/cfa_thrd.c  -DBENCH_N=10000000   -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     149        ${CC}        creation/cfa_thrd.c  -DBENCH_N=10000000   -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    195150
    196151creation-upp_coroutine$(EXEEXT):
    197         @u++          creation/upp_cor.cc  -DBENCH_N=50000000   -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     152        u++          creation/upp_cor.cc  -DBENCH_N=50000000   -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    198153
    199154creation-upp_thread$(EXEEXT):
    200         @u++          creation/upp_thrd.cc -DBENCH_N=50000000   -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     155        u++          creation/upp_thrd.cc -DBENCH_N=50000000   -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    201156
    202157creation-pthread$(EXEEXT):
    203         @@BACKEND_CC@ creation/pthreads.c  -DBENCH_N=250000     -I. -lrt -pthread                    ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     158        @BACKEND_CC@ creation/pthreads.c  -DBENCH_N=250000     -I. -lrt -pthread                    ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    204159
    205160## =========================================================================================================
    206161
    207 compile$(EXEEXT) :\
    208         compile-array.make      \
    209         compile-attributes.make \
    210         compile-empty.make      \
    211         compile-expression.make \
    212         compile-io.make         \
    213         compile-monitor.make    \
    214         compile-operators.make  \
    215         compile-typeof.make
     162%.run : %$(EXEEXT) ${REPEAT}
     163        @rm -f .result.log
     164        @echo "------------------------------------------------------"
     165        @echo $<
     166        @${REPEAT} ${repeats} ./a.out | tee -a .result.log
     167        @${STATS} .result.log
     168        @echo "------------------------------------------------------"
     169        @rm -f a.out .result.log
    216170
    217 
    218 compile-array$(EXEEXT):
    219         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/array.c                @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    220 
    221 compile-attributes$(EXEEXT):
    222         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/attributes.c   @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    223 
    224 compile-empty$(EXEEXT):
    225         @${CC} -nodebug -quiet -fsyntax-only -w compile/empty.c         @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    226 
    227 compile-expression$(EXEEXT):
    228         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/expression.c   @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    229 
    230 compile-io$(EXEEXT):
    231         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/io.c                   @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    232 
    233 compile-monitor$(EXEEXT):
    234         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/monitor.c              @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    235 
    236 compile-operators$(EXEEXT):
    237         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/operators.c    @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    238 
    239 compile-thread$(EXEEXT):
    240         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/thread.c               @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    241 
    242 compile-typeof$(EXEEXT):
    243         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/typeof.c               @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    244 
     171${REPEAT} :
     172        @+make -C ${TOOLSDIR} repeat
  • src/benchmark/Makefile.in

    r9e1eabc r65d6de4  
    124124  esac
    125125am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
    126 am__DIST_COMMON = $(srcdir)/Makefile.in compile
     126am__DIST_COMMON = $(srcdir)/Makefile.in
    127127DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
    128128ACLOCAL = @ACLOCAL@
     
    253253STATS = ${TOOLSDIR}stat.py
    254254repeats = 30
    255 TIME_FORMAT = "%E"
    256 PRINT_FORMAT = %20s: #Comments needed for spacing
    257255all: all-am
    258256
     
    448446all : ctxswitch$(EXEEXT) mutex$(EXEEXT) signal$(EXEEXT) waitfor$(EXEEXT) creation$(EXEEXT)
    449447
     448bench$(EXEEXT) :
     449        @for ccflags in "-debug" "-nodebug"; do \
     450                echo ${CC} ${AM_CFLAGS} ${CFLAGS} ${ccflags} @CFA_FLAGS@ -lrt bench.c;\
     451                ${CC} ${AM_CFLAGS} ${CFLAGS} $${ccflags} -lrt bench.c;\
     452                ./a.out ; \
     453        done ; \
     454        rm -f ./a.out ;
     455
     456csv-data$(EXEEXT):
     457        @${CC} ${AM_CFLAGS} ${CFLAGS} ${ccflags} @CFA_FLAGS@ -nodebug -lrt -quiet -DN=50000000 csv-data.c
     458        @./a.out
     459        @rm -f ./a.out
     460
     461ctxswitch$(EXEEXT): \
     462        ctxswitch-pthread.run           \
     463        ctxswitch-cfa_coroutine.run     \
     464        ctxswitch-cfa_thread.run        \
     465        ctxswitch-upp_coroutine.run     \
     466        ctxswitch-upp_thread.run
     467
     468ctxswitch-cfa_coroutine$(EXEEXT):
     469        ${CC}        ctxswitch/cfa_cor.c   -DBENCH_N=50000000  -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     470
     471ctxswitch-cfa_thread$(EXEEXT):
     472        ${CC}        ctxswitch/cfa_thrd.c  -DBENCH_N=50000000  -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     473
     474ctxswitch-upp_coroutine$(EXEEXT):
     475        u++          ctxswitch/upp_cor.cc  -DBENCH_N=50000000  -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     476
     477ctxswitch-upp_thread$(EXEEXT):
     478        u++          ctxswitch/upp_thrd.cc -DBENCH_N=50000000  -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     479
     480ctxswitch-pthread$(EXEEXT):
     481        @BACKEND_CC@ ctxswitch/pthreads.c  -DBENCH_N=50000000  -I. -lrt -pthread                    ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     482
     483mutex$(EXEEXT) :\
     484        mutex-function.run      \
     485        mutex-pthread_lock.run  \
     486        mutex-upp.run           \
     487        mutex-cfa1.run          \
     488        mutex-cfa2.run          \
     489        mutex-cfa4.run
     490
     491mutex-function$(EXEEXT):
     492        @BACKEND_CC@ mutex/function.c    -DBENCH_N=500000000   -I. -lrt -pthread                    ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     493
     494mutex-pthread_lock$(EXEEXT):
     495        @BACKEND_CC@ mutex/pthreads.c    -DBENCH_N=50000000    -I. -lrt -pthread                    ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     496
     497mutex-upp$(EXEEXT):
     498        u++          mutex/upp.cc        -DBENCH_N=50000000    -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     499
     500mutex-cfa1$(EXEEXT):
     501        ${CC}        mutex/cfa1.c        -DBENCH_N=5000000     -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     502
     503mutex-cfa2$(EXEEXT):
     504        ${CC}        mutex/cfa2.c        -DBENCH_N=5000000     -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     505
     506mutex-cfa4$(EXEEXT):
     507        ${CC}        mutex/cfa4.c        -DBENCH_N=5000000     -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     508
     509signal$(EXEEXT) :\
     510        signal-upp.run          \
     511        signal-cfa1.run         \
     512        signal-cfa2.run         \
     513        signal-cfa4.run
     514
     515signal-upp$(EXEEXT):
     516        u++          schedint/upp.cc     -DBENCH_N=5000000     -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     517
     518signal-cfa1$(EXEEXT):
     519        ${CC}        schedint/cfa1.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     520
     521signal-cfa2$(EXEEXT):
     522        ${CC}        schedint/cfa2.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     523
     524signal-cfa4$(EXEEXT):
     525        ${CC}        schedint/cfa4.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     526
     527waitfor$(EXEEXT) :\
     528        waitfor-upp.run         \
     529        waitfor-cfa1.run                \
     530        waitfor-cfa2.run                \
     531        waitfor-cfa4.run
     532
     533waitfor-upp$(EXEEXT):
     534        u++          schedext/upp.cc     -DBENCH_N=5000000     -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     535
     536waitfor-cfa1$(EXEEXT):
     537        ${CC}        schedext/cfa1.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     538
     539waitfor-cfa2$(EXEEXT):
     540        ${CC}        schedext/cfa2.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     541
     542waitfor-cfa4$(EXEEXT):
     543        ${CC}        schedext/cfa4.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     544
     545creation$(EXEEXT) :\
     546        creation-pthread.run                    \
     547        creation-cfa_coroutine.run              \
     548        creation-cfa_coroutine_eager.run        \
     549        creation-cfa_thread.run                 \
     550        creation-upp_coroutine.run              \
     551        creation-upp_thread.run
     552
     553creation-cfa_coroutine$(EXEEXT):
     554        ${CC}        creation/cfa_cor.c   -DBENCH_N=10000000   -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     555
     556creation-cfa_coroutine_eager$(EXEEXT):
     557        ${CC}        creation/cfa_cor.c   -DBENCH_N=10000000   -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} -DEAGER
     558
     559creation-cfa_thread$(EXEEXT):
     560        ${CC}        creation/cfa_thrd.c  -DBENCH_N=10000000   -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     561
     562creation-upp_coroutine$(EXEEXT):
     563        u++          creation/upp_cor.cc  -DBENCH_N=50000000   -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     564
     565creation-upp_thread$(EXEEXT):
     566        u++          creation/upp_thrd.cc -DBENCH_N=50000000   -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     567
     568creation-pthread$(EXEEXT):
     569        @BACKEND_CC@ creation/pthreads.c  -DBENCH_N=250000     -I. -lrt -pthread                    ${AM_CFLAGS} ${CFLAGS} ${ccflags}
     570
    450571%.run : %$(EXEEXT) ${REPEAT}
    451572        @rm -f .result.log
     
    457578        @rm -f a.out .result.log
    458579
    459 %.runquiet :
    460         @+make $(basename $@)
    461         @./a.out
    462         @rm -f a.out
    463 
    464 %.make :
    465         @printf "${PRINT_FORMAT}" $(basename $(subst compile-,,$@))
    466         @+/usr/bin/time -f ${TIME_FORMAT} make $(basename $@) 2>&1
    467 
    468580${REPEAT} :
    469581        @+make -C ${TOOLSDIR} repeat
    470 
    471 jenkins$(EXEEXT):
    472         @echo "{"
    473         @echo -e '\t"githash": "'${githash}'",'
    474         @echo -e '\t"arch": "'   ${arch}   '",'
    475         @echo -e '\t"compile": {'
    476         @+make compile TIME_FORMAT='%e,' PRINT_FORMAT='\t\t\"%s\" :'
    477         @echo -e '\t\t"dummy" : {}'
    478         @echo -e '\t},'
    479         @echo -e '\t"ctxswitch": {'
    480         @echo -en '\t\t"coroutine":'
    481         @+make ctxswitch-cfa_coroutine.runquiet
    482         @echo -en '\t\t,"thread":'
    483         @+make ctxswitch-cfa_thread.runquiet
    484         @echo -e '\t},'
    485         @echo -e '\t"mutex": ['
    486         @echo -en '\t\t'
    487         @+make mutex-cfa1.runquiet
    488         @echo -en '\t\t,'
    489         @+make mutex-cfa2.runquiet
    490         @echo -e '\t],'
    491         @echo -e '\t"scheduling": ['
    492         @echo -en '\t\t'
    493         @+make signal-cfa1.runquiet
    494         @echo -en '\t\t,'
    495         @+make signal-cfa2.runquiet
    496         @echo -en '\t\t,'
    497         @+make waitfor-cfa1.runquiet
    498         @echo -en '\t\t,'
    499         @+make waitfor-cfa2.runquiet
    500         @echo -e '\n\t],'
    501         @echo -e '\t"epoch": ' $(shell date +%s)
    502         @echo "}"
    503 
    504 ctxswitch$(EXEEXT): \
    505         ctxswitch-pthread.run           \
    506         ctxswitch-cfa_coroutine.run     \
    507         ctxswitch-cfa_thread.run        \
    508         ctxswitch-upp_coroutine.run     \
    509         ctxswitch-upp_thread.run
    510 
    511 ctxswitch-cfa_coroutine$(EXEEXT):
    512         @${CC}        ctxswitch/cfa_cor.c   -DBENCH_N=50000000  -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    513 
    514 ctxswitch-cfa_thread$(EXEEXT):
    515         @${CC}        ctxswitch/cfa_thrd.c  -DBENCH_N=50000000  -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    516 
    517 ctxswitch-upp_coroutine$(EXEEXT):
    518         @u++          ctxswitch/upp_cor.cc  -DBENCH_N=50000000  -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    519 
    520 ctxswitch-upp_thread$(EXEEXT):
    521         @u++          ctxswitch/upp_thrd.cc -DBENCH_N=50000000  -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    522 
    523 ctxswitch-pthread$(EXEEXT):
    524         @@BACKEND_CC@ ctxswitch/pthreads.c  -DBENCH_N=50000000  -I. -lrt -pthread                    ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    525 
    526 mutex$(EXEEXT) :\
    527         mutex-function.run      \
    528         mutex-pthread_lock.run  \
    529         mutex-upp.run           \
    530         mutex-cfa1.run          \
    531         mutex-cfa2.run          \
    532         mutex-cfa4.run
    533 
    534 mutex-function$(EXEEXT):
    535         @@BACKEND_CC@ mutex/function.c    -DBENCH_N=500000000   -I. -lrt -pthread                    ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    536 
    537 mutex-pthread_lock$(EXEEXT):
    538         @@BACKEND_CC@ mutex/pthreads.c    -DBENCH_N=50000000    -I. -lrt -pthread                    ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    539 
    540 mutex-upp$(EXEEXT):
    541         @u++          mutex/upp.cc        -DBENCH_N=50000000    -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    542 
    543 mutex-cfa1$(EXEEXT):
    544         @${CC}        mutex/cfa1.c        -DBENCH_N=5000000     -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    545 
    546 mutex-cfa2$(EXEEXT):
    547         @${CC}        mutex/cfa2.c        -DBENCH_N=5000000     -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    548 
    549 mutex-cfa4$(EXEEXT):
    550         @${CC}        mutex/cfa4.c        -DBENCH_N=5000000     -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    551 
    552 signal$(EXEEXT) :\
    553         signal-upp.run          \
    554         signal-cfa1.run         \
    555         signal-cfa2.run         \
    556         signal-cfa4.run
    557 
    558 signal-upp$(EXEEXT):
    559         @u++          schedint/upp.cc     -DBENCH_N=5000000     -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    560 
    561 signal-cfa1$(EXEEXT):
    562         @${CC}        schedint/cfa1.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    563 
    564 signal-cfa2$(EXEEXT):
    565         @${CC}        schedint/cfa2.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    566 
    567 signal-cfa4$(EXEEXT):
    568         @${CC}        schedint/cfa4.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    569 
    570 waitfor$(EXEEXT) :\
    571         waitfor-upp.run         \
    572         waitfor-cfa1.run                \
    573         waitfor-cfa2.run                \
    574         waitfor-cfa4.run
    575 
    576 waitfor-upp$(EXEEXT):
    577         @u++          schedext/upp.cc     -DBENCH_N=5000000     -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    578 
    579 waitfor-cfa1$(EXEEXT):
    580         @${CC}        schedext/cfa1.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    581 
    582 waitfor-cfa2$(EXEEXT):
    583         @${CC}        schedext/cfa2.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    584 
    585 waitfor-cfa4$(EXEEXT):
    586         @${CC}        schedext/cfa4.c     -DBENCH_N=500000      -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    587 
    588 creation$(EXEEXT) :\
    589         creation-pthread.run                    \
    590         creation-cfa_coroutine.run              \
    591         creation-cfa_coroutine_eager.run        \
    592         creation-cfa_thread.run                 \
    593         creation-upp_coroutine.run              \
    594         creation-upp_thread.run
    595 
    596 creation-cfa_coroutine$(EXEEXT):
    597         @${CC}        creation/cfa_cor.c   -DBENCH_N=10000000   -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    598 
    599 creation-cfa_coroutine_eager$(EXEEXT):
    600         @${CC}        creation/cfa_cor.c   -DBENCH_N=10000000   -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} -DEAGER
    601 
    602 creation-cfa_thread$(EXEEXT):
    603         @${CC}        creation/cfa_thrd.c  -DBENCH_N=10000000   -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    604 
    605 creation-upp_coroutine$(EXEEXT):
    606         @u++          creation/upp_cor.cc  -DBENCH_N=50000000   -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    607 
    608 creation-upp_thread$(EXEEXT):
    609         @u++          creation/upp_thrd.cc -DBENCH_N=50000000   -I. -nodebug -lrt -quiet             ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    610 
    611 creation-pthread$(EXEEXT):
    612         @@BACKEND_CC@ creation/pthreads.c  -DBENCH_N=250000     -I. -lrt -pthread                    ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    613 
    614 compile$(EXEEXT) :\
    615         compile-array.make      \
    616         compile-attributes.make \
    617         compile-empty.make      \
    618         compile-expression.make \
    619         compile-io.make         \
    620         compile-monitor.make    \
    621         compile-operators.make  \
    622         compile-typeof.make
    623 
    624 compile-array$(EXEEXT):
    625         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/array.c                @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    626 
    627 compile-attributes$(EXEEXT):
    628         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/attributes.c   @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    629 
    630 compile-empty$(EXEEXT):
    631         @${CC} -nodebug -quiet -fsyntax-only -w compile/empty.c         @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    632 
    633 compile-expression$(EXEEXT):
    634         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/expression.c   @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    635 
    636 compile-io$(EXEEXT):
    637         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/io.c                   @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    638 
    639 compile-monitor$(EXEEXT):
    640         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/monitor.c              @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    641 
    642 compile-operators$(EXEEXT):
    643         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/operators.c    @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    644 
    645 compile-thread$(EXEEXT):
    646         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/thread.c               @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    647 
    648 compile-typeof$(EXEEXT):
    649         @${CC} -nodebug -quiet -fsyntax-only -w ../tests/typeof.c               @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}
    650582
    651583# Tell versions [3.59,3.63) of GNU make to not export all variables.
  • src/main.cc

    r9e1eabc r65d6de4  
    206206                        FILE * extras = fopen( libcfap | treep ? "../prelude/extras.cf" : CFA_LIBDIR "/extras.cf", "r" );
    207207                        assertf( extras, "cannot open extras.cf\n" );
    208                         parse( extras, LinkageSpec::BuiltinC );
     208                        parse( extras, LinkageSpec::C );
    209209
    210210                        if ( ! libcfap ) {
  • src/tests/.expect/32/KRfunctions.txt

    r9e1eabc r65d6de4  
     1__attribute__ ((__nothrow__,__leaf__,__malloc__)) extern void *malloc(unsigned int __size);
     2__attribute__ ((__nothrow__,__leaf__)) extern void free(void *__ptr);
     3__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void abort(void);
     4__attribute__ ((__nothrow__,__leaf__,__nonnull__(1))) extern signed int atexit(void (*__func)(void));
     5__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void exit(signed int __status);
     6extern signed int printf(const char *__restrict __format, ...);
    17signed int __f0__Fi_iPCii__1(signed int __a__i_1, const signed int *__b__PCi_1, signed int __c__i_1){
    28    __attribute__ ((unused)) signed int ___retval_f0__i_1;
  • src/tests/.expect/32/attributes.txt

    r9e1eabc r65d6de4  
     1__attribute__ ((__nothrow__,__leaf__,__malloc__)) extern void *malloc(unsigned int __size);
     2__attribute__ ((__nothrow__,__leaf__)) extern void free(void *__ptr);
     3__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void abort(void);
     4__attribute__ ((__nothrow__,__leaf__,__nonnull__(1))) extern signed int atexit(void (*__func)(void));
     5__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void exit(signed int __status);
     6extern signed int printf(const char *__restrict __format, ...);
    17signed int __la__Fi___1(){
    28    __attribute__ ((unused)) signed int ___retval_la__i_1;
  • src/tests/.expect/32/declarationSpecifier.txt

    r9e1eabc r65d6de4  
     1__attribute__ ((__nothrow__,__leaf__,__malloc__)) extern void *malloc(unsigned int __size);
     2__attribute__ ((__nothrow__,__leaf__)) extern void free(void *__ptr);
     3__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void abort(void);
     4__attribute__ ((__nothrow__,__leaf__,__nonnull__(1))) extern signed int atexit(void (*__func)(void));
     5__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void exit(signed int __status);
     6extern signed int printf(const char *__restrict __format, ...);
    17volatile const signed short int __x1__CVs_1;
    28static volatile const signed short int __x2__CVs_1;
     
    695701}
    696702static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return __main__Fi_iPPCc__1(argc, argv); }
     703__attribute__ ((__nothrow__,__leaf__,__malloc__)) extern void *malloc(unsigned int __size);
     704__attribute__ ((__nothrow__,__leaf__)) extern void free(void *__ptr);
     705__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void abort(void);
     706__attribute__ ((__nothrow__,__leaf__,__nonnull__(1))) extern signed int atexit(void (*__func)(void));
     707__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void exit(signed int __status);
     708extern signed int printf(const char *__restrict __format, ...);
    697709static inline signed int invoke_main(signed int argc, char **argv, char **envp);
    698710signed int main(signed int __argc__i_1, char **__argv__PPc_1, char **__envp__PPc_1){
  • src/tests/.expect/32/extension.txt

    r9e1eabc r65d6de4  
     1__attribute__ ((__nothrow__,__leaf__,__malloc__)) extern void *malloc(unsigned int __size);
     2__attribute__ ((__nothrow__,__leaf__)) extern void free(void *__ptr);
     3__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void abort(void);
     4__attribute__ ((__nothrow__,__leaf__,__nonnull__(1))) extern signed int atexit(void (*__func)(void));
     5__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void exit(signed int __status);
     6extern signed int printf(const char *__restrict __format, ...);
    17__extension__ signed int __a__i_1;
    28__extension__ signed int __b__i_1;
  • src/tests/.expect/32/gccExtensions.txt

    r9e1eabc r65d6de4  
     1__attribute__ ((__nothrow__,__leaf__,__malloc__)) extern void *malloc(unsigned int __size);
     2__attribute__ ((__nothrow__,__leaf__)) extern void free(void *__ptr);
     3__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void abort(void);
     4__attribute__ ((__nothrow__,__leaf__,__nonnull__(1))) extern signed int atexit(void (*__func)(void));
     5__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void exit(signed int __status);
     6extern signed int printf(const char *__restrict __format, ...);
    17extern signed int __x__i_1 asm ( "xx" );
    28signed int __main__Fi_iPPCc__1(signed int __argc__i_1, const char **__argv__PPCc_1){
     
    168174}
    169175static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return __main__Fi_iPPCc__1(argc, argv); }
     176__attribute__ ((__nothrow__,__leaf__,__malloc__)) extern void *malloc(unsigned int __size);
     177__attribute__ ((__nothrow__,__leaf__)) extern void free(void *__ptr);
     178__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void abort(void);
     179__attribute__ ((__nothrow__,__leaf__,__nonnull__(1))) extern signed int atexit(void (*__func)(void));
     180__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void exit(signed int __status);
     181extern signed int printf(const char *__restrict __format, ...);
    170182static inline signed int invoke_main(signed int argc, char **argv, char **envp);
    171183signed int main(signed int __argc__i_1, char **__argv__PPc_1, char **__envp__PPc_1){
  • src/tests/.expect/32/literals.txt

    r9e1eabc r65d6de4  
     1__attribute__ ((__nothrow__,__leaf__,__malloc__)) extern void *malloc(unsigned int __size);
     2__attribute__ ((__nothrow__,__leaf__)) extern void free(void *__ptr);
     3__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void abort(void);
     4__attribute__ ((__nothrow__,__leaf__,__nonnull__(1))) extern signed int atexit(void (*__func)(void));
     5__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void exit(signed int __status);
     6extern signed int printf(const char *__restrict __format, ...);
    17void __for_each__A0_2_0_0____operator_assign__PFd0_Rd0d0____constructor__PF_Rd0____constructor__PF_Rd0d0____destructor__PF_Rd0____operator_assign__PFd1_Rd1d1____constructor__PF_Rd1____constructor__PF_Rd1d1____destructor__PF_Rd1____operator_preincr__PFd0_Rd0____operator_predecr__PFd0_Rd0____operator_equal__PFi_d0d0____operator_notequal__PFi_d0d0____operator_deref__PFRd1_d0__F_d0d0PF_d1___1(__attribute__ ((unused)) void (*_adapterF_9telt_type__P)(void (*__anonymous_object0)(), void *__anonymous_object1), __attribute__ ((unused)) void *(*_adapterFP9telt_type_14titerator_type_M_P)(void (*__anonymous_object2)(), void *__anonymous_object3), __attribute__ ((unused)) signed int (*_adapterFi_14titerator_type14titerator_type_M_PP)(void (*__anonymous_object4)(), void *__anonymous_object5, void *__anonymous_object6), __attribute__ ((unused)) void (*_adapterF14titerator_type_P14titerator_type_P_M)(void (*__anonymous_object7)(), __attribute__ ((unused)) void *___retval__operator_preincr__14titerator_type_1, void *__anonymous_object8), __attribute__ ((unused)) void (*_adapterF_P9telt_type9telt_type__MP)(void (*__anonymous_object9)(), void *__anonymous_object10, void *__anonymous_object11), __attribute__ ((unused)) void (*_adapterF9telt_type_P9telt_type9telt_type_P_MP)(void (*__anonymous_object12)(), __attribute__ ((unused)) void *___retval__operator_assign__9telt_type_1, void *__anonymous_object13, void *__anonymous_object14), __attribute__ ((unused)) void (*_adapterF_P14titerator_type14titerator_type__MP)(void (*__anonymous_object15)(), void *__anonymous_object16, void *__anonymous_object17), __attribute__ ((unused)) void (*_adapterF14titerator_type_P14titerator_type14titerator_type_P_MP)(void (*__anonymous_object18)(), __attribute__ ((unused)) void *___retval__operator_assign__14titerator_type_1, void *__anonymous_object19, void *__anonymous_object20), __attribute__ ((unused)) unsigned long int _sizeof_14titerator_type, __attribute__ ((unused)) unsigned long int _alignof_14titerator_type, __attribute__ ((unused)) unsigned long int _sizeof_9telt_type, __attribute__ ((unused)) unsigned long int _alignof_9telt_type, __attribute__ ((unused)) void *(*___operator_assign__PF14titerator_type_R14titerator_type14titerator_type__1)(void *__anonymous_object21, void *__anonymous_object22), __attribute__ ((unused)) void (*___constructor__PF_R14titerator_type__1)(void *__anonymous_object23), __attribute__ ((unused)) void (*___constructor__PF_R14titerator_type14titerator_type__1)(void *__anonymous_object24, void *__anonymous_object25), __attribute__ ((unused)) void (*___destructor__PF_R14titerator_type__1)(void *__anonymous_object26), __attribute__ ((unused)) void *(*___operator_assign__PF9telt_type_R9telt_type9telt_type__1)(void *__anonymous_object27, void *__anonymous_object28), __attribute__ ((unused)) void (*___constructor__PF_R9telt_type__1)(void *__anonymous_object29), __attribute__ ((unused)) void (*___constructor__PF_R9telt_type9telt_type__1)(void *__anonymous_object30, void *__anonymous_object31), __attribute__ ((unused)) void (*___destructor__PF_R9telt_type__1)(void *__anonymous_object32), __attribute__ ((unused)) void *(*___operator_preincr__PF14titerator_type_R14titerator_type__1)(void *__anonymous_object33), __attribute__ ((unused)) void *(*___operator_predecr__PF14titerator_type_R14titerator_type__1)(void *__anonymous_object34), __attribute__ ((unused)) signed int (*___operator_equal__PFi_14titerator_type14titerator_type__1)(void *__anonymous_object35, void *__anonymous_object36), __attribute__ ((unused)) signed int (*___operator_notequal__PFi_14titerator_type14titerator_type__1)(void *__anonymous_object37, void *__anonymous_object38), __attribute__ ((unused)) void *(*___operator_deref__PFR9telt_type_14titerator_type__1)(void *__anonymous_object39), void *__begin__14titerator_type_1, void *__end__14titerator_type_1, void (*__func__PF_9telt_type__1)(void *__anonymous_object40));
    28void __for_each_reverse__A0_2_0_0____operator_assign__PFd0_Rd0d0____constructor__PF_Rd0____constructor__PF_Rd0d0____destructor__PF_Rd0____operator_assign__PFd1_Rd1d1____constructor__PF_Rd1____constructor__PF_Rd1d1____destructor__PF_Rd1____operator_preincr__PFd0_Rd0____operator_predecr__PFd0_Rd0____operator_equal__PFi_d0d0____operator_notequal__PFi_d0d0____operator_deref__PFRd1_d0__F_d0d0PF_d1___1(__attribute__ ((unused)) void (*_adapterF_9telt_type__P)(void (*__anonymous_object41)(), void *__anonymous_object42), __attribute__ ((unused)) void *(*_adapterFP9telt_type_14titerator_type_M_P)(void (*__anonymous_object43)(), void *__anonymous_object44), __attribute__ ((unused)) signed int (*_adapterFi_14titerator_type14titerator_type_M_PP)(void (*__anonymous_object45)(), void *__anonymous_object46, void *__anonymous_object47), __attribute__ ((unused)) void (*_adapterF14titerator_type_P14titerator_type_P_M)(void (*__anonymous_object48)(), __attribute__ ((unused)) void *___retval__operator_preincr__14titerator_type_1, void *__anonymous_object49), __attribute__ ((unused)) void (*_adapterF_P9telt_type9telt_type__MP)(void (*__anonymous_object50)(), void *__anonymous_object51, void *__anonymous_object52), __attribute__ ((unused)) void (*_adapterF9telt_type_P9telt_type9telt_type_P_MP)(void (*__anonymous_object53)(), __attribute__ ((unused)) void *___retval__operator_assign__9telt_type_1, void *__anonymous_object54, void *__anonymous_object55), __attribute__ ((unused)) void (*_adapterF_P14titerator_type14titerator_type__MP)(void (*__anonymous_object56)(), void *__anonymous_object57, void *__anonymous_object58), __attribute__ ((unused)) void (*_adapterF14titerator_type_P14titerator_type14titerator_type_P_MP)(void (*__anonymous_object59)(), __attribute__ ((unused)) void *___retval__operator_assign__14titerator_type_1, void *__anonymous_object60, void *__anonymous_object61), __attribute__ ((unused)) unsigned long int _sizeof_14titerator_type, __attribute__ ((unused)) unsigned long int _alignof_14titerator_type, __attribute__ ((unused)) unsigned long int _sizeof_9telt_type, __attribute__ ((unused)) unsigned long int _alignof_9telt_type, __attribute__ ((unused)) void *(*___operator_assign__PF14titerator_type_R14titerator_type14titerator_type__1)(void *__anonymous_object62, void *__anonymous_object63), __attribute__ ((unused)) void (*___constructor__PF_R14titerator_type__1)(void *__anonymous_object64), __attribute__ ((unused)) void (*___constructor__PF_R14titerator_type14titerator_type__1)(void *__anonymous_object65, void *__anonymous_object66), __attribute__ ((unused)) void (*___destructor__PF_R14titerator_type__1)(void *__anonymous_object67), __attribute__ ((unused)) void *(*___operator_assign__PF9telt_type_R9telt_type9telt_type__1)(void *__anonymous_object68, void *__anonymous_object69), __attribute__ ((unused)) void (*___constructor__PF_R9telt_type__1)(void *__anonymous_object70), __attribute__ ((unused)) void (*___constructor__PF_R9telt_type9telt_type__1)(void *__anonymous_object71, void *__anonymous_object72), __attribute__ ((unused)) void (*___destructor__PF_R9telt_type__1)(void *__anonymous_object73), __attribute__ ((unused)) void *(*___operator_preincr__PF14titerator_type_R14titerator_type__1)(void *__anonymous_object74), __attribute__ ((unused)) void *(*___operator_predecr__PF14titerator_type_R14titerator_type__1)(void *__anonymous_object75), __attribute__ ((unused)) signed int (*___operator_equal__PFi_14titerator_type14titerator_type__1)(void *__anonymous_object76, void *__anonymous_object77), __attribute__ ((unused)) signed int (*___operator_notequal__PFi_14titerator_type14titerator_type__1)(void *__anonymous_object78, void *__anonymous_object79), __attribute__ ((unused)) void *(*___operator_deref__PFR9telt_type_14titerator_type__1)(void *__anonymous_object80), void *__begin__14titerator_type_1, void *__end__14titerator_type_1, void (*__func__PF_9telt_type__1)(void *__anonymous_object81));
     
    13711377}
    13721378static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return __main__Fi___1(); }
     1379__attribute__ ((__nothrow__,__leaf__,__malloc__)) extern void *malloc(unsigned int __size);
     1380__attribute__ ((__nothrow__,__leaf__)) extern void free(void *__ptr);
     1381__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void abort(void);
     1382__attribute__ ((__nothrow__,__leaf__,__nonnull__(1))) extern signed int atexit(void (*__func)(void));
     1383__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void exit(signed int __status);
     1384extern signed int printf(const char *__restrict __format, ...);
    13731385static inline signed int invoke_main(signed int argc, char **argv, char **envp);
    13741386signed int main(signed int __argc__i_1, char **__argv__PPc_1, char **__envp__PPc_1){
  • src/tests/.expect/64/KRfunctions.txt

    r9e1eabc r65d6de4  
     1__attribute__ ((__nothrow__,__leaf__,__malloc__)) extern void *malloc(unsigned long int __size);
     2__attribute__ ((__nothrow__,__leaf__)) extern void free(void *__ptr);
     3__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void abort(void);
     4__attribute__ ((__nothrow__,__leaf__,__nonnull__(1))) extern signed int atexit(void (*__func)(void));
     5__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void exit(signed int __status);
     6extern signed int printf(const char *__restrict __format, ...);
    17signed int __f0__Fi_iPCii__1(signed int __a__i_1, const signed int *__b__PCi_1, signed int __c__i_1){
    28    __attribute__ ((unused)) signed int ___retval_f0__i_1;
  • src/tests/.expect/64/attributes.txt

    r9e1eabc r65d6de4  
     1__attribute__ ((__nothrow__,__leaf__,__malloc__)) extern void *malloc(unsigned long int __size);
     2__attribute__ ((__nothrow__,__leaf__)) extern void free(void *__ptr);
     3__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void abort(void);
     4__attribute__ ((__nothrow__,__leaf__,__nonnull__(1))) extern signed int atexit(void (*__func)(void));
     5__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void exit(signed int __status);
     6extern signed int printf(const char *__restrict __format, ...);
    17signed int __la__Fi___1(){
    28    __attribute__ ((unused)) signed int ___retval_la__i_1;
  • src/tests/.expect/64/declarationSpecifier.txt

    r9e1eabc r65d6de4  
     1__attribute__ ((__nothrow__,__leaf__,__malloc__)) extern void *malloc(unsigned long int __size);
     2__attribute__ ((__nothrow__,__leaf__)) extern void free(void *__ptr);
     3__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void abort(void);
     4__attribute__ ((__nothrow__,__leaf__,__nonnull__(1))) extern signed int atexit(void (*__func)(void));
     5__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void exit(signed int __status);
     6extern signed int printf(const char *__restrict __format, ...);
    17volatile const signed short int __x1__CVs_1;
    28static volatile const signed short int __x2__CVs_1;
     
    695701}
    696702static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return __main__Fi_iPPCc__1(argc, argv); }
     703__attribute__ ((__nothrow__,__leaf__,__malloc__)) extern void *malloc(unsigned long int __size);
     704__attribute__ ((__nothrow__,__leaf__)) extern void free(void *__ptr);
     705__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void abort(void);
     706__attribute__ ((__nothrow__,__leaf__,__nonnull__(1))) extern signed int atexit(void (*__func)(void));
     707__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void exit(signed int __status);
     708extern signed int printf(const char *__restrict __format, ...);
    697709static inline signed int invoke_main(signed int argc, char **argv, char **envp);
    698710signed int main(signed int __argc__i_1, char **__argv__PPc_1, char **__envp__PPc_1){
  • src/tests/.expect/64/extension.txt

    r9e1eabc r65d6de4  
     1__attribute__ ((__nothrow__,__leaf__,__malloc__)) extern void *malloc(unsigned long int __size);
     2__attribute__ ((__nothrow__,__leaf__)) extern void free(void *__ptr);
     3__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void abort(void);
     4__attribute__ ((__nothrow__,__leaf__,__nonnull__(1))) extern signed int atexit(void (*__func)(void));
     5__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void exit(signed int __status);
     6extern signed int printf(const char *__restrict __format, ...);
    17__extension__ signed int __a__i_1;
    28__extension__ signed int __b__i_1;
  • src/tests/.expect/64/gccExtensions.txt

    r9e1eabc r65d6de4  
     1__attribute__ ((__nothrow__,__leaf__,__malloc__)) extern void *malloc(unsigned long int __size);
     2__attribute__ ((__nothrow__,__leaf__)) extern void free(void *__ptr);
     3__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void abort(void);
     4__attribute__ ((__nothrow__,__leaf__,__nonnull__(1))) extern signed int atexit(void (*__func)(void));
     5__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void exit(signed int __status);
     6extern signed int printf(const char *__restrict __format, ...);
    17extern signed int __x__i_1 asm ( "xx" );
    28signed int __main__Fi_iPPCc__1(signed int __argc__i_1, const char **__argv__PPCc_1){
     
    168174}
    169175static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return __main__Fi_iPPCc__1(argc, argv); }
     176__attribute__ ((__nothrow__,__leaf__,__malloc__)) extern void *malloc(unsigned long int __size);
     177__attribute__ ((__nothrow__,__leaf__)) extern void free(void *__ptr);
     178__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void abort(void);
     179__attribute__ ((__nothrow__,__leaf__,__nonnull__(1))) extern signed int atexit(void (*__func)(void));
     180__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void exit(signed int __status);
     181extern signed int printf(const char *__restrict __format, ...);
    170182static inline signed int invoke_main(signed int argc, char **argv, char **envp);
    171183signed int main(signed int __argc__i_1, char **__argv__PPc_1, char **__envp__PPc_1){
  • src/tests/.expect/64/literals.txt

    r9e1eabc r65d6de4  
     1__attribute__ ((__nothrow__,__leaf__,__malloc__)) extern void *malloc(unsigned long int __size);
     2__attribute__ ((__nothrow__,__leaf__)) extern void free(void *__ptr);
     3__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void abort(void);
     4__attribute__ ((__nothrow__,__leaf__,__nonnull__(1))) extern signed int atexit(void (*__func)(void));
     5__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void exit(signed int __status);
     6extern signed int printf(const char *__restrict __format, ...);
    17void __for_each__A0_2_0_0____operator_assign__PFd0_Rd0d0____constructor__PF_Rd0____constructor__PF_Rd0d0____destructor__PF_Rd0____operator_assign__PFd1_Rd1d1____constructor__PF_Rd1____constructor__PF_Rd1d1____destructor__PF_Rd1____operator_preincr__PFd0_Rd0____operator_predecr__PFd0_Rd0____operator_equal__PFi_d0d0____operator_notequal__PFi_d0d0____operator_deref__PFRd1_d0__F_d0d0PF_d1___1(__attribute__ ((unused)) void (*_adapterF_9telt_type__P)(void (*__anonymous_object0)(), void *__anonymous_object1), __attribute__ ((unused)) void *(*_adapterFP9telt_type_14titerator_type_M_P)(void (*__anonymous_object2)(), void *__anonymous_object3), __attribute__ ((unused)) signed int (*_adapterFi_14titerator_type14titerator_type_M_PP)(void (*__anonymous_object4)(), void *__anonymous_object5, void *__anonymous_object6), __attribute__ ((unused)) void (*_adapterF14titerator_type_P14titerator_type_P_M)(void (*__anonymous_object7)(), __attribute__ ((unused)) void *___retval__operator_preincr__14titerator_type_1, void *__anonymous_object8), __attribute__ ((unused)) void (*_adapterF_P9telt_type9telt_type__MP)(void (*__anonymous_object9)(), void *__anonymous_object10, void *__anonymous_object11), __attribute__ ((unused)) void (*_adapterF9telt_type_P9telt_type9telt_type_P_MP)(void (*__anonymous_object12)(), __attribute__ ((unused)) void *___retval__operator_assign__9telt_type_1, void *__anonymous_object13, void *__anonymous_object14), __attribute__ ((unused)) void (*_adapterF_P14titerator_type14titerator_type__MP)(void (*__anonymous_object15)(), void *__anonymous_object16, void *__anonymous_object17), __attribute__ ((unused)) void (*_adapterF14titerator_type_P14titerator_type14titerator_type_P_MP)(void (*__anonymous_object18)(), __attribute__ ((unused)) void *___retval__operator_assign__14titerator_type_1, void *__anonymous_object19, void *__anonymous_object20), __attribute__ ((unused)) unsigned long int _sizeof_14titerator_type, __attribute__ ((unused)) unsigned long int _alignof_14titerator_type, __attribute__ ((unused)) unsigned long int _sizeof_9telt_type, __attribute__ ((unused)) unsigned long int _alignof_9telt_type, __attribute__ ((unused)) void *(*___operator_assign__PF14titerator_type_R14titerator_type14titerator_type__1)(void *__anonymous_object21, void *__anonymous_object22), __attribute__ ((unused)) void (*___constructor__PF_R14titerator_type__1)(void *__anonymous_object23), __attribute__ ((unused)) void (*___constructor__PF_R14titerator_type14titerator_type__1)(void *__anonymous_object24, void *__anonymous_object25), __attribute__ ((unused)) void (*___destructor__PF_R14titerator_type__1)(void *__anonymous_object26), __attribute__ ((unused)) void *(*___operator_assign__PF9telt_type_R9telt_type9telt_type__1)(void *__anonymous_object27, void *__anonymous_object28), __attribute__ ((unused)) void (*___constructor__PF_R9telt_type__1)(void *__anonymous_object29), __attribute__ ((unused)) void (*___constructor__PF_R9telt_type9telt_type__1)(void *__anonymous_object30, void *__anonymous_object31), __attribute__ ((unused)) void (*___destructor__PF_R9telt_type__1)(void *__anonymous_object32), __attribute__ ((unused)) void *(*___operator_preincr__PF14titerator_type_R14titerator_type__1)(void *__anonymous_object33), __attribute__ ((unused)) void *(*___operator_predecr__PF14titerator_type_R14titerator_type__1)(void *__anonymous_object34), __attribute__ ((unused)) signed int (*___operator_equal__PFi_14titerator_type14titerator_type__1)(void *__anonymous_object35, void *__anonymous_object36), __attribute__ ((unused)) signed int (*___operator_notequal__PFi_14titerator_type14titerator_type__1)(void *__anonymous_object37, void *__anonymous_object38), __attribute__ ((unused)) void *(*___operator_deref__PFR9telt_type_14titerator_type__1)(void *__anonymous_object39), void *__begin__14titerator_type_1, void *__end__14titerator_type_1, void (*__func__PF_9telt_type__1)(void *__anonymous_object40));
    28void __for_each_reverse__A0_2_0_0____operator_assign__PFd0_Rd0d0____constructor__PF_Rd0____constructor__PF_Rd0d0____destructor__PF_Rd0____operator_assign__PFd1_Rd1d1____constructor__PF_Rd1____constructor__PF_Rd1d1____destructor__PF_Rd1____operator_preincr__PFd0_Rd0____operator_predecr__PFd0_Rd0____operator_equal__PFi_d0d0____operator_notequal__PFi_d0d0____operator_deref__PFRd1_d0__F_d0d0PF_d1___1(__attribute__ ((unused)) void (*_adapterF_9telt_type__P)(void (*__anonymous_object41)(), void *__anonymous_object42), __attribute__ ((unused)) void *(*_adapterFP9telt_type_14titerator_type_M_P)(void (*__anonymous_object43)(), void *__anonymous_object44), __attribute__ ((unused)) signed int (*_adapterFi_14titerator_type14titerator_type_M_PP)(void (*__anonymous_object45)(), void *__anonymous_object46, void *__anonymous_object47), __attribute__ ((unused)) void (*_adapterF14titerator_type_P14titerator_type_P_M)(void (*__anonymous_object48)(), __attribute__ ((unused)) void *___retval__operator_preincr__14titerator_type_1, void *__anonymous_object49), __attribute__ ((unused)) void (*_adapterF_P9telt_type9telt_type__MP)(void (*__anonymous_object50)(), void *__anonymous_object51, void *__anonymous_object52), __attribute__ ((unused)) void (*_adapterF9telt_type_P9telt_type9telt_type_P_MP)(void (*__anonymous_object53)(), __attribute__ ((unused)) void *___retval__operator_assign__9telt_type_1, void *__anonymous_object54, void *__anonymous_object55), __attribute__ ((unused)) void (*_adapterF_P14titerator_type14titerator_type__MP)(void (*__anonymous_object56)(), void *__anonymous_object57, void *__anonymous_object58), __attribute__ ((unused)) void (*_adapterF14titerator_type_P14titerator_type14titerator_type_P_MP)(void (*__anonymous_object59)(), __attribute__ ((unused)) void *___retval__operator_assign__14titerator_type_1, void *__anonymous_object60, void *__anonymous_object61), __attribute__ ((unused)) unsigned long int _sizeof_14titerator_type, __attribute__ ((unused)) unsigned long int _alignof_14titerator_type, __attribute__ ((unused)) unsigned long int _sizeof_9telt_type, __attribute__ ((unused)) unsigned long int _alignof_9telt_type, __attribute__ ((unused)) void *(*___operator_assign__PF14titerator_type_R14titerator_type14titerator_type__1)(void *__anonymous_object62, void *__anonymous_object63), __attribute__ ((unused)) void (*___constructor__PF_R14titerator_type__1)(void *__anonymous_object64), __attribute__ ((unused)) void (*___constructor__PF_R14titerator_type14titerator_type__1)(void *__anonymous_object65, void *__anonymous_object66), __attribute__ ((unused)) void (*___destructor__PF_R14titerator_type__1)(void *__anonymous_object67), __attribute__ ((unused)) void *(*___operator_assign__PF9telt_type_R9telt_type9telt_type__1)(void *__anonymous_object68, void *__anonymous_object69), __attribute__ ((unused)) void (*___constructor__PF_R9telt_type__1)(void *__anonymous_object70), __attribute__ ((unused)) void (*___constructor__PF_R9telt_type9telt_type__1)(void *__anonymous_object71, void *__anonymous_object72), __attribute__ ((unused)) void (*___destructor__PF_R9telt_type__1)(void *__anonymous_object73), __attribute__ ((unused)) void *(*___operator_preincr__PF14titerator_type_R14titerator_type__1)(void *__anonymous_object74), __attribute__ ((unused)) void *(*___operator_predecr__PF14titerator_type_R14titerator_type__1)(void *__anonymous_object75), __attribute__ ((unused)) signed int (*___operator_equal__PFi_14titerator_type14titerator_type__1)(void *__anonymous_object76, void *__anonymous_object77), __attribute__ ((unused)) signed int (*___operator_notequal__PFi_14titerator_type14titerator_type__1)(void *__anonymous_object78, void *__anonymous_object79), __attribute__ ((unused)) void *(*___operator_deref__PFR9telt_type_14titerator_type__1)(void *__anonymous_object80), void *__begin__14titerator_type_1, void *__end__14titerator_type_1, void (*__func__PF_9telt_type__1)(void *__anonymous_object81));
     
    13711377}
    13721378static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return __main__Fi___1(); }
     1379__attribute__ ((__nothrow__,__leaf__,__malloc__)) extern void *malloc(unsigned long int __size);
     1380__attribute__ ((__nothrow__,__leaf__)) extern void free(void *__ptr);
     1381__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void abort(void);
     1382__attribute__ ((__nothrow__,__leaf__,__nonnull__(1))) extern signed int atexit(void (*__func)(void));
     1383__attribute__ ((__nothrow__,__leaf__,__noreturn__)) extern void exit(signed int __status);
     1384extern signed int printf(const char *__restrict __format, ...);
    13731385static inline signed int invoke_main(signed int argc, char **argv, char **envp);
    13741386signed int main(signed int __argc__i_1, char **__argv__PPc_1, char **__envp__PPc_1){
Note: See TracChangeset for help on using the changeset viewer.