diff --git a/Makefile b/Makefile index 2f46237258fb558d645fc6b3b229c8879d041b15..9e5a4670930bca65c061076616538595c5fbdfd6 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,10 @@ TOOLCHAIN_PREFIX = CC = $(TOOLCHAIN_PREFIX)gcc OBJDUMP = $(TOOLCHAIN_PREFIX)objdump +TARGETS = libaes.so test_aes.elf cache_profiling_hit.elf cache_profiling_pp1.elf cache_profiling_pp8.elf + .PHONY: all clean -all: libaes.so test_aes.elf cache_profiling_hit.elf +all: $(TARGETS) libaes.so: aes/aes_core.c aes/aes_local.h aes/aes.h $(CC) -fPIC aes/aes_core.c -Iaes -shared -o $@ @@ -14,5 +16,11 @@ test_aes.elf: src/test_aes.c libaes.so cache_profiling_hit.elf: src/cache_profiling_hit.c cache/cache_util.c cache/cache_util.h cache/cache_low.h visual/histogram.c visual/histogram.h $(CC) src/cache_profiling_hit.c cache/cache_util.c visual/histogram.c -Icache -Ivisual -o $@ +cache_profiling_pp1.elf: src/cache_profiling_pp1.c cache/cache_util.c cache/cache_util.h cache/cache_low.h visual/histogram.c visual/histogram.h + $(CC) src/cache_profiling_pp1.c cache/cache_util.c visual/histogram.c -Icache -Ivisual -o $@ + +cache_profiling_pp8.elf: src/cache_profiling_pp8.c cache/cache_l1.c cache/cache_l1.h cache/cache_util.c cache/cache_util.h cache/cache_low.h visual/histogram.c visual/histogram.h + $(CC) src/cache_profiling_pp8.c cache/cache_l1.c cache/cache_util.c visual/histogram.c -Icache -Ivisual -o $@ + clean: rm -f -- *.elf *.so *.dump *.csv diff --git a/cache/cache_l1.c b/cache/cache_l1.c new file mode 100644 index 0000000000000000000000000000000000000000..65085d57b9dd93c81549887847e68995bc25d657 --- /dev/null +++ b/cache/cache_l1.c @@ -0,0 +1,176 @@ +/* + * Copyright 2016 CSIRO + * + * This file is part of Mastik. + * + * Mastik is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mastik is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mastik. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <sys/mman.h> +#include <assert.h> +#include <strings.h> + +#include "cache_low.h" +#include "cache_l1.h" + +#define L1_ASSOCIATIVITY 8 + +#define L1_CACHELINE 64 +#define L1_STRIDE (L1_CACHELINE * L1_SETS) + +#define PTR(set, way, ptr) (void *)(((uintptr_t)l1->memory) + ((set) * L1_CACHELINE) + ((way) * L1_STRIDE) + ((ptr)*sizeof(void *))) +#define LNEXT(p) (*(void **)(p)) + +struct l1pp{ + void *memory; + void *fwdlist; + void *bkwlist; + uint8_t monitored[L1_SETS]; + int nsets; +}; + +static void rebuild(l1pp_t l1) { + if (l1->nsets == 0) { + l1->fwdlist = l1->bkwlist = NULL; + return; + } + for (int i = 0; i < l1->nsets - 1; i++) { + LNEXT(PTR(l1->monitored[i], L1_ASSOCIATIVITY - 1, 0)) = PTR(l1->monitored[i+1], 0, 0); + LNEXT(PTR(l1->monitored[i], 0, 1)) = PTR(l1->monitored[i+1], L1_ASSOCIATIVITY - 1, 1); + } + l1->fwdlist = LNEXT(PTR(l1->monitored[l1->nsets - 1], L1_ASSOCIATIVITY - 1, 0)) = PTR(l1->monitored[0], 0, 0); + l1->bkwlist = LNEXT(PTR(l1->monitored[l1->nsets - 1], 0, 1)) = PTR(l1->monitored[0], L1_ASSOCIATIVITY - 1, 1); +} + +static void probelist(void *p, int segments, int seglen, uint16_t *results) { + while (segments--) { + uint32_t s = rdtscp(); + for (int i = seglen; i--; ) { + asm volatile (""::"r" (p):); + p = LNEXT(p); + } + uint32_t res = rdtscp() - s; + *results = res > UINT16_MAX ? UINT16_MAX : res; + results++; + } +} + +l1pp_t l1_prepare(void) { + l1pp_t l1 = (l1pp_t)malloc(sizeof(struct l1pp)); + l1->memory = mmap(0, PAGE_SIZE * L1_ASSOCIATIVITY, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); + l1->fwdlist = NULL; + l1->bkwlist = NULL; + for (int set = 0; set < L1_SETS; set++) { + for (int way = 0; way < L1_ASSOCIATIVITY - 1; way++) { + LNEXT(PTR(set, way, 0)) = PTR(set, way+1, 0); + LNEXT(PTR(set, way+1, 1)) = PTR(set, way, 1); + } + } +// l1_monitorall(l1); + return l1; +} + +void l1_release(l1pp_t l1) { + munmap(l1->memory, PAGE_SIZE * L1_ASSOCIATIVITY); + bzero(l1, sizeof(struct l1pp)); + free(l1); +} + +int l1_monitor(l1pp_t l1, int line) { + for (int i = 0; i < l1->nsets; i++) + if (l1->monitored[i] == line) + return 0; + l1->monitored[l1->nsets++] = line; + rebuild(l1); + return 1; +} + +int l1_unmonitor(l1pp_t l1, int line) { + for (int i = 0; i < l1->nsets; i++) + if (l1->monitored[i] == line) { + l1->monitored[i] = l1->monitored[l1->nsets--]; + rebuild(l1); + return 1; + } + return 0; +} + +void l1_monitorall(l1pp_t l1) { + for (int i = 0; i < L1_SETS; i++) + l1->monitored[i] = i; + l1->nsets = L1_SETS; + l1_randomise(l1); +} + +void l1_unmonitorall(l1pp_t l1) { + l1->nsets = 0; + rebuild(l1); +} + +int l1_getmonitoredset(l1pp_t l1, int *lines, int nlines) { + if (lines != NULL) { + if (nlines > l1->nsets) + nlines = l1->nsets; + for (int i = 0; i < nlines; i++) + lines[i] = l1->monitored[i]; + } + return l1->nsets; +} + +int l1_nsets(l1pp_t l1) { + return l1->nsets; +} + +void l1_randomise(l1pp_t l1) { + for (int i = 0; i < l1->nsets; i++) { + int p = random() % (l1->nsets - i) + i; + uint8_t t = l1->monitored[p]; + l1->monitored[p] = l1->monitored[i]; + l1->monitored[i] = t; + } + rebuild(l1); +} + +void l1_probe(l1pp_t l1, uint16_t *results) { + probelist(l1->fwdlist, l1->nsets, L1_ASSOCIATIVITY, results); +} + +void l1_bprobe(l1pp_t l1, uint16_t *results) { + probelist(l1->bkwlist, l1->nsets, L1_ASSOCIATIVITY, results); +} + + +int l1_repeatedprobe(l1pp_t l1, int nrecords, uint16_t *results, int slot) { + assert(l1 != NULL); + assert(results != NULL); + + if (nrecords == 0) + return 0; + + int len = l1->nsets; + + for (int i = 0; i < nrecords; /* Increment inside */) { + l1_probe(l1, results); + results += len; + i++; + l1_bprobe(l1, results); + results += len; + i++; + } + return nrecords; +} + diff --git a/cache/cache_l1.h b/cache/cache_l1.h new file mode 100644 index 0000000000000000000000000000000000000000..8cf2cea54dff8b1b1b5b461cf1bbbc53809e5105 --- /dev/null +++ b/cache/cache_l1.h @@ -0,0 +1,46 @@ +/* + * Copyright 2016 CSIRO + * + * This file is part of Mastik. + * + * Mastik is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mastik is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mastik. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __CACHE_L1_H__ +#define __CACHE_L1_H__ 1 + +#define L1_SETS 64 + +typedef struct l1pp *l1pp_t; + +l1pp_t l1_prepare(void); +void l1_release(l1pp_t l1); + +int l1_monitor(l1pp_t l1, int line); +int l1_unmonitor(l1pp_t l1, int line); +void l1_monitorall(l1pp_t l1); +void l1_unmonitorall(l1pp_t l1); +int l1_getmonitoredset(l1pp_t l1, int *lines, int nlines); +void l1_randomise(l1pp_t l1); + +void l1_probe(l1pp_t l1, uint16_t *results); +void l1_bprobe(l1pp_t l1, uint16_t *results); + +// Slot is currently not implemented +int l1_repeatedprobe(l1pp_t l1, int nrecords, uint16_t *results, int slot); + + + +#endif // __CACHE_L1_H__ + diff --git a/cache/cache_low.h b/cache/cache_low.h index 9537c8d31fb7f569b22821f4b661dd92834880b8..93f19dcf1cdf754c908a08eb58970e378a04255d 100644 --- a/cache/cache_low.h +++ b/cache/cache_low.h @@ -3,6 +3,12 @@ #include <stdint.h> +#ifdef PAGE_SIZE +#undef PAGE_SIZE +#endif +#define PAGE_SIZE 4096 +//sysconf(_SC_PAGE_SIZE) + static inline int memaccess(void *v) { int rv; #ifndef __riscv diff --git a/src/cache_profiling_hit.c b/src/cache_profiling_hit.c index cffc9b94c932557cb8bffa4c6c20da4a394c623e..b3bf424e9b4aef1d6381a8481d62e4fa84059e77 100644 --- a/src/cache_profiling_hit.c +++ b/src/cache_profiling_hit.c @@ -45,6 +45,7 @@ int main(void) { } fclose(fcache_profiling); + unmap_offset(addr); return 0; } diff --git a/src/cache_profiling_pp1.c b/src/cache_profiling_pp1.c new file mode 100644 index 0000000000000000000000000000000000000000..f381d63252e783a2757ab814fcc9f9a55f3d55d9 --- /dev/null +++ b/src/cache_profiling_pp1.c @@ -0,0 +1,75 @@ +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <sys/mman.h> +#include <unistd.h> + +#include "cache_low.h" +#include "cache_util.h" +#include "histogram.h" + +#define SAMPLES 10000 +#define MAX_CYCLES 500 + +#define L1_SETS 64 +#define L1_CACHELINE 64 + +int main(int argc, char **argv) { + + if (argc != 2) { + printf("usage %s <set to monitor(0-%d)>, set%d refer to all sets\n", argv[0], L1_SETS, L1_SETS); + return 1; + } + + int set_to_monitor = atoi(argv[1]); + if (set_to_monitor < 0 || set_to_monitor > L1_SETS) { + printf("usage %s <set to monitor(0-%d)>, set%d refer to all sets\n", argv[0], L1_SETS, L1_SETS); + return 1; + } + + uint16_t cache_access_cycles[SAMPLES]; + uint16_t cache_access_histogram[MAX_CYCLES]; + + memset(cache_access_histogram, 0, MAX_CYCLES*sizeof(uint16_t)); + + void* addr = map_offset("libaes.so", 0); + printf("Monitored addr: %p\n", addr); + + // Prepare Prime+Probe playground + void* pp_memory = mmap(0, PAGE_SIZE * 1, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); + void* pp_memory_access = pp_memory + set_to_monitor*L1_CACHELINE; + printf("Prime+Probe addr: %p\n", pp_memory_access); + + // Cache access cycles + for (int i=0; i < SAMPLES; i++){ + memaccesstime_u16(pp_memory_access); + cache_access_cycles[i] = memaccesstime_u16(addr); + } + + // Cache histogram + for (int i=0; i < SAMPLES; i++) { + if (cache_access_cycles[i] < MAX_CYCLES) { + cache_access_histogram[cache_access_cycles[i]] ++; + } else { + cache_access_histogram[MAX_CYCLES] ++; + } + } + + // Print histogram + draw_histogram_u16(cache_access_histogram, MAX_CYCLES); + + // Export to csv file + FILE* fcache_profiling = fopen("cache_profiling_pp1.csv","w"); + fprintf(fcache_profiling,"index;cache access\n"); + + for(int i = 0; i < MAX_CYCLES; i++) { + fprintf(fcache_profiling,"%d;%d;\n", i, cache_access_histogram[i]); + } + + fclose(fcache_profiling); + unmap_offset(addr); + munmap(pp_memory, PAGE_SIZE * 1); + + return 0; +} diff --git a/src/cache_profiling_pp8.c b/src/cache_profiling_pp8.c new file mode 100644 index 0000000000000000000000000000000000000000..dbf948f1c25ae35859a260ae3a020c06fdaf22b3 --- /dev/null +++ b/src/cache_profiling_pp8.c @@ -0,0 +1,97 @@ +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> + +#include "cache_low.h" +#include "cache_util.h" +#include "cache_l1.h" +#include "histogram.h" + +#define SAMPLES 10000 +#define MAX_CYCLES 500 + +int main(int argc, char **argv) { + + if (argc != 2) { + printf("usage %s <set to monitor(0-%d)>, set%d refer to all sets\n", argv[0], L1_SETS, L1_SETS); + return 1; + } + + int set_to_monitor = atoi(argv[1]); + if (set_to_monitor < 0 || set_to_monitor > L1_SETS) { + printf("usage %s <set to monitor(0-%d)>, set%d refer to all sets\n", argv[0], L1_SETS, L1_SETS); + return 1; + } + + uint16_t cache_access_cycles[SAMPLES]; + uint16_t cache_access_histogram[MAX_CYCLES]; + + memset(cache_access_histogram, 0, MAX_CYCLES*sizeof(uint16_t)); + + void* addr = map_offset("libaes.so",0); + printf("Monitored addr: %p\n", addr); + + // Prepare Prime+Probe playground + l1pp_t l1 = l1_prepare(); + if (set_to_monitor < L1_SETS) { + // Monitor 1 set + l1_monitor(l1, set_to_monitor); + } else { + l1_monitorall(l1); + } + int nsets = l1_getmonitoredset(l1, NULL, 0); + printf("L1 monitored set: %d\n", nsets); + + uint16_t pp_results[nsets*SAMPLES]; + uint16_t pp_histogram[MAX_CYCLES]; + + // Cache access cycles + for (int i=0; i < SAMPLES; i++){ + l1_probe(l1, &pp_results[i*nsets]); + cache_access_cycles[i] = memaccesstime_u16(addr); + } + + // Cache histogram + printf("Cache access histogram:\n"); + for (int i=0; i < SAMPLES; i++) { + if (cache_access_cycles[i] < MAX_CYCLES) { + cache_access_histogram[cache_access_cycles[i]] ++; + } else { + cache_access_histogram[MAX_CYCLES] ++; + } + } + + // Print histogram + draw_histogram_u16(cache_access_histogram, MAX_CYCLES); + + // Prime+Probe histogram + printf("Prime+Probe histogram\n"); + for (int i=0; i < SAMPLES; i++) { + for (int j=0; j < nsets; j++) { + uint16_t res = pp_results[i*nsets + j]; + if (res < MAX_CYCLES) { + pp_histogram[res] ++; + } else { + pp_histogram[MAX_CYCLES] ++; + } + } + } + + // Print histogram + draw_histogram_u16(pp_histogram, MAX_CYCLES); + + // Export to csv file + FILE* fcache_profiling = fopen("cache_profiling_pp8.csv","w"); + fprintf(fcache_profiling,"index;cache access\n"); + + for(int i = 0; i < MAX_CYCLES; i++) { + fprintf(fcache_profiling,"%d;%d;\n", i, cache_access_histogram[i]); + } + + fclose(fcache_profiling); + unmap_offset(addr); + l1_release(l1); + + return 0; +}