-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Prime+Scope implementation, including a "PrimeTime"
implementation for finding prime patterns
- Loading branch information
1 parent
fea5ad2
commit bec7e05
Showing
6 changed files
with
767 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
|
||
#include <mastik/ps.h> | ||
#include <mastik/pt.h> | ||
#include <mastik/l3.h> | ||
|
||
int main() { | ||
pt_t patterns = pt_prepare(NULL, NULL); | ||
pt_results_t results = generate_prime_patterns(patterns); | ||
|
||
printf("EVCr | Cycles | Pattern\n"); | ||
for(int i = 0; i < PT_RESULTS_COUNT; i++){ | ||
printf("%7.3f%% | %6d | ", results->evcrs[i]*100, results->cycles[i]); | ||
dump_ppattern(results->patterns[i]); | ||
printf("\n"); | ||
} | ||
|
||
free(results); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
#define _GNU_SOURCE | ||
#include <sched.h> | ||
#undef _GNU_SOURCE | ||
|
||
#include <stdio.h> | ||
#include <string.h> | ||
#include <assert.h> | ||
#include <signal.h> | ||
#include <unistd.h> | ||
#include <sys/wait.h> | ||
#include <sys/mman.h> | ||
#include <sys/prctl.h> | ||
#include <mastik/ps.h> | ||
#include <mastik/low.h> | ||
|
||
void pin_to_core(int core) { | ||
cpu_set_t cpu_set; | ||
CPU_ZERO(&cpu_set); | ||
CPU_SET(core, &cpu_set); | ||
sched_setaffinity(0, sizeof(cpu_set_t), &cpu_set); | ||
} | ||
|
||
enum SHARED_STATE { | ||
STATE_INIT, | ||
STATE_SHOULD_ACCESS, | ||
}; | ||
volatile enum SHARED_STATE* shared_state; | ||
|
||
pid_t setup_child(void* target) { | ||
shared_state = mmap(NULL, sizeof(enum SHARED_STATE), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); | ||
*shared_state = STATE_INIT; | ||
|
||
pid_t child_pid = fork(); | ||
if(child_pid == 0) { | ||
prctl(PR_SET_PDEATHSIG, SIGKILL); | ||
pin_to_core(3); | ||
while(1) { | ||
while(*shared_state == STATE_INIT) {} | ||
mfence(); | ||
memaccesstime(target); | ||
mfence(); | ||
*shared_state = STATE_INIT; | ||
} | ||
} | ||
|
||
return child_pid; | ||
} | ||
|
||
void cleanup_child(pid_t pid) { | ||
kill(pid, SIGKILL); | ||
waitpid(pid, 0, 0); | ||
munmap((void*)shared_state, sizeof(enum SHARED_STATE)); | ||
} | ||
|
||
#define TARGET_LINE 31 | ||
#define TRIALS 100 | ||
int main() { | ||
// Intel Core i5-8250U: R4_S4_P0S123S1231S23 [99.98% Success rate, 1625 cycles] | ||
uint8_t _pat[13] = {0, PATTERN_TARGET, 1, 2, 3, PATTERN_TARGET, 1, 2, 3, 1, PATTERN_TARGET, 2, 3}; | ||
ppattern_t best_pat = construct_pattern(4, 4, _pat, sizeof(_pat)); | ||
|
||
mm_t mm = mm_prepare(NULL, NULL, NULL); | ||
assert(mm); | ||
ps_t ps = ps_prepare(best_pat, NULL, mm); | ||
assert(ps); | ||
|
||
void* target = mm_requestline(mm, L3, TARGET_LINE); | ||
// NOTE: We are somwhat abusing this for demonstration purposes - | ||
// we are relying on the fact that Linux uses copy-on-write for | ||
// for MAP_PRIVATE mmap-allocations: This line comes from the | ||
// mm->memory buffer, which is MAP_PRIVATE and so in theory it | ||
// is not shared with the forked process, but practically it is. | ||
|
||
ps_monitor(ps, TARGET_LINE); | ||
|
||
pid_t child_pid = setup_child(target); | ||
pin_to_core(2); | ||
|
||
int success = 0; | ||
for(int i = 0; i < TRIALS; i++) { | ||
ps_prime(ps); | ||
|
||
uint16_t t_res; | ||
|
||
ps_scope(ps, &t_res); | ||
if(t_res > L3_THRESHOLD) | ||
continue; | ||
|
||
ps_scope(ps, &t_res); | ||
if(t_res > L3_THRESHOLD) | ||
continue; | ||
|
||
*shared_state = STATE_SHOULD_ACCESS; | ||
mfence(); | ||
while(*shared_state == STATE_SHOULD_ACCESS) {} | ||
mfence(); | ||
|
||
ps_scope(ps, &t_res); | ||
if(t_res < L3_THRESHOLD) | ||
continue; | ||
|
||
success += 1; | ||
} | ||
|
||
printf("%d/%d Successful\n", success, TRIALS); | ||
|
||
ps_release(ps); | ||
cleanup_child(child_pid); | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#ifndef __PS_H__ | ||
#define __PS_H__ 1 | ||
|
||
#include <mastik/lx.h> | ||
#include <mastik/l3.h> | ||
|
||
#define PATTERN_CAPACITY 20 | ||
#define PATTERN_TARGET 0xFF | ||
struct prime_pattern { | ||
uint8_t repeat; | ||
uint8_t stride; | ||
// The largest offset from i | ||
uint8_t width; | ||
uint8_t length; | ||
// 0xFF denotes the target, other values denote offset from i | ||
uint8_t pattern[PATTERN_CAPACITY]; | ||
}; | ||
typedef struct prime_pattern ppattern_t; | ||
ppattern_t construct_pattern(uint8_t repeat, uint8_t stride, uint8_t* pattern, uint8_t length); | ||
void dump_ppattern(ppattern_t pattern); | ||
void access_pattern(vlist_t evset, int associativity, ppattern_t pattern); | ||
|
||
typedef struct ps *ps_t; | ||
ps_t ps_prepare(ppattern_t prime_pattern, l3info_t l3info, mm_t mm); | ||
|
||
int ps_monitor(ps_t ps, int line); | ||
int ps_unmonitor(ps_t ps, int line); | ||
void ps_unmonitorall(ps_t ps); | ||
int ps_getmonitoredset(ps_t ps, int *lines, int nlines); | ||
|
||
void ps_prime(ps_t ps); | ||
void ps_scope(ps_t ps, uint16_t* results); | ||
// Returns the first line that is accessed, or (-1) if no monitored line | ||
// was accessed before running through all iterations | ||
int ps_prime_and_scope(ps_t ps, int iterations); | ||
|
||
void ps_release(ps_t ps); | ||
|
||
#endif // __PS_H__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#ifndef __PRIME_TIME_H__ | ||
#define __PRIME_TIME_H__ 1 | ||
|
||
#include <mastik/ps.h> | ||
|
||
typedef struct prime_time* pt_t; | ||
|
||
#define PT_RESULTS_COUNT 100 | ||
struct pt_results { | ||
ppattern_t patterns[PT_RESULTS_COUNT]; | ||
float evcrs[PT_RESULTS_COUNT]; | ||
int cycles[PT_RESULTS_COUNT]; | ||
}; | ||
typedef struct pt_results* pt_results_t; | ||
|
||
pt_t pt_prepare(l3info_t l3info, mm_t mm); | ||
void pt_release(pt_t pt); | ||
|
||
// Results have to be free()-ed | ||
pt_results_t generate_prime_patterns(pt_t patterns); | ||
|
||
#endif // __PRIME_TIME_H__ |
Oops, something went wrong.