Merge pull request #51 from birth-software/improve-timer-entry-point

Improve timer and entry point code
This commit is contained in:
David 2024-09-17 16:55:19 -06:00 committed by GitHub
commit 95d65235d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 175 additions and 61 deletions

View File

@ -145,6 +145,8 @@ fn void compile_c(const CompileOptions *const options, char** envp)
memcpy(vb_add(args, array_length(static_options)), static_options, sizeof(static_options)); memcpy(vb_add(args, array_length(static_options)), static_options, sizeof(static_options));
} }
*vb_add(args, 1) = "-DSILENT";
if (options->compiler == clang) if (options->compiler == clang)
{ {
*vb_add(args, 1) = "-MJ"; *vb_add(args, 1) = "-MJ";
@ -364,14 +366,13 @@ fn void run_tests(Arena* arena, TestOptions const * const test_options, char** e
} }
} }
int main(int argc, char* argv[], char** envp) fn void entry_point(int argc, char* argv[], char* envp[])
{ {
if (argc < 2) if (argc < 2)
{ {
print("Expected some arguments\n"); print("Expected some arguments\n");
return 1; fail();
} }
// calibrate_cpu_timer();
CompilerBackend preferred_compiler_backend = COMPILER_BACKEND_COUNT; CompilerBackend preferred_compiler_backend = COMPILER_BACKEND_COUNT;
Command command = COMMAND_COUNT; Command command = COMMAND_COUNT;
@ -437,7 +438,7 @@ int main(int argc, char* argv[], char** envp)
if (command == COMMAND_COUNT && !source_file_path.pointer) if (command == COMMAND_COUNT && !source_file_path.pointer)
{ {
print("Expected a command\n"); print("Expected a command\n");
return 1; fail();
} }
if (command == COMMAND_COUNT) if (command == COMMAND_COUNT)
@ -461,12 +462,8 @@ int main(int argc, char* argv[], char** envp)
fail(); fail();
} }
Linkage linkage = // Test always with dynamic linkage because it's more trustworthy
#if defined(__linux__) Linkage linkage = LINKAGE_DYNAMIC;
LINKAGE_STATIC;
#else
LINKAGE_DYNAMIC;
#endif
compile_and_run(&(CompileOptions) { compile_and_run(&(CompileOptions) {
.in_path = compiler_source_path, .in_path = compiler_source_path,
@ -481,8 +478,13 @@ int main(int argc, char* argv[], char** envp)
case COMMAND_RUN_TESTS: case COMMAND_RUN_TESTS:
{ {
Arena* arena = arena_init_default(KB(64)); Arena* arena = arena_init_default(KB(64));
Linkage all_linkages[] = { LINKAGE_DYNAMIC, LINKAGE_STATIC }; Linkage all_linkages[] = {
static_assert(array_length(all_linkages) == LINKAGE_COUNT); LINKAGE_DYNAMIC,
#ifdef __linux__
LINKAGE_STATIC
#endif
};
OptimizationMode all_optimization_modes[] = { OptimizationMode all_optimization_modes[] = {
O0, O0,
O1, O1,

View File

@ -97,15 +97,34 @@ FOR_N(_i, 0, ((set)->arr.capacity + 63) / 64) FOR_BIT(it, _i*64, (set)->arr.poin
b = temp;\ b = temp;\
} while (0) } while (0)
fn u64 timestamp() fn
#if LINK_LIBC
struct timespec
#else
u64
#endif
timestamp()
{ {
#if LINK_LIBC
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts;
#else
#if defined(__x86_64__) #if defined(__x86_64__)
return __rdtsc(); return __rdtsc();
#else #else
return 0; return 0;
#endif #endif
#endif
} }
#if LINK_LIBC
global struct timespec cpu_resolution;
#else
global u64 cpu_frequency;
#endif
may_be_unused fn void print(const char* format, ...); may_be_unused fn void print(const char* format, ...);
may_be_unused fn u16 cast_u32_to_u16(u32 source, const char* name, int line) may_be_unused fn u16 cast_u32_to_u16(u32 source, const char* name, int line)
@ -435,6 +454,75 @@ may_be_unused fn s32 cast_s64_to_s32(s64 source, const char* name, int line)
const global u64 page_size = KB(4); const global u64 page_size = KB(4);
#endif #endif
typedef enum TimeUnit
{
TIME_UNIT_NANOSECONDS,
TIME_UNIT_MICROSECONDS,
TIME_UNIT_MILLISECONDS,
TIME_UNIT_SECONDS,
} TimeUnit;
fn f64 resolve_timestamp(
#if LINK_LIBC
struct timespec start, struct timespec end,
#else
u64 start, u64 end,
#endif
TimeUnit time_unit)
{
#if LINK_LIBC
assert(end.tv_sec >= start.tv_sec);
struct timespec result = {
.tv_sec = end.tv_sec - start.tv_sec,
.tv_nsec = end.tv_nsec - start.tv_nsec,
};
auto ns_in_a_sec = 1000000000;
if (result.tv_nsec < 0)
{
result.tv_sec -= 1;
result.tv_nsec += ns_in_a_sec;
}
auto ns = result.tv_sec * ns_in_a_sec + result.tv_nsec;
switch (time_unit)
{
case TIME_UNIT_NANOSECONDS:
return (f64)ns;
case TIME_UNIT_MICROSECONDS:
return ns / 1000.0;
case TIME_UNIT_MILLISECONDS:
return ns / 1000000.0;
case TIME_UNIT_SECONDS:
return ns / 1000000000.0;
}
#else
assert(end >= start);
auto ticks = end - start;
f64 s = (f64)(end - start);
if (cpu_frequency)
{
s = s / (f64)cpu_frequency;
switch (time_unit)
{
case TIME_UNIT_NANOSECONDS:
return s / 1000000000.0;
case TIME_UNIT_MICROSECONDS:
return s / 1000000.0;
case TIME_UNIT_MILLISECONDS:
return s / 1000.0;
case TIME_UNIT_SECONDS:
return s;
}
}
else
{
// warning: rdtsc frequency not queried (returning ticks as are)
return s;
}
#endif
}
const may_be_unused global u8 brace_open = '{'; const may_be_unused global u8 brace_open = '{';
const may_be_unused global u8 brace_close = '}'; const may_be_unused global u8 brace_close = '}';
@ -1425,10 +1513,11 @@ may_be_unused fn u64 os_timer_get()
return result; return result;
} }
global u64 cpu_frequency;
may_be_unused fn void calibrate_cpu_timer() may_be_unused fn void calibrate_cpu_timer()
{ {
#if LINK_LIBC
// clock_getres(CLOCK_MONOTONIC, &cpu_resolution);
#else
u64 miliseconds_to_wait = 100; u64 miliseconds_to_wait = 100;
u64 cpu_start = timestamp(); u64 cpu_start = timestamp();
u64 os_frequency = os_timer_freq(); u64 os_frequency = os_timer_freq();
@ -1445,6 +1534,7 @@ may_be_unused fn void calibrate_cpu_timer()
u64 cpu_end = timestamp(); u64 cpu_end = timestamp();
u64 cpu_elapsed = cpu_end - cpu_start; u64 cpu_elapsed = cpu_end - cpu_start;
cpu_frequency = os_frequency * cpu_elapsed / os_elapsed; cpu_frequency = os_frequency * cpu_elapsed / os_elapsed;
#endif
} }
fn u8* reserve(u64 size) fn u8* reserve(u64 size)
@ -1538,7 +1628,6 @@ fn u32 format_decimal(String buffer, u64 decimal)
} }
} }
#define SILENT (0)
STRUCT(SmallIntResult) STRUCT(SmallIntResult)
{ {
u64 mantissa; u64 mantissa;
@ -2210,7 +2299,7 @@ fn void write_float_decimal(String buffer, u64* value, u64 count)
may_be_unused fn void print(const char* format, ...) may_be_unused fn void print(const char* format, ...)
{ {
#if SILENT == 0 #ifndef SILENT
u8 stack_buffer[4096]; u8 stack_buffer[4096];
va_list args; va_list args;
va_start(args, format); va_start(args, format);
@ -2463,7 +2552,24 @@ may_be_unused fn void print(const char* format, ...)
} }
else else
{ {
__builtin_trap(); auto dp_uoffset = (u64)dp_offset;
if (dp_uoffset >= olength)
{
write_float_decimal(s_get_slice(u8, buffer, buffer_i, buffer.length), &output, olength);
buffer_i += olength;
auto length = dp_uoffset - olength;
auto memset_slice = s_get_slice(u8, buffer, buffer_i, buffer_i + length);
memset(memset_slice.pointer, 0, length);
buffer_i += length;
}
else
{
write_float_decimal(s_get_slice(u8, buffer, buffer_i + dp_uoffset + 1, buffer.length), &output, olength - dp_uoffset);
buffer.pointer[buffer_i + dp_uoffset] = '.';
auto dp_index = buffer_i + dp_uoffset + 1;
write_float_decimal(s_get_slice(u8, buffer, buffer_i, buffer.length), &output, dp_uoffset);
buffer_i += olength + 1;
}
} }
} break; } break;
} }
@ -2692,7 +2798,7 @@ fn void run_command(CStringSlice arguments, char* envp[])
trap(); trap();
} }
u64 start_ns = timestamp(); auto start_timestamp = timestamp();
if (pid == 0) if (pid == 0)
{ {
@ -2712,7 +2818,7 @@ fn void run_command(CStringSlice arguments, char* envp[])
int status = 0; int status = 0;
int options = 0; int options = 0;
pid_t result = syscall_waitpid(pid, &status, options); pid_t result = syscall_waitpid(pid, &status, options);
u64 end_ns = timestamp(); auto end_timestamp = timestamp();
int success = 0; int success = 0;
if (result == pid) if (result == pid)
{ {
@ -2736,14 +2842,15 @@ fn void run_command(CStringSlice arguments, char* envp[])
fail(); fail();
} }
if (cpu_frequency) auto ms = resolve_timestamp(start_timestamp, end_timestamp, TIME_UNIT_MILLISECONDS);
{ auto ticks =
auto ticks = end_ns - start_ns; #if LINK_LIBC
auto ticks_f = (f64)ticks; 0
auto time_frequency_f = (f64)cpu_frequency; #else
auto s = ticks_f / time_frequency_f; cpu_frequency != 0
print("Command run successfully in {f64} s\n", s); #endif
} ;
print("Command run successfully in {f64} {cstr}\n", ms, ticks ? "ticks" : "ms");
} }
} }
@ -2840,3 +2947,36 @@ may_be_unused fn Hash32 hash64_fib_end(Hash64 hash)
auto result = truncate(Hash32, (hash * 11400714819323198485ull) >> 32); auto result = truncate(Hash32, (hash * 11400714819323198485ull) >> 32);
return result; return result;
} }
fn void entry_point(int argc, char* argv[], char* envp[]);
#if LINK_LIBC
int main(int argc, char* argv[], char* envp[])
{
entry_point(argc, argv, envp);
return 0;
}
#else
[[gnu::naked]] [[noreturn]] void _start()
{
__asm__ __volatile__(
"\nxor %ebp, %ebp"
"\npopq %rdi"
"\nmov %rsp, %rsi"
"\nand $~0xf, %rsp"
"\npushq %rsp"
"\npushq $0"
"\ncallq static_entry_point"
"\nud2\n"
);
}
void static_entry_point(int argc, char* argv[])
{
char** envp = (char**)&argv[argc + 1];
calibrate_cpu_timer();
entry_point(argc, argv, envp);
syscall_exit(0);
}
#endif

