From 28308f58b26e638bbf44f054f3f72cb06bf17dd5 Mon Sep 17 00:00:00 2001 From: krzosa Date: Tue, 23 Dec 2025 13:18:41 +0100 Subject: [PATCH] Optimizations and profiling (fix draw line numbers, coroutines) --- src/backup/todo.txt | 6 +++-- src/basic/basic_os.cpp | 27 ++++++++++++++++++++ src/text_editor/commands.cpp | 6 +---- src/text_editor/coroutines.cpp | 45 ++++++++++++++++++++-------------- src/text_editor/draw.cpp | 11 ++++++--- src/text_editor/globals.cpp | 4 ++- src/text_editor/profiler.h | 6 ++--- 7 files changed, 72 insertions(+), 33 deletions(-) diff --git a/src/backup/todo.txt b/src/backup/todo.txt index 656b9ec..fd13baf 100644 --- a/src/backup/todo.txt +++ b/src/backup/todo.txt @@ -1,11 +1,13 @@ - What precise workflow do I need for me to be viable to use this? - From a user (novice) point of view, how does it look like? +- Optimization: - Show what process/coroutines are running and allow to kill (active process buffer?) - ctrl + p like in VSCode (without special buffers) - - I THINK WE NEED A SPECIAL VIEW, this is too slow - - Move to the top so that it can be progressively expanded using coroutines by appending at the end - Maybe 2 windows? +- Database idea: use special buffers to store information + - Editing the buffer doesn't seem to be the slow part rather, accessing the data and putting it into the buffer (potentially hitting many different memory locations) I have a crazy idea to use buffers in order to store the names in a serialized format + - non editable buffers (raw ops ok, non-raw no op) - Guide on the first page for new users with links to configs, tutorials - Why constraint that name of buffer needs to be unique? For Open() and default behavior but is this required? diff --git a/src/basic/basic_os.cpp b/src/basic/basic_os.cpp index 2b2d56e..69b504d 100644 --- a/src/basic/basic_os.cpp +++ b/src/basic/basic_os.cpp @@ -193,6 +193,13 @@ API String GetExeDir(Allocator al) { return result; } +API uint64_t GetTimeNanos(void) { + struct timespec spec; + clock_gettime(CLOCK_MONOTONIC, &spec); + uint64_t ts = ((uint64_t)spec.tv_sec * 1000000000ull) + (uint64_t)spec.tv_nsec; + return ts; +} + API double GetTimeMicros(void) { struct timespec spec; clock_gettime(CLOCK_MONOTONIC, &spec); @@ -565,6 +572,19 @@ API FileIter IterateFiles(Allocator alo, String path) { return it; } +API uint64_t GetTimeNanos(void) { + static double invfreq; + if (!invfreq) { + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + invfreq = 1000000000.0 / frequency.QuadPart; + } + LARGE_INTEGER counter; + QueryPerformanceCounter(&counter); + uint64_t ts = (uint64_t)((double)counter.QuadPart * invfreq); + return ts; +} + API double GetTimeMicros(void) { static double invfreq; if (!invfreq) { @@ -1047,6 +1067,13 @@ API String GetExeDir(Allocator al) { return result; } +API uint64_t GetTimeNanos(void) { + struct timespec spec; + clock_gettime(CLOCK_MONOTONIC, &spec); + uint64_t ts = ((uint64_t)spec.tv_sec * 1000000000ull) + (uint64_t)spec.tv_nsec; + return ts; +} + API double GetTimeMicros(void) { struct timespec spec; clock_gettime(CLOCK_MONOTONIC, &spec); diff --git a/src/text_editor/commands.cpp b/src/text_editor/commands.cpp index f250377..b22fce5 100644 --- a/src/text_editor/commands.cpp +++ b/src/text_editor/commands.cpp @@ -674,11 +674,7 @@ void Coro_OpenCode(mco_coro *co) { } } - - if ((i%32) == 0) { - CoYield(co); - } - i += 1; + CoYield(co); } } Release(&arena); diff --git a/src/text_editor/coroutines.cpp b/src/text_editor/coroutines.cpp index 5c82a6e..dc98221 100644 --- a/src/text_editor/coroutines.cpp +++ b/src/text_editor/coroutines.cpp @@ -1,6 +1,7 @@ typedef void CoroutineProc(mco_coro *co); -mco_coro *CoAdd(CoroutineProc *proc) { +#define CoAdd(x) CoAddEx(x, #x) +mco_coro *CoAddEx(CoroutineProc *proc, String name) { mco_desc desc = mco_desc_init(proc, 0); mco_coro *coro = NULL; @@ -11,32 +12,35 @@ mco_coro *CoAdd(CoroutineProc *proc) { } mco_resume(coro); - Add(&ActiveCoroutines, coro); + Add(&ActiveCoroutines, {coro, name}); return coro; } void CoUpdate(Event *event) { ProfileFunction(); double start = GetTimeSeconds(); - IterRemove(ActiveCoroutines) { - IterRemovePrepare(ActiveCoroutines); + for (;ActiveCoroutines.len;) { + IterRemove(ActiveCoroutines) { + IterRemovePrepare(ActiveCoroutines); + ProfileScopeEx(it.name); - mco_state status = mco_status(it); - if (status == MCO_DEAD) { - mco_destroy(it); - remove_item = true; - } else { - mco_push(it, &event, sizeof(Event *)); - mco_result ok = mco_resume(it); - if (ok != MCO_SUCCESS) { - ReportWarningf("failed to resume coroutine %d", ok); - mco_destroy(it); + mco_state status = mco_status(it.co); + if (status == MCO_DEAD) { + mco_destroy(it.co); remove_item = true; + } else { + mco_push(it.co, &event, sizeof(Event *)); + mco_result ok = mco_resume(it.co); + if (ok != MCO_SUCCESS) { + ReportWarningf("failed to resume coroutine %d", ok); + mco_destroy(it.co); + remove_item = true; + } } } double took = GetTimeSeconds() - start; - if (took > 0.01) { + if (took > (0.016666 / 3.0)) { break; } } @@ -53,7 +57,12 @@ Event *CoYield(mco_coro *co) { return event; } -void CoRemove(mco_coro *co) { - UnorderedRemove(&ActiveCoroutines, co); - mco_destroy(co); +void CoRemove(String name) { + IterRemove(ActiveCoroutines) { + IterRemovePrepare(ActiveCoroutines); + if (it.name == name) { + mco_destroy(it.co); + remove_item = true; + } + } } diff --git a/src/text_editor/draw.cpp b/src/text_editor/draw.cpp index 06d8764..d5cbb1c 100644 --- a/src/text_editor/draw.cpp +++ b/src/text_editor/draw.cpp @@ -235,7 +235,7 @@ void DrawWindow(Window *window, Event &event) { // Draw caret "|" markings if (is_active) { - BeginProfileScope(draw_carets); + ProfileScope(DrawCarets); For(view->carets) { Int front = GetFront(it); XY fxy = PosToXY(buffer, front); @@ -244,17 +244,17 @@ void DrawWindow(Window *window, Event &event) { DrawCaret(window, fxy, 0.3f, main_caret ? color_main_caret : color_sub_caret); } } - EndProfileScope(); } // Draw line numbers if (window->draw_line_numbers) { + ProfileScope(DrawLineNumbers); + Scratch scratch; SetScissor(window->line_numbers_rect); Rect2I vlines = GetVisibleCells(window); for (Int line = vlines.min.y; line <= visible.max.y && line >= 0 && line < buffer->line_starts.len; line += 1) { - Scratch scratch; - Vec2I pos = {0, line * window->font->line_spacing}; + Vec2I pos = {0, line * window->font->line_spacing}; pos.y -= view->scroll.y; pos += window->line_numbers_rect.min; String s = Format(scratch, "%lld", (long long)line + 1ll); @@ -270,6 +270,7 @@ void DrawWindow(Window *window, Event &event) { // Draw scrollbar if (window->draw_scrollbar) { + ProfileScope(DrawScrollbar); SetScissor(window->scrollbar_rect); DrawRect(window->scrollbar_rect, ColorScrollbarBackground); Scroller scroller = ComputeScrollerRect(window); @@ -281,12 +282,14 @@ void DrawWindow(Window *window, Event &event) { // color the floating object to make it stand out if (window->z >= 1) { + ProfileScope(ColorFloating); SetScissor(window->total_rect); DrawRect(window->total_rect, {255, 255, 255, 25}); } // darken the inactive windows if (!is_active) { + ProfileScope(DarkenInactiveRect); SetScissor(screen_rect); DrawRect(window->total_rect, ColorInactiveWindow); } diff --git a/src/text_editor/globals.cpp b/src/text_editor/globals.cpp index a6090b9..5113218 100644 --- a/src/text_editor/globals.cpp +++ b/src/text_editor/globals.cpp @@ -81,7 +81,9 @@ Array Variables; Array ActiveProcesses = {}; Array ProcessEnviroment = {}; -Array ActiveCoroutines; + +struct CoData { mco_coro *co; String name; }; +Array ActiveCoroutines; /////////////////////////////// diff --git a/src/text_editor/profiler.h b/src/text_editor/profiler.h index f039f8f..991c302 100644 --- a/src/text_editor/profiler.h +++ b/src/text_editor/profiler.h @@ -364,7 +364,7 @@ SPALL_FN bool spall_buffer_name_process(SpallProfile *ctx, SpallBuffer *wb, cons static SpallProfile spall_ctx; static SpallBuffer spall_buffer; -double GetTimeMicros(void); +uint64_t GetTimeNanos(void); void BeginProfiler() { spall_init_file("te.spall", 1, &spall_ctx); @@ -386,14 +386,14 @@ void _BeginProfileScope(const char *name, int len) { spall_buffer_begin(&spall_ctx, &spall_buffer, name, // name of your name len, // name len minus the null terminator - (uint64_t)GetTimeMicros() // timestamp in microseconds -- start of your timing block + GetTimeNanos() // timestamp in microseconds -- start of your timing block ); } #define BeginProfileScope(name) _BeginProfileScope(#name, sizeof(#name) - 1) void EndProfileScope() { spall_buffer_end(&spall_ctx, &spall_buffer, - (uint64_t)GetTimeMicros() // timestamp in microseconds -- end of your timing block + GetTimeNanos() // timestamp in microseconds -- end of your timing block ); } #define ProfileScopeEx(name) ProfileScopeClass PROFILE_SCOPE_VAR_((name).data, (int)(name).len)