Files
lab-rv32i-freertos-schedule…/doc/main.tex
T

285 lines
10 KiB
TeX

\documentclass[10pt]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[polish]{babel}
\usepackage[a4paper,margin=1.55cm]{geometry}
\usepackage{array,tabularx,booktabs}
\usepackage{amsmath,amssymb}
\usepackage{xcolor,listings}
\usepackage{hyperref,fancyhdr,lastpage,enumitem}
\definecolor{accent}{HTML}{16324A}
\definecolor{accentlight}{HTML}{EEF3F7}
\definecolor{rulegray}{HTML}{D7DEE5}
\hypersetup{colorlinks=true,linkcolor=accent,urlcolor=blue}
\IfFileExists{build-meta.tex}{\input{build-meta.tex}}{\newcommand{\BuildCommit}{local}}
\newcommand{\PublisherDomain}{mpabi}
\newcommand{\CardArea}{inf}
\newcommand{\CardSeries}{freertos-cpp}
\newcommand{\CardNumber}{04}
\newcommand{\CardCount}{16}
\newcommand{\CardSlug}{scheduler-states}
\newcommand{\CardVersion}{v00.01}
\newcommand{\DocumentUUID}{853a7dd7-b00b-4f4a-96e8-c160fc5bb04a}
\newcommand{\blank}[1]{\rule{#1}{.2pt}}
\lstset{
language=C++,basicstyle=\ttfamily\scriptsize,columns=fullflexible,
keepspaces=true,frame=single,breaklines=true,showstringspaces=false,
numbers=none,backgroundcolor=\color{accentlight},rulecolor=\color{rulegray}
}
\pagestyle{fancy}
\fancyhf{}
\lhead{\textbf{K04 · FreeRTOS C++ · scheduler}}
\rhead{\small L03 · stany, priorytety, ticki}
\lfoot{\scriptsize commit \BuildCommit}
\cfoot{\scriptsize \thepage/\pageref{LastPage}}
\rfoot{\scriptsize V11.3.0 / \CardVersion}
\setlength{\headheight}{14pt}
\setlength{\footskip}{19pt}
\setlist[itemize]{nosep,leftmargin=1.45em}
\setlist[enumerate]{nosep,leftmargin=1.65em}
\begin{document}
\sloppy
\begin{center}
{\LARGE\bfseries Scheduler: stany, priorytety i typowane ticki}\par
\vspace{.25em}
{\large przewidź przełączenie, potem udowodnij je śladem}\par
\end{center}
\noindent\begin{tabularx}{\textwidth}{@{}p{1.65cm}Xp{1.55cm}X@{}}
\toprule
Karta & K04 / \CardCount & Czas & 30 minut \\
Platforma & Hazard3 / RV32I & Język & freestanding C++17 \\
Scheduler & preemption + time slicing & Kernel & V11.3.0, bez zmian \\
Wersja & \CardVersion & UUID karty & \texttt{853a7dd7-...} \\
\bottomrule
\end{tabularx}
\section*{Cel i jedna sekwencja dowodowa}
Dwa zadania A i B mają priorytet 2. Najpierw scheduler dzieli CPU między
równych. Potem A blokuje się na 3 ticki. Na końcu A podnosi priorytet B do 3.
Nie zgadujemy kolejności --- zapisujemy stany, ticki oraz znaczniki wykonania.
\begin{center}
\texttt{READY} $\rightarrow$ \texttt{RUNNING} $\rightarrow$
\texttt{BLOCKED} $\rightarrow$ \texttt{READY} $\rightarrow$
\texttt{RUNNING} $\rightarrow$ \texttt{DELETED}
\end{center}
\noindent\fcolorbox{accent}{accentlight}{%
\begin{minipage}{.94\textwidth}
\textbf{Dwa warunki K04.} Zadanie o najwyższym priorytecie wygrywa tylko wtedy,
gdy jest gotowe. Tick jest jednostką schedulera, nie ukrytą nazwą milisekundy.
\end{minipage}}
\section*{Plan 30 minut}
\begin{tabularx}{\textwidth}{@{}p{1.35cm}p{3.0cm}X@{}}
\toprule
Czas & Tryb & Dowód ucznia \\
\midrule
0--4 & predykcja & tabela stanów i bieżącego zadania \\
4--8 & czas typowany & \texttt{Ticks} kontra \texttt{TickPoint} \\
8--13 & time slicing & A--B--A albo B--A--B przy priorytecie 2 \\
13--19 & blokada & A=BLOCKED, B=RUNNING, różnica ticków 3 \\
19--25 & priorytet & BEFORE--HIGH--AFTER ma wartości 1--2--3 \\
25--30 & wyjście & delay względny/okresowy i granica \texttt{TaskRef} \\
\bottomrule
\end{tabularx}
\section*{Najpierw przewidź}
Który identyfikator pojawi się pierwszy: A czy B? \blank{2cm}\quad
Czy test powinien wymagać właśnie tej odpowiedzi? \blank{5cm}
\newpage
\section{Stany są warunkiem kwalifikacji do CPU}
\begin{tabularx}{\textwidth}{@{}p{2.5cm}p{4.0cm}X@{}}
\toprule
Stan & Czy może teraz dostać CPU? & Typowa przyczyna \\
\midrule
\texttt{eRunning} & tak, jedno zadanie na rdzeń & scheduler właśnie je wybrał \\
\texttt{eReady} & tak, czeka na wybór & równy/niższy priorytet lub wywłaszczenie \\
\texttt{eBlocked} & nie & delay albo oczekiwanie na zdarzenie \\
\texttt{eSuspended} & nie & jawne zawieszenie, nie upływ czasu \\
\texttt{eDeleted} & nie & stan terminalny w śladzie tej karty \\
\bottomrule
\end{tabularx}
\subsection*{Pułapka „najwyższy zawsze działa”}
Jeżeli A ma priorytet 4, ale jest \texttt{BLOCKED}, a B ma priorytet 2 i jest
\texttt{READY}, scheduler wybierze \blank{2cm}, ponieważ
\blank{10cm}.
\subsection*{Równe priorytety i time slicing}
Przy \texttt{configUSE\_PREEMPTION=1} oraz
\texttt{configUSE\_TIME\_SLICING=1} tick może przenieść wykonanie do innego
gotowego zadania o tym samym priorytecie. Zalicza relacja:
\begin{center}
\texttt{first == third \&\& first != second}
\end{center}
Wpisz dwa dopuszczalne ślady: \blank{3cm}\quad lub \quad\blank{3cm}.
\section{Czas: wartość ma znaczenie dopiero z jednostką}
\begin{lstlisting}
freertos::Ticks duration{3};
const auto start = freertos::TickPoint::now();
vTaskDelay(duration.count());
const auto elapsed = freertos::TickPoint::now() - start;
\end{lstlisting}
\texttt{Ticks} jest czasem trwania. \texttt{TickPoint} jest punktem na
zawijającym się liczniku. Odejmowanie dwóch punktów daje czas trwania także
przy przejściu licznika przez maksimum typu bez znaku.
\noindent\begin{tabularx}{\textwidth}{@{}p{4.4cm}X@{}}
\toprule
API & Znaczenie \\
\midrule
\texttt{vTaskDelay(3)} & blokada względna: trzy ticki od chwili wywołania \\
\texttt{xTaskDelayUntil} (\texttt{\&next,3}) & kolejny termin względem zapamiętanej osi okresu \\
\bottomrule
\end{tabularx}
W laboratorium tick rate wynosi 1000 Hz, ale poprawne zdanie brzmi
„A było zablokowane przez \blank{1.5cm} ticki”. Przeliczenie na ms:
\blank{3cm}. Co zmieni się przy 250 Hz? \blank{5cm}
\newpage
\section{Tabela predykcji i obserwacji}
Najpierw wypełnij kolumnę „predykcja”. Dopiero potem uruchom program i wpisz
wartości z \texttt{g\_snapshots}. Priorytet zapisuj obok stanu, np.
\texttt{READY/p2}.
\renewcommand{\arraystretch}{1.32}
\noindent\begin{tabularx}{\textwidth}{@{}p{.7cm}p{2.3cm}p{3.2cm}p{3.2cm}p{1.8cm}X@{}}
\toprule
Nr & Zdarzenie & A: pred./odczyt & B: pred./odczyt & Current & Dlaczego? \\
\midrule
1 & startup & \blank{2.7cm} & \blank{2.7cm} & \blank{1.3cm} & \blank{2.05cm} \\
2 & przed delay & \blank{2.7cm} & \blank{2.7cm} & \blank{1.3cm} & \blank{2.05cm} \\
3 & A czeka & \blank{2.7cm} & \blank{2.7cm} & \blank{1.3cm} & \blank{2.05cm} \\
4 & A obudzone & \blank{2.7cm} & \blank{2.7cm} & \blank{1.3cm} & \blank{2.05cm} \\
5 & BEFORE & \blank{2.7cm} & \blank{2.7cm} & \blank{1.3cm} & \blank{2.05cm} \\
6 & HIGH & \blank{2.7cm} & \blank{2.7cm} & \blank{1.3cm} & \blank{2.05cm} \\
7 & AFTER & \blank{2.7cm} & \blank{2.7cm} & \blank{1.3cm} & \blank{2.05cm} \\
8 & verifier & \blank{2.7cm} & \blank{2.7cm} & \blank{1.3cm} & \blank{2.05cm} \\
\bottomrule
\end{tabularx}
\renewcommand{\arraystretch}{1}
\section*{Trzy znaczniki jako dowód wywłaszczenia}
Kod A zapisuje \texttt{BEFORE=1}, podnosi B do priorytetu 3, a po powrocie z
API zapisuje \texttt{AFTER=3}. Kod B zapisuje \texttt{HIGH=2} natychmiast po
uzyskaniu CPU.
\begin{lstlisting}
append_priority_order(BEFORE); // A: 1
peer.set_priority(3); // B staje sie wyzej priorytetowe
append_priority_order(AFTER); // A: 3, dopiero po powrocie
// B, zanim wywolanie w A zdazy wrocic:
append_priority_order(HIGH); // B: 2
\end{lstlisting}
Gdyby nie doszło do natychmiastowego wywłaszczenia, możliwa kolejność
wynosiłaby \blank{4cm}. Odczyt oczekiwany: \blank{4cm}.
\section*{Osiem rekordów, ale żadnego użycia wiszącego uchwytu}
Po usunięciu zadania jego TCB może zostać odzyskany przez idle task.
\texttt{TaskRef} nie posiada TCB i nie wydłuża jego życia. Dlatego terminalny
rekord zapisuje znany stan \texttt{DELETED}, ale nie wywołuje
\texttt{eTaskGetState()} przez stary uchwyt.
\newpage
\section{Uruchomienie i kontrakt dowodu}
\begin{lstlisting}[language=bash]
make check
riscv64-unknown-elf-gdb build/task01_scheduler_states/prog.elf
\end{lstlisting}
\begin{lstlisting}
p g_alternating_tasks
p g_alternating_ticks
p g_snapshots
p g_delay_start_tick
p g_delay_observed_tick
p g_delay_end_tick
p g_delay_elapsed
p g_priority_order
p g_scheduler_states_pass
\end{lstlisting}
\noindent\begin{tabularx}{\textwidth}{@{}p{5.2cm}X@{}}
\toprule
Warunek & Odczyt ucznia \\
\midrule
identyfikatory mają postać X,Y,X, $X\ne Y$ & \blank{6cm} \\
w zdarzeniu 3: A=BLOCKED, B=RUNNING & \blank{6cm} \\
\texttt{delay\_end - delay\_start == 3} & \blank{6cm} \\
obserwacja blokady jest przed końcem delay & \blank{6cm} \\
w zdarzeniu 6 B ma priorytet 3 & \blank{6cm} \\
\texttt{priority\_order == \{1,2,3\}} & \blank{6cm} \\
osiem snapshotów i \texttt{pass == 1} & \blank{6cm} \\
\bottomrule
\end{tabularx}
\section*{Minimalne wrappery C++}
\begin{lstlisting}
class TaskRef final {
public:
explicit TaskRef(TaskHandle_t h) : handle_{h} {}
eTaskState state() const { return eTaskGetState(handle_); }
UBaseType_t priority() const { return uxTaskPriorityGet(handle_); }
void set_priority(UBaseType_t p) const {
vTaskPrioritySet(handle_, p);
}
private:
TaskHandle_t handle_; // non-owning
};
\end{lstlisting}
Nie ma tu wirtualności, alokacji ani automatycznego delete. Rozmiar
\texttt{TaskRef} jest równy rozmiarowi uchwytu. Pełna polityka własności taska
pojawi się dopiero w K07--K09.
\section*{Wyjście — cztery krótkie odpowiedzi}
\begin{enumerate}
\item Dlaczego zadanie o priorytecie 4 może nie działać, gdy działa p2?\\[1em]
\item Dlaczego test nie wymaga, by A było pierwsze w śladzie time slicing?\\[1em]
\item Kiedy \texttt{vTaskDelay(3)} oznacza dokładnie 3 ms?\\[1em]
\item Co dokładnie dowodzi kolejność \texttt{1,2,3}?\\[1em]
\end{enumerate}
\section*{Zaliczenie}
\begin{itemize}
\item $\square$ rozróżniam READY, RUNNING, BLOCKED i DELETED;
\item $\square$ pokazuję X--Y--X, blokadę na 3 ticki i porządek 1--2--3;
\item $\square$ odróżniam delay względny od okresowego terminu;
\item $\square$ nie utożsamiam ticka z milisekundą bez konfiguracji;
\item $\square$ wiem, że \texttt{TaskRef} nie jest właścicielem TCB.
\end{itemize}
\vfill
\noindent\textbf{Następna karta K05:} most C++ do heapu, porównanie modeli
FreeRTOS oraz tylko-odczytowy \texttt{HeapStats}.
\end{document}