1 | \chapter{\CFA Runtime}\label{cfaruntime} |
---|
2 | This chapter presents an overview of the capabilities of the \CFA runtime prior to this thesis work. |
---|
3 | |
---|
4 | \section{C Threading} |
---|
5 | |
---|
6 | \Celeven introduced threading features, such the @_Thread_local@ storage class, and libraries @stdatomic.h@ and @threads.h@. |
---|
7 | Interestingly, almost a decade after the \Celeven standard, the most recent versions of gcc, clang, and msvc do not support the \Celeven include @threads.h@, indicating no interest in the C11 concurrency approach (possibly because of the recent effort to add concurrency to \CC). |
---|
8 | While the \Celeven standard does not state a threading model, the historical association with pthreads suggests implementations would adopt kernel-level threading (1:1)~\cite{ThreadModel}, as for \CC. |
---|
9 | This model uses \glspl{kthrd} to achieve parallelism and concurrency. In this model, every thread of computation maps to an object in the kernel. |
---|
10 | The kernel then has the responsibility of managing these threads, \eg creating, scheduling, blocking. |
---|
11 | A consequence of this approach is that the kernel has a perfect view of every thread executing in the system\footnote{This is not completely true due to primitives like \lstinline|futex|es, which have a significant portion of their logic in user space.}. |
---|
12 | |
---|
13 | \section{M:N Threading}\label{prev:model} |
---|
14 | |
---|
15 | Threading in \CFA is based on \Gls{uthrding}, where \glspl{thrd} are the representation of a unit of work. As such, \CFA programmers should expect these units to be fairly inexpensive, \ie programmers should be able to create a large number of \glspl{thrd} and switch among \glspl{thrd} liberally without many concerns for performance. |
---|
16 | |
---|
17 | The \CFA M:N threading models is implemented using many user-level threads mapped onto fewer \glspl{kthrd}. |
---|
18 | The user-level threads have the same semantic meaning as a \glspl{kthrd} in the 1:1 model: they represent an independent thread of execution with its own stack. |
---|
19 | The difference is that user-level threads do not have a corresponding object in the kernel; they are handled by the runtime in user space and scheduled onto \glspl{kthrd}, referred to as \glspl{proc} in this document. \Glspl{proc} run a \gls{thrd} until it context switches out, it then chooses a different \gls{thrd} to run. |
---|
20 | |
---|
21 | \section{Clusters} |
---|
22 | \CFA allows the option to group user-level threading, in the form of clusters. |
---|
23 | Both \glspl{thrd} and \glspl{proc} belong to a specific cluster. |
---|
24 | \Glspl{thrd} are only scheduled onto \glspl{proc} in the same cluster and scheduling is done independently of other clusters. |
---|
25 | Figure~\ref{fig:system} shows an overview of the \CFA runtime, which allows programmers to tightly control parallelism. |
---|
26 | It also opens the door to handling effects like NUMA, by pinning clusters to a specific NUMA node\footnote{This capability is not currently implemented in \CFA, but the only hurdle left is creating a generic interface for CPU masks.}. |
---|
27 | |
---|
28 | \begin{figure} |
---|
29 | \begin{center} |
---|
30 | \input{system.pstex_t} |
---|
31 | \end{center} |
---|
32 | \caption[Overview of the \CFA runtime]{Overview of the \CFA runtime \newline \Glspl{thrd} are scheduled inside a particular cluster and run on the \glspl{proc} that belong to the cluster. The discrete-event manager, which handles preemption and timeout, is a \gls{proc} that lives outside any cluster and does not run \glspl{thrd}.} |
---|
33 | \label{fig:system} |
---|
34 | \end{figure} |
---|
35 | |
---|
36 | \section{Scheduling} |
---|
37 | The \CFA runtime previously used a \glsxtrshort{fifo} ready-queue with a single lock. This setup offers perfect fairness in terms of opportunities to run. However, it offers poor scalability, since the performance of the ready queue can never be improved by adding more \glspl{hthrd} and contention can cause significant performance degradation. |
---|
38 | |
---|
39 | \section{\glsxtrshort{io}}\label{prev:io} |
---|
40 | Prior to this work, the \CFA runtime did not add any particular support for \glsxtrshort{io} operations. While all \glsxtrshort{io} operations available in C are available in \CFA, \glsxtrshort{io} operations are designed for the POSIX threading model~\cite{pthreads}. Using these 1:1 threading operations in an M:N threading model means \glsxtrshort{io} operations block \glspl{proc} instead of \glspl{thrd}. While this can work in certain cases, it limits the number of concurrent operations to the number of \glspl{proc} rather than \glspl{thrd}. It also means deadlock can occur because all \glspl{proc} are blocked even if at least one \gls{thrd} is ready to run. A simple example of this type of deadlock would be as follows: |
---|
41 | |
---|
42 | \begin{quote} |
---|
43 | Given a simple network program with 2 \glspl{thrd} and a single \gls{proc}, one \gls{thrd} sends network requests to a server and the other \gls{thrd} waits for a response from the server. |
---|
44 | If the second \gls{thrd} races ahead, it may wait for responses to requests that have not been sent yet. |
---|
45 | In theory, this should not be a problem, even if the second \gls{thrd} waits, because the first \gls{thrd} is still ready to run and should be able to get CPU time to send the request. |
---|
46 | With M:N threading, while the first \gls{thrd} is ready, the lone \gls{proc} \emph{cannot} run the first \gls{thrd} if it is blocked in the \glsxtrshort{io} operation of the second \gls{thrd}. |
---|
47 | If this happen, the system is in a synchronization deadlock\footnote{In this example, the deadlock could be resolved if the server sends unprompted messages to the client. |
---|
48 | However, this solution is neither general nor appropriate even in this simple case.}. |
---|
49 | \end{quote} |
---|
50 | |
---|
51 | Therefore, one of the objective of this work is to introduce \emph{User-Level \glsxtrshort{io}}, which like \glslink{uthrding}{User-Level \emph{Threading}}, blocks \glspl{thrd} rather than \glspl{proc} when doing \glsxtrshort{io} ope rations. |
---|
52 | This feature entails multiplexing the \glsxtrshort{io} operations of many \glspl{thrd} onto fewer \glspl{proc}. |
---|
53 | The multiplexing requires a single \gls{proc} to execute multiple \glsxtrshort{io} operations in parallel. |
---|
54 | This requirement cannot be done with operations that block \glspl{proc}, \ie \glspl{kthrd}, since the first operation would prevent starting new operations for its blocking duration. |
---|
55 | Executing \glsxtrshort{io} operations in parallel requires \emph{asynchronous} \glsxtrshort{io}, sometimes referred to as \emph{non-blocking}, since the \gls{kthrd} does not block. |
---|
56 | |
---|
57 | \section{Interoperating with C} |
---|
58 | While \glsxtrshort{io} operations are the classical example of operations that block \glspl{kthrd}, the non-blocking challenge extends to all blocking system-calls. The POSIX standard states~\cite[\S~2.9.1]{POSIX17}: |
---|
59 | \begin{quote} |
---|
60 | All functions defined by this volume of POSIX.1-2017 shall be thread-safe, except that the following functions need not be thread-safe. ... (list of 70+ excluded functions) |
---|
61 | \end{quote} |
---|
62 | Only UNIX @man@ pages identify whether or not a library function is thread safe, and hence, may block on a pthreads lock or system call; hence interoperability with UNIX library functions is a challenge for an M:N threading model. |
---|
63 | |
---|
64 | Languages like Go and Java, which have strict interoperability with C\cite{wiki:jni,go:cgo}, can control operations in C by ``sandboxing'' them, \eg a blocking function may be delegated to a \gls{kthrd}. Sandboxing may help towards guaranteeing that the kind of deadlock mentioned above does not occur. |
---|
65 | |
---|
66 | As mentioned in Section~\ref{intro}, \CFA is binary compatible with C and, as such, must support all C library functions. Furthermore, interoperability can happen at the function-call level, inline code, or C and \CFA translation units linked together. This fine-grained interoperability between C and \CFA has two consequences: |
---|
67 | \begin{enumerate} |
---|
68 | \item Precisely identifying blocking C calls is difficult. |
---|
69 | \item Introducing safe-point code (see Go~page~\pageref{GoSafePoint}) can have a significant impact on general performance. |
---|
70 | \end{enumerate} |
---|
71 | Because of these consequences, this work does not attempt to ``sandbox'' calls to C. |
---|
72 | Therefore, it is possible calls to an unknown library function can block a \gls{kthrd} leading to deadlocks in \CFA's M:N threading model, which would not occur in a traditional 1:1 threading model. |
---|
73 | Currently, all M:N thread systems interacting with UNIX without sandboxing suffer from this problem but manage to work very well in the majority of applications. |
---|
74 | Therefore, a complete solution to this problem is outside the scope of this thesis.\footnote{\CFA does provide a pthreads emulation, so any library function using embedded pthreads locks are redirected to \CFA user-level locks. This capability further reduces the chances of blocking a \gls{kthrd}.} |
---|