From c05df87c02dddc52bb9fb5af17631a797292959c Mon Sep 17 00:00:00 2001 From: mpabi Date: Sat, 2 May 2026 01:05:59 +0200 Subject: [PATCH] Add line range algorithm notes --- doc/main.tex | 127 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 116 insertions(+), 11 deletions(-) diff --git a/doc/main.tex b/doc/main.tex index df43bfe..cfbf93d 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -32,7 +32,7 @@ \renewcommand{\lstlistlistingname}{Lista listingów} \lstset{basicstyle=\ttfamily\small,columns=fullflexible,keepspaces=true,frame=single,breaklines=true,showstringspaces=false,numbers=left,numberstyle=\tiny\color{accent},stepnumber=1,numbersep=8pt,backgroundcolor=\color{accentlight},rulecolor=\color{rulegray},captionpos=b} -\newcommand{\TaskSection}[4]{\section{Task #1: #3}#4\lstinputlisting[language=C,caption={Task #1: #3},label={lst:task#1-c}]{../src/tasks/#2.c}\lstinputlisting[basicstyle=\ttfamily\scriptsize,caption={ASM dla task #1},label={lst:task#1-asm}]{../build/#2/#2.s}} +\newcommand{\TaskSection}[5]{\section{Task #1: #3}\subsection*{Algorytm i zakresy linii}#4\lstinputlisting[language=C,caption={Task #1: #3},label={lst:task#1-c}]{../src/tasks/#2.c}\subsection*{Co sprawdzić w ASM}#5\lstinputlisting[basicstyle=\ttfamily\scriptsize,caption={ASM dla task #1},label={lst:task#1-asm}]{../build/#2/#2.s}} \pagestyle{fancy} \fancyhf{} @@ -94,6 +94,9 @@ kopią pliku upstream FreeRTOS. Na RV32I wyniki są zapisywane w globalnych zmiennych \texttt{volatile}; \texttt{printf} jest dostępny wyłącznie w wariancie hostowym przez flagę \texttt{-DHOST\_PRINTF=1}. +Listingi C i ASM mają numerowane linie. Opisy w sekcjach tasków odnoszą się +do numerów widocznych po lewej stronie listingów C. + \lstinputlisting[language=C,caption={Wspólny nagłówek dla karty \texttt{heap\_4}},label={lst:common-h}]{../src/tasks/heap4_common.h} \subsection{\texttt{static inline} w nagłówku} @@ -130,16 +133,118 @@ Task & Temat \\ \hline \end{tabularx} -\TaskSection{01}{task01_heap_map}{mapa \texttt{heap\_4}}{Listing~\ref{lst:task01-c} pokazuje nagłówek bloku, wyrównanie rozmiaru i bit oznaczający blok zajęty.} -\TaskSection{02}{task02_free_list}{lista wolnych bloków}{Listing~\ref{lst:task02-c} przechodzi po liście wolnych bloków i liczy sumę dostępnej pamięci.} -\TaskSection{03}{task03_heap_init}{inicjalizacja sterty}{Listing~\ref{lst:task03-c} tworzy pierwszy wolny blok oraz końcowy znacznik listy.} -\TaskSection{04}{task04_alignment}{wyrównanie}{Listing~\ref{lst:task04-c} pokazuje, dlaczego alokator zaokrągla rozmiary i adres początku sterty.} -\TaskSection{05}{task05_malloc_first_fit}{\texttt{first fit}}{Listing~\ref{lst:task05-c} wybiera pierwszy wolny blok wystarczająco duży dla żądania.} -\TaskSection{06}{task06_split_block}{podział bloku}{Listing~\ref{lst:task06-c} zostawia resztę dużego bloku na liście wolnych bloków.} -\TaskSection{07}{task07_free_insert}{\texttt{free} i wstawianie}{Listing~\ref{lst:task07-c} zwraca blok do listy tak, aby lista pozostała posortowana po adresach.} -\TaskSection{08}{task08_coalescing}{scalanie bloków}{Listing~\ref{lst:task08-c} scala blok z lewym i prawym sąsiadem, gdy adresy są ciągłe.} -\TaskSection{09}{task09_config_macros}{makra konfiguracyjne}{Listing~\ref{lst:task09-c} pokazuje małe odpowiedniki makr konfiguracyjnych FreeRTOS-a.} -\TaskSection{10}{task10_heap4_demo}{mini \texttt{heap\_4}}{Listing~\ref{lst:task10-c} łączy inicjalizację, alokację, zwalnianie i scalanie w jeden model.} +\TaskSection{01}{task01_heap_map}{mapa \texttt{heap\_4}}{ +\begin{itemize}[leftmargin=1.6em] + \item Linie 3--7 definiują zmienne \texttt{volatile}, czyli obserwowalne wyniki taska. + \item Linie 11--16 tworzą pojedynczy blok i zapisują w jego polu \texttt{size} rozmiar z bitem alokacji. + \item Linie 18--22 rozbijają nagłówek bloku na wartości pomocnicze: rozmiar nagłówka, rozmiar wyrównany, bit zajętości, rozmiar całego bloku i część użytkownika. + \item Linie 24--27 wypisują te same wartości tylko w wariancie hostowym; na RV32I makro \texttt{TRACE\_PRINTF} znika. + \item Wynik sprawdzaj w \texttt{g\_header\_size}, \texttt{g\_allocated\_bit\_set}, \texttt{g\_total\_block\_bytes} i \texttt{g\_user\_bytes}. +\end{itemize} +}{ +W ASM szukaj operacji ustawiania najwyższego bitu rozmiaru oraz zapisów do symboli globalnych \texttt{g\_*}. Dostęp do pól \texttt{block.next} i \texttt{block.size} powinien być zwykłym zapisem pod adres bazowy stosu z przesunięciem. +} +\TaskSection{02}{task02_free_list}{lista wolnych bloków}{ +\begin{itemize}[leftmargin=1.6em] + \item Linie 7--16 implementują sumowanie rozmiarów bloków na liście. + \item Linie 18--28 przechodzą po tej samej liście i zapamiętują największy blok. + \item Linie 30--39 liczą liczbę węzłów listy. + \item Linie 43--55 budują ręcznie listę \texttt{start -> a -> b -> c -> NULL}. + \item Linie 57--59 uruchamiają trzy funkcje pomiarowe i zapisują wyniki w \texttt{volatile}. +\end{itemize} +}{ +W ASM zwróć uwagę na pętle po wskaźniku \texttt{block = block->next}. To jest podstawowy idiom przechodzenia po liście jednokierunkowej, widoczny jako ładowanie pola \texttt{next} i skok warunkowy. +} +\TaskSection{03}{task03_heap_init}{inicjalizacja sterty}{ +\begin{itemize}[leftmargin=1.6em] + \item Linie 3--7 definiują bufor sterty, węzeł startowy listy i wskaźnik końcowego wartownika. + \item Linie 20--23 wyrównują początek sterty i obcinają dostępną długość do wielokrotności wyrównania. + \item Linie 25--28 ustawiają adres i pola końcowego wartownika. + \item Linie 30--34 tworzą pierwszy wolny blok i podpinają go za \texttt{start}. + \item Linie 39--43 wykonują inicjalizację i zapisują trzy wartości kontrolne. +\end{itemize} +}{ +W ASM szukaj maskowania dolnych bitów adresu i rozmiaru. Warto też porównać zapisy do \texttt{first->next}, \texttt{first->size}, \texttt{start.next} i \texttt{start.size}; każdy z nich jest dostępem do pola struktury. +} +\TaskSection{04}{task04_alignment}{wyrównanie}{ +\begin{itemize}[leftmargin=1.6em] + \item Linie 3--6 definiują wyniki pokazujące wpływ wyrównania. + \item Linie 14--16 liczą rzeczywiste rozmiary bloków dla żądań 1, 9 i 17 bajtów, po dodaniu nagłówka. + \item Linie 18--20 biorą celowo nie-wyrównany adres \texttt{\&bytes[1]} i wyliczają przesunięcie do kolejnej granicy wyrównania. + \item Linie 22--24 są hostowym wypisem kontrolnym. +\end{itemize} +}{ +W ASM znajdź operacje \texttt{and} używane do testowania dolnych bitów oraz dodawanie brakującej liczby bajtów do wyrównania. To jest ten sam mechanizm, którego używa alokator dla rozmiaru bloku i początku sterty. +} +\TaskSection{05}{task05_malloc_first_fit}{\texttt{first fit}}{ +\begin{itemize}[leftmargin=1.6em] + \item Linie 13--30 inicjalizują stertę z jednym wolnym blokiem oraz wartownikiem końca. + \item Linie 38--40 zamieniają żądanie użytkownika na całkowity rozmiar bloku i ustawiają początek przeszukiwania listy. + \item Linie 42--51 realizują algorytm \texttt{first fit}: idą po liście do pierwszego bloku o wystarczającym rozmiarze. + \item Linie 44--47 zdejmują znaleziony blok z listy wolnych, oznaczają go jako zajęty i zwracają adres danych użytkownika. + \item Linie 61--67 wykonują alokację i zapisują, czy się udała, jaki rozmiar dostał blok i ile wolnego miejsca zostało na liście. +\end{itemize} +}{ +W ASM obserwuj porównanie \texttt{block->size >= total}, zmianę \texttt{previous->next} oraz dodanie \texttt{sizeof(HeapBlock)} do adresu bloku przed zwróceniem wskaźnika użytkownika. +} +\TaskSection{06}{task06_split_block}{podział bloku}{ +\begin{itemize}[leftmargin=1.6em] + \item Linie 3--12 definiują rozmiar sterty, minimalny sensowny rozmiar reszty i zmienne wynikowe. + \item Linie 14--28 tworzą jeden duży wolny blok. + \item Linie 38--44 szukają bloku pasującego do żądania i zapamiętują jego pierwotny rozmiar. + \item Linie 45--50 wykonują podział: nowy blok \texttt{remainder} zaczyna się pod adresem \texttt{block + total}. + \item Linie 51--56 obsługują przypadek bez podziału, oznaczają blok jako zajęty i zwracają adres użytkownika. + \item Linie 65--73 liczą pozostałe wolne bloki, a linie 81--87 zapisują wynik demonstracji. +\end{itemize} +}{ +W ASM szukaj arytmetyki adresów dla \texttt{remainder}: adres bloku plus \texttt{total}. To najważniejszy fragment pokazujący, że dzielenie bloku jest tylko przesunięciem wskaźnika i zapisaniem nowego nagłówka. +} +\TaskSection{07}{task07_free_insert}{\texttt{free} i wstawianie}{ +\begin{itemize}[leftmargin=1.6em] + \item Linie 11--20 wstawiają blok do listy w miejscu wynikającym z porządku adresów. + \item Linie 22--32 modelują \texttt{free}: z adresu użytkownika wracają do nagłówka bloku, czyszczą bit alokacji i wywołują wstawianie. + \item Linie 34--54 zawierają funkcje kontrolne liczące węzły oraz łączny rozmiar wolnej pamięci. + \item Linie 63--76 budują układ \texttt{a}, \texttt{b}, \texttt{c}, gdzie \texttt{b} jest zajętym blokiem między dwoma wolnymi. + \item Linie 78--83 zwalniają \texttt{b} i sprawdzają, czy lista ma kolejność \texttt{a -> b -> c -> end}. +\end{itemize} +}{ +W ASM zwróć uwagę na porównywanie adresów w pętli z linii 15. To porządkowanie po adresie jest przygotowaniem do scalania bloków w następnym tasku. +} +\TaskSection{08}{task08_coalescing}{scalanie bloków}{ +\begin{itemize}[leftmargin=1.6em] + \item Linie 11--17 znajdują miejsce w liście, w którym powinien znaleźć się zwracany blok. + \item Linie 19--25 sprawdzają sąsiedztwo z prawym blokiem; jeśli adres końca zwracanego bloku jest adresem następnego, rozmiary są łączone. + \item Linie 27--32 sprawdzają sąsiedztwo z lewym blokiem i ewentualnie dołączają scalony wynik do lewej strony. + \item Linie 35--44 liczą końcową liczbę wolnych bloków. + \item Linie 52--65 budują trzy sąsiednie bloki w pamięci, a linia 67 uruchamia scalanie środkowego bloku. + \item Linie 69--71 zapisują, czy po scaleniu został jeden blok i jaki ma rozmiar. +\end{itemize} +}{ +W ASM szukaj testu \texttt{(uint8\_t *)block + block->size == iterator->next}. To jest sedno scalania: alokator nie porównuje indeksów, tylko rzeczywiste adresy końca i początku bloków. +} +\TaskSection{09}{task09_config_macros}{makra konfiguracyjne}{ +\begin{itemize}[leftmargin=1.6em] + \item Linie 3--9 definiują wartości domyślne tylko wtedy, gdy nie zostały podane z zewnątrz przez kompilator. + \item Linia 11 tworzy wartość pochodną od konfiguracji i wyrównania. + \item Linie 20--22 zapisują wartości makr do zmiennych \texttt{volatile}, żeby były widoczne w debugerze. + \item Linie 24--28 pokazują kompilację warunkową: host ustawia \texttt{g\_trace\_is\_host\_only} na 1, RV32I na 0. + \item Linie 30--32 wypisują wynik tylko w wariancie hostowym. +\end{itemize} +}{ +W ASM dla RV32I nie powinno być wywołania \texttt{printf}. Sprawdź też, że makra konfiguracyjne nie są zmiennymi w pamięci, tylko stałymi wstawionymi do kodu przez preprocesor. +} +\TaskSection{10}{task10_heap4_demo}{mini \texttt{heap\_4}}{ +\begin{itemize}[leftmargin=1.6em] + \item Linie 18--38 to funkcje diagnostyczne przechodzące po liście wolnych bloków. + \item Linie 40--62 wstawiają blok i scalają go z prawym oraz lewym sąsiadem. + \item Linie 64--88 inicjalizują stertę: wyrównują początek, ustawiają wartownika, pierwszy wolny blok i liczniki wolnej pamięci. + \item Linie 90--131 implementują alokację: sprawdzają rozmiar żądania, szukają bloku, dzielą go lub zdejmują w całości z listy, oznaczają jako zajęty i aktualizują minimum wolnej pamięci. + \item Linie 133--149 implementują zwalnianie: wracają z adresu użytkownika do nagłówka, sprawdzają bit alokacji, przywracają rozmiar i scalają blok. + \item Linie 157--169 wykonują sekwencję \texttt{malloc/free} i zapisują stan końcowy alokatora. +\end{itemize} +}{ +W ASM porównaj trzy fragmenty: inicjalizację listy, pętlę szukania wolnego bloku oraz wywołanie \texttt{insert\_block\_merge}. To pokazuje, że pełny model składa się z prostych operacji wskaźnikowych poznanych w poprzednich taskach. +} \section{Polecenia} \begin{enumerate}[leftmargin=1.6em]