|
/* |
|
* See if I can trigger the cache trashing issue. |
|
* |
|
* Compile with |
|
* gcc cache-test.c -L. -ltcc -ldl -o cache-test |
|
* |
|
* Run as |
|
* ./cache-test mem 30 50000000 |
|
* or, for performance metrics, try |
|
* perf stat -d -d -d ./cache-test mem 30 50000000 |
|
*/ |
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include "libtcc.h" |
|
|
|
void setup_paths(TCCState * state, char **argv); |
|
int setup_link_process(TCCState * state, char **argv); |
|
char * generate_library_code(int N_commands); |
|
void make_library(TCCState * state, int link_process, char *code_to_emit); |
|
void * get_wheels_ptr(TCCState * state, int link_process); |
|
|
|
int main(int argc, char **argv) |
|
{ |
|
/* Print usage error statement */ |
|
if (argc != 4) { |
|
printf("Usage: %s <mem|so> <N-commands> <N-iterations>\n", |
|
argv[0]); |
|
return 1; |
|
} |
|
|
|
/* Set up compiler for 'library' code */ |
|
TCCState *s = tcc_new(); |
|
setup_paths(s, argv); |
|
int link_process = setup_link_process(s, argv); |
|
|
|
/* Assemble library code */ |
|
int N_commands = atoi(argv[2]); |
|
char * code_to_compile = generate_library_code(N_commands); |
|
//printf("code to compile:\n%s\n", code_to_compile); |
|
make_library(s, link_process, code_to_compile); |
|
|
|
void (*spin_wheels)() = get_wheels_ptr(s, link_process); |
|
|
|
/* perform the requested number of iterations */ |
|
int i, N_iterations = atoi(argv[3]); |
|
for (i = 0; i < N_iterations; i++) spin_wheels(); |
|
|
|
return 0; |
|
} |
|
|
|
/* use the current directory as the lib path so this will work with |
|
* whatever is being built at the moment. */ |
|
void setup_paths(TCCState * state, char **argv) { |
|
tcc_set_lib_path(state, "."); |
|
} |
|
|
|
int setup_link_process(TCCState * state, char **argv) { |
|
int output_type = TCC_OUTPUT_MEMORY; |
|
|
|
if (strcmp(argv[1], "so") == 0) output_type = TCC_OUTPUT_DLL; |
|
else if (strcmp(argv[1], "mem") != 0) { |
|
printf("Invalid output type '%s'\n", argv[1]); |
|
printf("Usage: %s <mem|so> <N-commands> <N-iterations>\n", |
|
argv[0]); |
|
exit(1); |
|
} |
|
|
|
tcc_set_output_type(state, output_type); |
|
return output_type; |
|
} |
|
|
|
/* produces a function for the library with the specified number of |
|
* commands in the body of the function. */ |
|
char header[] = "int i; void spin_wheels() {i = 0; if (i) {"; |
|
char footer[] = "} i++; }"; |
|
char * ops[] = { |
|
"i++;", |
|
"i--;", |
|
}; |
|
#define OP_LENGTH 4 |
|
char * generate_library_code(int N_commands) { |
|
/* compute length and allocate */ |
|
int total_length = sizeof(header) + N_commands * OP_LENGTH |
|
+ sizeof(footer) - 1; |
|
char * to_return = malloc(total_length); |
|
char * curr_offset = to_return + sizeof(header) - 1; |
|
|
|
/* set header */ |
|
strcpy(to_return, header); |
|
|
|
/* assemble operations */ |
|
for (int i = 0; i < N_commands; i++) { |
|
strcpy(curr_offset, ops[i % 2]); |
|
curr_offset += OP_LENGTH; |
|
} |
|
|
|
/* closing bracket and trailing null */ |
|
strcpy(curr_offset, footer); |
|
curr_offset[sizeof(footer)] = '\0'; |
|
|
|
return to_return; |
|
} |
|
|
|
void make_library(TCCState * state, int link_process, char *code_to_compile) { |
|
tcc_compile_string(state, code_to_compile); |
|
if (link_process == TCC_OUTPUT_MEMORY) { |
|
printf("Code bytes: %d\n", tcc_relocate(state, 0)); |
|
tcc_relocate(state, TCC_RELOCATE_AUTO); |
|
} |
|
else { |
|
tcc_output_file(state, "cache-test.so"); |
|
} |
|
} |
|
|
|
#include <dlfcn.h> |
|
|
|
void * get_wheels_ptr(TCCState * state, int link_process) { |
|
if (link_process == TCC_OUTPUT_MEMORY) { |
|
return tcc_get_symbol(state, "spin_wheels"); |
|
} |
|
void * lib = dlopen("./cache-test.so", RTLD_NOW); |
|
return dlsym(lib, "spin_wheels"); |
|
} |