From e214322fc3c1ab2e614938c128af74a48206fdd3 Mon Sep 17 00:00:00 2001 From: Lenni Hein Date: Tue, 25 Feb 2025 16:25:01 +0100 Subject: [PATCH] NOPFunction rename, added ualarm link, added rule of thumb for interval --- README.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ac93632..d6e4084 100644 --- a/README.md +++ b/README.md @@ -71,10 +71,10 @@ Muster: `./src/cache_test.c` **Jetzt können wir den Cache doch mal als Medium verwenden. Der Sender kann `0` und `1` über den (ausbleibenden) Speicherzugriff kodieren. Der Empfänger interpretiert dann, je nach Zugriffszeit.** -`sharedlib.c` sieht so aus: +Um zu kommunizieren, müssen sich Sender und Empfänger auf eine physische Adresse einigen, die für Flush+Reload verwendet wird. Dafür nehmen wir am besten eine shared library, die ist schon als `sharedlib.c` bereitgestellt: ```C -void function(void) +void myStupidNOPFunction(void) { asm volatile ( "nop\n\t" "nop\n\t" @@ -90,11 +90,13 @@ void function(void) ... ``` -Die Adresse von `function` kann also zum Flushen und Reloaded verwendet werden. +Die Adresse von `myStupidNOPFunction` kann also zum Flushen und Reloaded verwendet werden. Da immer eine gesamte Cacheline geladen wird, sollte sich nichts anderes in dem selben 64Byte Block befinden. Die Funktionen `padding_before` und `padding_after` sind beide 64 Byte groß, also eine Cacheline. Damit kann dann auch gar nichts mehr schief gehen :) +*`MyStupidNOPFunction` ist übrigens genau $256*64\ Byte$ groß. Das wird vielleicht ja noch praktisch ;)* + `sharedlib.c` kann man so kompilieren und linken: ```bash @@ -107,13 +109,13 @@ gcc -O0 empfaenger.c lib.c -L. -lsharedlib -o empfaenger export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ``` -*(oder einfach `cmake` verwenden)* +*(oder einfach `cmake` verwenden :P)* -dann kann man `function` verwenden: +dann kann man `function` benutzen: ```C # in e.g. sender.c -maccess((void *) function) +maccess((void *) myStupidNOPFunction) ... ``` ##### Tips @@ -121,13 +123,13 @@ maccess((void *) function) - `taskset` zum kann pinnen der Programme auf einen bestimmten CPU-Kern benutzt werden. Das kann helfen. - Verwendet man blockierenden Sleep um zu Takten, z.B. `clock_nanosleep`, dann sollte man unbedingt darauf achten nicht eine Periodendauer zu schlafen, sondern nur bis zum nächsten Zeitabschnitt. Einfacher geht es mit nicht-blockierendem Sleep, z.B. `ualarm`. -So kann man `ualarm` nutzen, um alle x µs einen `SIGARLM` auszulösen: +So kann man `ualarm` [Linux Manual](https://man7.org/linux/man-pages/man3/ualarm.3.html) nutzen, um alle x µs einen `SIGARLM` auszulösen: ```C int main(void){ ... signal(SIGALRM, signal_handler); - ualarm(sample_interval, sample_interval); + ualarm(0, interval); ``` Bei jedem `SIGALRM` Signal wird `signal_handler` ausgeführt: @@ -142,6 +144,7 @@ void signal_handler(int signo) { - Der Zeitabstand von Flush zu Reload sollte MAXIMIERT werden! Dies ist das Zeitfenster, in welchem der Sender die Adresse(n) zurück in den Cache laden kann. - Der Sender kann nicht nur einmal Laden. Das kann man auch mehrfach in einem Zeitfenster machen, um sicher zu gehen, dass die Cacheline auch geladen ist, wenn der Empfänger ausließt. +- **Richtwert**: 1000µs pro Zyklus haben sich als ganz gut erwiesen (→ 1kHz). Ein zu kurzes Zeitfenster lässt nicht genug Zeit um alle Instruktionen abzuarbeiten, ein zu langes führt zu mehr Noise, falls die Cacheline zwischenzeitlich aus dem Cache verdrängt wird. ### Block 3: Einen String über den Cache als Medium senden