#include "tsf_ir.h" #include "tsf_ir_different.h" #include #include #include #include #ifdef TSF_BUILD_SYSTEM #include "tsf.h" #else #include #endif static void usage(void) { fprintf(stderr, "Usage: tsf_ir_speed []\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; }