.
This commit is contained in:
parent
5b881c5cde
commit
47c10976f0
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
### Primitive
|
### Primitive
|
||||||
|
|
||||||
|
in `./src/lib.c` sind folgende Primitive:
|
||||||
|
|
||||||
`time_maccess` misst wie lange der Zugriff auf die Speicheradresse `addr` dauert.
|
`time_maccess` misst wie lange der Zugriff auf die Speicheradresse `addr` dauert.
|
||||||
```C
|
```C
|
||||||
size_t time_maccess(void (* addr)(void))
|
size_t time_maccess(void (* addr)(void))
|
||||||
@ -53,16 +55,36 @@ void flush(void* addr)
|
|||||||
```bash
|
```bash
|
||||||
gcc -O0 cache_test.c primitive.c -o cache_test
|
gcc -O0 cache_test.c primitive.c -o cache_test
|
||||||
```
|
```
|
||||||
##### [Muster](./src/cache_test.c)
|
- CMake ist praktisch! siehe `./src/CMakeList.txt`. Verwenden durch `cmake .` und dann `make`.
|
||||||
|
|
||||||
|
Muster: `./src/cache_test.c`
|
||||||
### Block 2: Signale über den Cache
|
### Block 2: Signale über den Cache
|
||||||
|
|
||||||
`sharedlib.c` sieht so aus:
|
`sharedlib.c` sieht so aus:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
|
void function(void)
|
||||||
|
{ asm volatile (
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
Das kann man so kompilieren:
|
|
||||||
|
Die Adresse von `function` 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 :)
|
||||||
|
|
||||||
|
`sharedlib.c` kann man so kompilieren und linken:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# sharedlib kompilieren
|
# sharedlib kompilieren
|
||||||
@ -73,9 +95,11 @@ gcc -O0 empfaenger.c primitive.c -L. -lsharedlib -o empfaenger
|
|||||||
# ggfs. muss man noch den PATH exportieren
|
# ggfs. muss man noch den PATH exportieren
|
||||||
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
|
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
|
||||||
```
|
```
|
||||||
|
|
||||||
dann kann man `function` verwenden:
|
dann kann man `function` verwenden:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
|
# in e.g. sender.c
|
||||||
maccess((void *) function)
|
maccess((void *) function)
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
@ -83,7 +107,12 @@ maccess((void *) function)
|
|||||||
|
|
||||||
- `taskset` zum pinnen der Programme auf einen bestimmten CPU-Kern.
|
- `taskset` zum pinnen der Programme auf einen bestimmten CPU-Kern.
|
||||||
- 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`.
|
- 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`.
|
||||||
|
- 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 das Flushen übernehmen)
|
- (Der Sender kann das Flushen übernehmen)
|
||||||
- (Der Sender kann im gesamten Zeitabschnitt Flushen oder Laden, nicht nur einmal)
|
- (Der Sender kann im gesamten Zeitabschnitt Flushen oder Laden, nicht nur einmal)
|
||||||
|
|
||||||
### Block 3: Pakete über den Cache als Medium
|
### Block 3: Pakete über den Cache als Medium
|
||||||
|
|
||||||
|
- Kann man irgendwie mehr als ein Bit gleichzeitig senden? ;)
|
||||||
|
|
||||||
|
Muster: `./src/sender.c` und `./src/receiver.c`
|
||||||
@ -8,8 +8,10 @@ extern void flush(void* addr);
|
|||||||
extern void maccess(void* addr);
|
extern void maccess(void* addr);
|
||||||
extern uint64_t time_maccess(void* addr);
|
extern uint64_t time_maccess(void* addr);
|
||||||
|
|
||||||
void measure_multiple_accesses(void (*addr)(void), size_t num_accesses, size_t* hits, size_t* misses) {
|
void measure_multiple_accesses(void (*addr)(void), size_t num_accesses, size_t* hits, size_t* misses)
|
||||||
for (size_t i = 0; i < num_accesses; i++) {
|
{
|
||||||
|
for (size_t i = 0; i < num_accesses; i++)
|
||||||
|
{
|
||||||
flush((void*) addr);
|
flush((void*) addr);
|
||||||
misses[i] = time_maccess(addr);
|
misses[i] = time_maccess(addr);
|
||||||
|
|
||||||
@ -19,10 +21,12 @@ void measure_multiple_accesses(void (*addr)(void), size_t num_accesses, size_t*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t find_crossover_point(size_t* hits, size_t* misses, size_t num_accesses) {
|
size_t find_crossover_point(size_t* hits, size_t* misses, size_t num_accesses)
|
||||||
|
{
|
||||||
size_t hit_sum = 0, miss_sum = 0;
|
size_t hit_sum = 0, miss_sum = 0;
|
||||||
|
|
||||||
for (size_t i = 0; i < num_accesses; i++) {
|
for (size_t i = 0; i < num_accesses; i++)
|
||||||
|
{
|
||||||
hit_sum += hits[i];
|
hit_sum += hits[i];
|
||||||
miss_sum += misses[i];
|
miss_sum += misses[i];
|
||||||
}
|
}
|
||||||
@ -33,11 +37,13 @@ size_t find_crossover_point(size_t* hits, size_t* misses, size_t num_accesses) {
|
|||||||
return (avg_hit + avg_miss) / 2; // Midpoint as threshold
|
return (avg_hit + avg_miss) / 2; // Midpoint as threshold
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
|
{
|
||||||
size_t* hits = malloc(NUM_ACCESSES * sizeof(size_t));
|
size_t* hits = malloc(NUM_ACCESSES * sizeof(size_t));
|
||||||
size_t* misses = malloc(NUM_ACCESSES * sizeof(size_t));
|
size_t* misses = malloc(NUM_ACCESSES * sizeof(size_t));
|
||||||
|
|
||||||
if (!hits || !misses) {
|
if (!hits || !misses)
|
||||||
|
{
|
||||||
perror("Memory allocation failed");
|
perror("Memory allocation failed");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
25
src/recv.c
25
src/recv.c
@ -16,23 +16,31 @@ volatile int sample_interval = 100; // Default: 100 µs
|
|||||||
volatile int threshold = 245; // Default: 245 cycles
|
volatile int threshold = 245; // Default: 245 cycles
|
||||||
|
|
||||||
void signal_handler(int signo) {
|
void signal_handler(int signo) {
|
||||||
if (signo == SIGALRM) {
|
if (signo == SIGALRM)
|
||||||
if (byte_index >= BUFFER_SIZE) {
|
{
|
||||||
|
// Check if buffer is full
|
||||||
|
if (byte_index >= BUFFER_SIZE)
|
||||||
|
{
|
||||||
ualarm(0, 0); // Stop sampling
|
ualarm(0, 0); // Stop sampling
|
||||||
printf("Buffer full. Stopping capture.\n");
|
printf("Buffer full. Stopping capture.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Receive a byte
|
||||||
uint8_t byte = 0;
|
uint8_t byte = 0;
|
||||||
for (int i = 0; i < BITS; i++) {
|
for (int i = 0; i < BITS; i++)
|
||||||
|
{
|
||||||
size_t time = time_maccess((void *) function + (i << 9));
|
size_t time = time_maccess((void *) function + (i << 9));
|
||||||
if (time < threshold) {
|
if (time < threshold)
|
||||||
|
{
|
||||||
|
// set the ith bit of byte to 1 if it was a cache hit
|
||||||
byte |= (1 << i);
|
byte |= (1 << i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// flush the cache
|
// flush the cache
|
||||||
for (int i = 0; i < BITS; i++) {
|
for (int i = 0; i < BITS; i++)
|
||||||
|
{
|
||||||
flush((void *) function + (i << 9));
|
flush((void *) function + (i << 9));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +49,8 @@ void signal_handler(int signo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
if (argc < 3) {
|
if (argc < 3)
|
||||||
|
{
|
||||||
fprintf(stderr, "Usage: %s <sample_interval> <threshold>\n", argv[0]);
|
fprintf(stderr, "Usage: %s <sample_interval> <threshold>\n", argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -51,7 +60,9 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
printf("Receiver started with sample interval: %d µs, threshold: %d cycles\n", sample_interval, threshold);
|
printf("Receiver started with sample interval: %d µs, threshold: %d cycles\n", sample_interval, threshold);
|
||||||
|
|
||||||
for (int i = 0; i < BITS; i++) {
|
// Flush the cache once before starting
|
||||||
|
for (int i = 0; i < BITS; i++)
|
||||||
|
{
|
||||||
flush((void *) function + (i << 9));
|
flush((void *) function + (i << 9));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
11
src/send.c
11
src/send.c
@ -14,8 +14,10 @@ volatile size_t buffer_len = 0;
|
|||||||
volatile size_t current_index = 0;
|
volatile size_t current_index = 0;
|
||||||
volatile uint8_t byte_to_send = 0;
|
volatile uint8_t byte_to_send = 0;
|
||||||
|
|
||||||
void signal_handler(int signo) {
|
void signal_handler(int signo)
|
||||||
if (signo == SIGALRM) {
|
{
|
||||||
|
if (signo == SIGALRM)
|
||||||
|
{
|
||||||
if (current_index < buffer_len)
|
if (current_index < buffer_len)
|
||||||
{
|
{
|
||||||
byte_to_send = buffer[current_index++];
|
byte_to_send = buffer[current_index++];
|
||||||
@ -26,7 +28,8 @@ void signal_handler(int signo) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
if (argc < 3)
|
if (argc < 3)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: %s <string> <sample_interval>\n", argv[0]);
|
fprintf(stderr, "Usage: %s <string> <sample_interval>\n", argv[0]);
|
||||||
@ -37,9 +40,11 @@ int main(int argc, char *argv[]) {
|
|||||||
buffer_len = strlen(argv[1]);
|
buffer_len = strlen(argv[1]);
|
||||||
int sample_interval = atoi(argv[2]);
|
int sample_interval = atoi(argv[2]);
|
||||||
|
|
||||||
|
// set up an alarm signal that triggers every timeframe
|
||||||
signal(SIGALRM, signal_handler);
|
signal(SIGALRM, signal_handler);
|
||||||
ualarm(sample_interval, sample_interval);
|
ualarm(sample_interval, sample_interval);
|
||||||
|
|
||||||
|
// during the timeframe, continuously send the signal
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < BITS; i++)
|
for (int i = 0; i < BITS; i++)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user