blob: dd75c43e51c89a36b75746e95547a871e891fd1f [file] [log] [blame]
#include "tsf_ir.h"
#include "tsf_ir_different.h"
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <sys/time.h>
#ifdef TSF_BUILD_SYSTEM
#include "tsf.h"
#else
#include <tsf/tsf.h>
#endif
static void usage(void) {
fprintf(stderr, "Usage: tsf_ir_speed [<count>]\n");
exit(1);
}
static double milliTime(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000. + tv.tv_usec / 1000.;
}
#define TIMEIT(statement) do { \
double __ti_before = milliTime(); \
statement; \
double __ti_after = milliTime(); \
printf("%s: %.3lf ms\n", #statement, __ti_after - __ti_before); \
} while (0)
/* If the expression evaluates false then it assumes an error and exits. */
#define CT(exp) do { \
if (!(exp)) { \
fprintf(stderr, "%s:%d: %s: %s\n", \
__FILE__, __LINE__, #exp, tsf_get_error()); \
exit(1); \
} \
} while (0)
#define CS(exp) do { \
if (!(exp)) { \
int myErrno = errno; \
fprintf(stderr, "%s:%d: %s: %s\n", \
__FILE__, __LINE__, #exp, strerror(myErrno)); \
exit(1); \
} \
} while (0)
static void writeTest(const char *filename,
unsigned programSize, unsigned numPrograms,
tsf_zip_mode_t zipMode) {
tsf_zip_wtr_attr_t zipAttributes;
tsf_stream_file_output_t *out;
unsigned programIndex;
char buf[256];
CT(tsf_zip_wtr_attr_get_for_mode(&zipAttributes, zipMode));
CT(out = tsf_stream_file_output_open(filename, tsf_false, &zipAttributes));
for (programIndex = 0; programIndex < numPrograms; ++programIndex) {
const unsigned numDecls = 25;
const unsigned numDefns = 25;
Program_t *program;
unsigned elementIndex;
CS(program = tsf_region_create(sizeof(Program_t)));
program->globals.len = numDecls + numDefns;
CS(program->globals.data = tsf_region_alloc(
program, sizeof(ProgramElement_t) * program->globals.len));
for (elementIndex = 0; elementIndex < numDecls; ++elementIndex) {
ProgramElement_t *element;
ProcedureDecl_t *procedure;
element = program->globals.data + elementIndex;
element->value = ProgramElement__procedureDecl;
procedure = &element->u.procedureDecl;
snprintf(buf, sizeof(buf), "foo%u", elementIndex);
procedure->name = tsf_region_strdup(program, buf);
}
for (elementIndex = numDecls;
elementIndex < numDecls + numDefns;
++elementIndex) {
ProgramElement_t *element;
ProcedureDefn_t *procedure;
unsigned numVariables = (programIndex % programSize) + 1;
unsigned numInstructions = (programIndex % programSize) * 2 + 1;
unsigned numDebugDatas = (numInstructions + 5) / 6;
unsigned variableIndex;
unsigned instructionIndex;
unsigned debugDataIndex;
element = program->globals.data + elementIndex;
element->value = ProgramElement__procedureDefn;
procedure = &element->u.procedureDefn;
snprintf(buf, sizeof(buf), "bar%u", elementIndex);
procedure->name = tsf_region_strdup(program, buf);
procedure->variables.len = numVariables;
CS(procedure->variables.data = tsf_region_alloc(
program, sizeof(VariableDecl_t) * numVariables));
for (variableIndex = 0; variableIndex < numVariables; ++variableIndex) {
VariableDecl_t *variable;
variable = procedure->variables.data + variableIndex;
switch ((variableIndex + programIndex) % 3) {
case 0:
variable->type = "foo";
break;
case 1:
variable->type = "bar";
break;
case 2:
variable->type = "baz";
break;
default:
abort();
break;
}
snprintf(buf, sizeof(buf), "x%u", variableIndex);
variable->name = tsf_region_strdup(program, buf);
}
procedure->code.len = numInstructions;
CS(procedure->code.data = tsf_region_alloc(
program, sizeof(Instruction_t) * numInstructions));
for (instructionIndex = 0;
instructionIndex < numInstructions;
++instructionIndex) {
Instruction_t *instruction;
instruction = procedure->code.data + instructionIndex;
switch ((instructionIndex + programIndex) % 8) {
case Instruction__nop: {
instruction->value = Instruction__nop;
break;
}
case Instruction__mov: {
instruction->value = Instruction__mov;
instruction->u.mov.dest =
(instructionIndex + programIndex) % numVariables;
instruction->u.mov.src =
(instructionIndex + programIndex + 1) % numVariables;
break;
}
case Instruction__add: {
instruction->value = Instruction__add;
instruction->u.add.dest =
(instructionIndex + programIndex + 2) % numVariables;
instruction->u.add.src =
(instructionIndex + programIndex + 3) % numVariables;
break;
}
case Instruction__alloc: {
instruction->value = Instruction__alloc;
snprintf(buf, sizeof(buf), "t%u", instructionIndex + programIndex);
instruction->u.alloc.type = tsf_region_strdup(program, buf);
break;
}
case Instruction__ret: {
instruction->value = Instruction__ret;
instruction->u.ret.src =
(instructionIndex + programIndex + 4) % numVariables;
break;
}
case Instruction__jump: {
instruction->value = Instruction__jump;
instruction->u.jump.target =
(instructionIndex + programIndex) % numInstructions;
break;
}
case Instruction__call: {
unsigned numArgs = (instructionIndex + programIndex) % 10;
unsigned argIndex;
instruction->value = Instruction__call;
instruction->u.call.dest =
(instructionIndex + programIndex + 7) % numVariables;
instruction->u.call.callee =
((instructionIndex + programIndex) %
(numVariables + numDecls + numDefns)) -
numDecls - numDefns;
instruction->u.call.args.len = numArgs;
CS(instruction->u.call.args.data = tsf_region_alloc(
program, sizeof(Operand_t) * numArgs));
for (argIndex = 0; argIndex < numArgs; ++argIndex) {
instruction->u.call.args.data[argIndex] =
(instructionIndex + programIndex + argIndex) % numVariables;
}
break;
}
case Instruction__branchZero: {
instruction->value = Instruction__branchZero;
instruction->u.branchZero.src =
(instructionIndex + programIndex + 5) % numVariables;
instruction->u.branchZero.target =
(instructionIndex + programIndex + 6) % numInstructions;
break;
}
default:
abort();
break;
}
}
procedure->debug.len = numDebugDatas;
CS(procedure->debug.data = tsf_region_alloc(
program, sizeof(DebugData_t) * numDebugDatas));
for (debugDataIndex = 0; debugDataIndex < numDebugDatas; ++debugDataIndex) {
DebugData_t *debugData;
debugData = procedure->debug.data + debugDataIndex;
debugData->startOffset = debugDataIndex;
debugData->spanSize = 1;
snprintf(buf, sizeof(buf), "debug%u", debugDataIndex);
debugData->data = tsf_region_strdup(program, buf);
}
}
Program__write(out, program);
tsf_region_free(program);
}
CT(tsf_stream_file_output_close(out));
}
static void readTest(const char *filename, unsigned numPrograms) {
tsf_stream_file_input_t *in;
unsigned count;
CT(in = tsf_stream_file_input_open(filename, NULL, NULL));
count = 0;
for (;;) {
Program_t *program = Program__read(in);
if (!program) {
CT(tsf_get_error_code() == TSF_E_EOF);
break;
}
count++;
tsf_region_free(program);
}
if (count != numPrograms)
abort();
tsf_stream_file_input_close(in);
}
static void readMallocTest(const char *filename, unsigned numPrograms) {
tsf_stream_file_input_t *in;
unsigned count;
CT(in = tsf_stream_file_input_open(filename, NULL, NULL));
count = 0;
for (;;) {
Program_t program;
if (!Program__read_into(in, &program)) {
CT(tsf_get_error_code() == TSF_E_EOF);
break;
}
count++;
Program__destruct(&program);
}
if (count != numPrograms)
abort();
tsf_stream_file_input_close(in);
}
static void readConvertTest(const char *filename, unsigned numPrograms) {
tsf_stream_file_input_t *in;
unsigned count;
CT(in = tsf_stream_file_input_open(filename, NULL, NULL));
count = 0;
for (;;) {
DProgram_t *program = DProgram__read(in);
if (!program) {
CT(tsf_get_error_code() == TSF_E_EOF);
break;
}
count++;
tsf_region_free(program);
}
if (count != numPrograms)
abort();
tsf_stream_file_input_close(in);
}
int main(int c, char **v) {
static const char *filename = "tsf_ir_speed_test_file.tsf";
static const char *zipFilename = "tsf_ir_speed_test_zip_file.tsf";
unsigned count;
switch (c) {
case 1:
/* Use a small problem size suitable for regression testing. */
count = 1000;
break;
case 2:
if (sscanf(v[1], "%u", &count) != 1) {
usage();
}
break;
default:
usage();
return 1;
}
printf("Writing %u programs.\n", count);
if (count != 10000)
printf("WARNING: If you are benchmarking, please use count = 10000.\n");
TIMEIT(writeTest(filename, 100, count, TSF_ZIP_NONE));
TIMEIT(readTest(filename, count));
TIMEIT(readMallocTest(filename, count));
TIMEIT(readConvertTest(filename, count));
if (tsf_zlib_supported()) {
TIMEIT(writeTest(zipFilename, 100, count, TSF_ZIP_ZLIB));
TIMEIT(readTest(zipFilename, count));
TIMEIT(readMallocTest(filename, count));
TIMEIT(readConvertTest(zipFilename, count));
}
/* We don't benchmark bzip2 because it's just too slow to be interesting. */
return 0;
}