aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAria Shrimpton <me@aria.rip>2024-02-09 12:24:21 +0000
committerAria Shrimpton <me@aria.rip>2024-02-09 12:24:21 +0000
commiteecdde83e1bcccee7cdfa4af8191ec1aa727acb7 (patch)
tree6715a8b654550964ed7bac11ec4a2c3244c2e283
parente43fef5b73b74849e0f85df48a62b29be52534b3 (diff)
more writing
-rw-r--r--nix/tex-env.nix2
-rw-r--r--thesis/main.tex40
-rw-r--r--thesis/parts/design.tex76
3 files changed, 104 insertions, 14 deletions
diff --git a/nix/tex-env.nix b/nix/tex-env.nix
index 96d621d..13137fe 100644
--- a/nix/tex-env.nix
+++ b/nix/tex-env.nix
@@ -10,6 +10,8 @@ pkgs.texlive.combine {
helvetic
courier
biblatex
+ listings
+ zapfchan
latex-bin
latexmk
;
diff --git a/thesis/main.tex b/thesis/main.tex
index 21de962..d16e956 100644
--- a/thesis/main.tex
+++ b/thesis/main.tex
@@ -14,6 +14,32 @@
\newcommand{\code}{\texttt}
\newcommand{\todo}[1]{\colorbox{yellow}{TODO: #1} \newline}
+%% Code blocks
+\usepackage{listings}
+\usepackage{courier}
+\definecolor{codegreen}{rgb}{0,0.6,0}
+\definecolor{codegray}{rgb}{0.5,0.5,0.5}
+\definecolor{codepurple}{rgb}{0.58,0,0.82}
+\lstdefinestyle{mystyle}{
+ commentstyle=\color{codegreen},
+ keywordstyle=\color{magenta},
+ numberstyle=\tiny\color{codegray},
+ stringstyle=\color{codepurple},
+ basicstyle=\ttfamily\footnotesize,
+ breakatwhitespace=false,
+ breaklines=true,
+ captionpos=b,
+ keepspaces=true,
+ numbers=left,
+ numbersep=5pt,
+ showspaces=false,
+ showstringspaces=false,
+ showtabs=false,
+ tabsize=4
+}
+
+\lstset{style=mystyle}
+
\begin{document}
\begin{preliminary}
@@ -50,25 +76,25 @@ from the Informatics Research Ethics committee.
\end{preliminary}
-\chapter{Introduction}
+\chapter{Introduction} \label{chap:introduction}
\input{parts/introduction}
-\chapter{Background}
+\chapter{Background} \label{chap:background}
\input {parts/background}
-\chapter{Design}
+\chapter{Design} \label{chap:design}
\input{parts/design}
-\chapter{Implementation}
+\chapter{Implementation} \label{chap:implementation}
\input{parts/implementation}
-\chapter{Results}
+\chapter{Results} \label{chap:results}
\input{parts/results}
-\chapter{Analysis}
+\chapter{Analysis} \label{chap:analysis}
\input{parts/analysis}
-\chapter{Conclusion}
+\chapter{Conclusion} \label{chap:conclusion}
\input{parts/conclusion}
diff --git a/thesis/parts/design.tex b/thesis/parts/design.tex
index 0a93836..03e281d 100644
--- a/thesis/parts/design.tex
+++ b/thesis/parts/design.tex
@@ -1,18 +1,80 @@
-\todo{Introduction}
-\todo{Aims / expected input}
+This chapter outlines the design of our container selection system (Candelabra), and the justification behind these design decisions.
-\section{Overview of approach}
+We first describe our aims and priorities for the system, and illustrate its usage with an example.
+
+We then provide an overview of the container selection process, and each part in it.
+
+\section{Aims \& Usage}
+
+We aim to create a program for container selection that can select based on both functional and non-functional requirements.
+Flexibility is a high priority: It should be easy to add new container implementations, and to integrate our system into existing applications.
+Our system should also be able to scale to larger programs, and remain convenient for developers to use.
+
+We chose to implement our system as a Rust CLI, and limit it to selecting containers for Rust programs.
+We require the user to provide their own benchmarks, which should be representative of a typical application run.
+
+The user can specify their functional requirements by listing the required traits, and specifying properties that must always hold in a lisp-like language.
+This part of the process is handled by Primrose\parencite{qin_primrose_2023}, with only minor modifications to integrate with the rest of our system.
+
+For example, take the below code from our test case based on the sieve of Eratosthenes (\code{src/tests/prime\_sieve} in the source artifacts).
+Here we request two container types: \code{Sieve} and \code{Primes}.
+The first must implement the \code{Container} and \code{Stack} traits, and must satisfy the \code{lifo} property. This property is defined at the top as only being applicable to \code{Stack}s, and requires that for any \code{x}, pushing \code{x} then popping from the container returns \code{x}.
+
+The second container type, \code{Primes}, must only implement the \code{Container} trait, and must satisfy the \code{ascending} property.
+This property requires that at any point, for all consecutive \code{x, y} pairs in the container, \code{x $\leq$ y}.
+
+\begin{lstlisting}
+/*SPEC*
+property lifo<T> {
+ \c <: (Stack) -> (forall \x -> ((equal? (pop ((push c) x))) x))
+}
+
+property ascending<T> {
+ \c -> ((for-all-consecutive-pairs c) leq?)
+}
+
+
+type Sieve<S> = {c impl (Container, Stack) | (lifo c)}
+type Primes<S> = {c impl (Container) | (ascending c)}
+*ENDSPEC*/
+\end{lstlisting}
+
+Once we've specified our functional requirements and provided a benchmark (\code{src/tests/prime\_sieve/benches/main.rs}), we can simply run candelabra to select a container:
+
+\todo{Show selection process}
+
+Our tool integrates with Rust's packaging system (Cargo) to discover the information it needs about our project, then runs Primrose to find a list of implementations satsifying our functional requirements.
+
+Once it has this list, it estimates a 'cost' for each candidate, which is an upper bound on the total time taken for all container operations.
+At this point, it also checks if an 'adaptive' container would be better, by checking if one implementation is better performing at a lower n, and another at a higher n.
+
+Finally, it picks the container with the minimum cost, and creates a new Rust file where the chosen container type is exported.
+
+Our tool requires little user intervention, integrates well with existing workflows, and the time it takes scales linearly with the number of container types in a given project.
+
+\section{Selection Process}
+
+We now describe the design of our selection process in detail, and justify our choices.
+
+As mentioned above, the first stage of our process is to satisfy functional requirements, which we do using code from Primrose\parencite{qin_primrose_2023}.
+The exact internals are beyond the scope of this paper, but in brief this works by:
+\begin{itemize}
+\item Finding all implementations in the container library that implement all required traits
+\item Translate any specified properties to a Rosette expression
+\item For each implementation, model the behaviour of each operation in Rosette, and check that the required properties always hold
+\end{itemize}
+
+We use the code provided with the Primrose paper, with minor modifications elaborated on in \ref{chap:implementation}.
Once a list of functionally close enough implementations have been found, selection is done by:
\begin{itemize}
-\item Get a list of implementations that satisfy the program's functional requirements
-\item Estimating the cost of each operation, for each implementation, for any given n value
-\item Profiling the program to rank operation 'importance',
+\item For each operation of each implementation, build a cost model which can estimate the 'cost' of that operation at any given container size $n$
+\item Profile the program, tracking operation frequency and container sizes
\item Combining the two to create an estimate of the relative cost of each implementation
\end{itemize}
-\subsection{Cost Estimation}
+\subsection{Cost Models}
We use an approach similar to CollectionSwitch\parencite{costa_collectionswitch_2018}, which assumes that the main factor in how long an operation takes is the current size of the collection.