From 025622f7ba344b1e47dd47c92ed380902ecbddfd Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Sun, 6 Aug 2023 18:18:31 +0200 Subject: A6: WIP (code is done) --- a6/au_BentBisballeNyeng_A6.tex | 117 +++++++++++++++++++++++++++++++++-------- 1 file changed, 94 insertions(+), 23 deletions(-) (limited to 'a6/au_BentBisballeNyeng_A6.tex') diff --git a/a6/au_BentBisballeNyeng_A6.tex b/a6/au_BentBisballeNyeng_A6.tex index ad4cc0d..c6ad150 100644 --- a/a6/au_BentBisballeNyeng_A6.tex +++ b/a6/au_BentBisballeNyeng_A6.tex @@ -90,9 +90,11 @@ along with not supporting exceptions and run-time type information\cite{craig}. Working with the resulting small sub-set of the available components, -however, is not well suited for making contemporary C++ applications. +however, is not well suited for making contemporary C++ applications; +too many core components are missing so be able to really call it +contemporary. The ideal solution would be to find ways to be able to use all (or at -least most) features, but with a potential known set of restictions or +least more) features, but with a potential known set of restictions or limitations. \section{Method} @@ -100,28 +102,73 @@ In the following, 3 methods for managing memory allocations will be investigated, and their suitability for real-life applications be evaluated: \begin{itemize} -\item Using Custom Allocators for the STL components that supports it. -\item Overloading \texttt{new}/\texttt{delete} to use stack allocated - memory instead of the free-store for all allocation. \item Support from the compiler to fail compilation if an unintentional \texttt{new} or \texttt{delete} is being called, at least preventing accidental allocations. +\item Using Custom Allocators for the STL components that supports it. +\item Overloading \texttt{new}/\texttt{delete} to use stack allocated + memory instead of the free-store for all allocation. \end{itemize} -Each of the three will be evaluated with large lambda -captures, \texttt{std::vector} allocation and some simple co-routines. -The epxeriments are done on a linux PC using the gcc-11.2 compiler. +\noindent{}Each of the three will be evaluated with +\texttt{std::string}, \texttt{std::vector}, \texttt{std::function} and +co-routines.\\ +The experiments are done on a linux PC using the gcc-11.2 compiler. \section{Experiments} - ----------------------------------------- - - -No access to MMU, implicitly, prohibits calls to delete after -initialization phase. Otherwise this will lead to memory fragmentation -which again might lead to free-store depletion and ultimately -application failure. +This section describes the work done during the three experiments +along with any numerical or analytical results found. + +\subsection{Detecting Allocations}\label{detect} + +Searches on the Internet{\tm} has identified no ways of instructing +the compiler that ``no allocations allowed, fail if one is made''. +The reworked free-standing specification might make this possible in +the future, similarly to how exceptions and run-time type information +can be disabled with \texttt{-fno-exceptions} and \texttt{-fno-rtti}. +There exists a \texttt{-ffreestanding} argument, but this follows the +old (current) definition of free-standing and as such allows +dynamic allocation so it cannot be used. + +Some constructs have built-in optimizations that make them store their +data in local members, instead of on the free-store through a pointer, +until som limit is reached making it possible to use for +example \texttt{std::string}s or \texttt{std::function}s as long as +they don't require more than $N$ bytes, where $N$ is a compiler +dependent. + +To detect if a free-store allocation is done a simple overload +of \texttt{new} and \texttt{delete} can be done, which simply throws +an exeption if called. +This will lead to a run-time error and not a compile-time one as would +have been the ideal solution, but at least it can assists in finding +the $N$ for a specific compiler. + +This experiment can be found in the \texttt{noalloc.cc} file. The +following table shows the impirically deduced sizes of $N$ wherever +SSO/SBO is available along with comments about the general component +behaviour.\\ + +\noindent\begin{tabular}{| l | c | l |} +\hline +Component & $N$ & Comments \\ +\hline +\texttt{std::string} & $16$ & Exception propagates to caller. \\ +\texttt{std::vector} & N/A & No SBO, exception propagates to caller. \\ +\texttt{std::function} & $16$ & Exception doesn't seem to propagate to +caller (possible gcc bug). \\ +co-routine & N/A & No SBO, exception propagates to caller. \\ +\hline +\end{tabular} + +\subsection{Custom Allocator} + +\begin{verbatim} +Write allocator that uses stack-buffer and fails when depleted and try +it out (monotonic allocations) +List the components that supports it +\end{verbatim} Writing a custom allocator is only a solution to a sub-set of the allocations in an application, for example if all allocations are @@ -132,6 +179,17 @@ But for most applications (or at least most parts on an application) this is not the case, and therefore others means need to be taken into use. +std::string works, using basic_string, but is a bit clumsy + +std::vector works beautifully + +std::function as of c++17 can no longer be used with allocators + +Adding new operator to promise_type: +https://en.cppreference.com/w/cpp/language/coroutines#Dynamic_allocation + + +\subsection{Use \texttt{new} with Stack Buffer} The most common way of addressing this, is simply to only use stack allocation, or store all objects in as static globals. But in certain areas of the C++ language dynamic allocation might @@ -141,13 +199,26 @@ one example, but even more devious is the capture clause of a lambda, which might allocate extra memory, if more than $N$ members are captured, where $N$ is compiler dependent. -No way of telling the compiler that ``no allocations allowed, fail if -one is made'' exists, but one could wish for such a mechanism in the -wake of the ``free-standing C++'' subset work. -One thing is to prohibit use of language constructs that are -guaranteed to allocate, but quite another is to allow using constructs -in ways that doesn't make them allocate. -This, I think, is not part of the ``free-standing C++'' work. +Expanding on the overloaded \texttt{new} and \texttt{delete} from +section \ref{detect} a mechanism for using a stack-buffer for exactly +one call to \texttt{new} is made, looking something like this: +\begin{lstlisting}[language=C++] +void foo() +\end{lstlisting} + +Object owning the buffer and registering itself with the next call to +new. + +Scope of the stack object must be the same as the object using +it. Compiler does not help with that so this must be done by +convention. + +\section{Summing Up} + +Can be done, but is by no means elegant and can in some solution be +downright dangerous. +But if this is the price to pay to be able to use co-routines in +microcontrollers perhaps it is worth it none the less. \printbibliography -- cgit v1.2.3