diff --git a/Makefile b/Makefile index b57f56c..577be81 100644 --- a/Makefile +++ b/Makefile @@ -83,6 +83,12 @@ CXXFLAGS += -DFLOPCOUNT=$(FLOPCOUNT) # Pass random-seeding mode to the C++ code. CXXFLAGS += -DRANDOM_SEED=$(RANDOM_SEED) +# Roofline benchmarcking mode enabled/disabled +# default = 0 = disabled (hot cache, for normal performance plot measurments) +# 1 = enabled (cold cache, for roofline plot measurements) +ROOFLINE ?= 0 +CXXFLAGS += -DROOFLINE=$(ROOFLINE) + # Benchmark suite parameters. BENCH_SIZES ?= 50 100 200 500 1000 2000 5000 10000 BENCH_ITER ?= 1000 diff --git a/headers/constants.hpp b/headers/constants.hpp index 02beb3e..15841b4 100644 --- a/headers/constants.hpp +++ b/headers/constants.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include // // $\frac{1}{\tau_{\alpha}}$; $\tau_{\alpha} = 0.5s$ @@ -93,4 +94,6 @@ const double cost_sqrt = 1; const double EPS = 1e-9; // Squared numerical tolerance -const double EPS_SQ = EPS * EPS; \ No newline at end of file +const double EPS_SQ = EPS * EPS; + +const size_t CACHE_BLOCK_SIZE = std::hardware_destructive_interference_size; \ No newline at end of file diff --git a/main.cpp b/main.cpp index 9a185f5..7ee2ea8 100644 --- a/main.cpp +++ b/main.cpp @@ -13,18 +13,64 @@ #define BENCHMARK 0 #endif +#ifndef ROOFLINE +#define ROOFLINE 0 +#endif + #ifdef __x86_64__ #include "./headers/tsc_x86.h" +#include +#define TRASH_BUFFER_SIZE (16ULL * 1024 * 1024 * 2) // Size of L3 cache : 16MB +#define PAGE_SIZE 4096 #endif #ifdef __aarch64__ #include "./headers/kperf.h" +#include +#define TRASH_BUFFER_SIZE (1502838784ULL * 2) // Size of SLC on M3 pro chips : 1.5GB +#define PAGE_SIZE 16384 #endif #define N_OBSTACLES 2 #define WARMUP_ITERS 5 #define NUM_REPS 11 +// Flushes caches by streaming reads through a large persistent buffer. +long long flush_cache() { + static volatile char *trash_buffer = nullptr; + static bool initialized = false; + + if (!initialized) { + trash_buffer = new volatile char[TRASH_BUFFER_SIZE]; + + // Touch one byte per page once so pages are physically mapped. And we avoid paying the cost of page faults during cache trashing below. + for (size_t i = 0; i < TRASH_BUFFER_SIZE; i += PAGE_SIZE) { + trash_buffer[i] = 1; + } + + initialized = true; + } + + long long acc = 0; + + for (size_t i = 0; i < TRASH_BUFFER_SIZE; i += CACHE_BLOCK_SIZE) { + // Access one byte per cache block is enough + acc += trash_buffer[i]; + } + +#ifdef __x86_64__ + _mm_lfence(); +#endif + +#ifdef __aarch64__ + __isb(0xF); +#endif + + asm volatile("" ::: "memory"); + + return acc; +} + int main(int argc, const char *argv[]) { // Check that the correct number of arguments has been passed. // @@ -60,6 +106,10 @@ int main(int argc, const char *argv[]) { #if BENCHMARK +#if ROOFLINE + volatile long long trash_value; +#endif + #ifdef __aarch64__ // Initialize ARM performance counters. kperf_init(); @@ -86,6 +136,9 @@ int main(int argc, const char *argv[]) { for (int i = 0; i < NUM_REPS; i++) { Pedestrian *P = init_pedestrians(n_p); Board board = init_board_without_obstacles(); +#if ROOFLINE + trash_value = flush_cache(); +#endif #ifdef __x86_64__ myInt64 start = start_tsc();