View File

@ -61,7 +61,7 @@ fn String file_read(Arena* arena, String path)
fn void print_string(String message) fn void print_string(String message)
{ {
#if SILENT == 0 #ifndef SILENT
ssize_t result = syscall_write(1, message.pointer, message.length); ssize_t result = syscall_write(1, message.pointer, message.length);
assert(result >= 0); assert(result >= 0);
assert((u64)result == message.length); assert((u64)result == message.length);
@ -12538,21 +12538,6 @@ fn void print_ir(Thread* restrict thread)
} }
} }
#if LINK_LIBC == 0
[[gnu::naked]] [[noreturn]] void _start()
{
__asm__ __volatile__(
"\nxor %ebp, %ebp"
"\npopq %rdi"
"\nmov %rsp, %rsi"
"\nand $~0xf, %rsp"
"\npushq %rsp"
"\npushq $0"
"\ncallq entry_point"
"\nud2\n"
);
}
#endif
fn void dwarf_playground(Thread* thread) fn void dwarf_playground(Thread* thread)
{ {
@ -12817,22 +12802,12 @@ fn void dwarf_playground(Thread* thread)
assert(*debug_info_bytes.pointer == 0); assert(*debug_info_bytes.pointer == 0);
} }
#if LINK_LIBC fn void entry_point(int argc, char* argv[], char* envp[])
int main(int argc, const char* argv[], char* envp[])
{ {
#else
void entry_point(int argc, const char* argv[])
{
char** envp = (char**)&argv[argc + 1];
unused(envp);
#endif
#if DO_UNIT_TESTS #if DO_UNIT_TESTS
unit_tests(); unit_tests();
#endif #endif
// calibrate_cpu_timer();
Arena* global_arena = arena_init(MB(2), KB(64), KB(64)); Arena* global_arena = arena_init(MB(2), KB(64), KB(64));
{ {
@ -12890,13 +12865,10 @@ void entry_point(int argc, const char* argv[])
else else
{ {
code_generation(thread, (CodegenOptions) { code_generation(thread, (CodegenOptions) {
.test_name = test_name, .test_name = test_name,
.backend = compiler_backend, .backend = compiler_backend,
}, envp); }, envp);
} }
thread_clear(thread); thread_clear(thread);
#if LINK_LIBC == 0
syscall_exit(0);
#endif
} }