Optimize GarbageCollect and DebugWindowUpdate, bring back profiler

This commit is contained in:
krzosa
2025-12-22 17:44:21 +01:00
parent 6243cace7d
commit af1d88b07c
18 changed files with 568 additions and 117 deletions

View File

@@ -1,9 +1,7 @@
- What precise workflow do I need for me to be viable to use this? - 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? - From a user (novice) point of view, how does it look like?
- Close all (ask to save) - ctrl + p like in VSCode (without special buffers)
- Close buffer instead of window (ask to save)
- Open all in the folder and ctrl + p like in VSCode (without special buffers)
- Guide on the first page for new users with links to configs, tutorials - Guide on the first page for new users with links to configs, tutorials
- Window, View, Buffer + flags design (or is completely new kind based approach needed for Windows/Views?) - Window, View, Buffer + flags design (or is completely new kind based approach needed for Windows/Views?)

View File

@@ -1436,6 +1436,18 @@ bool IsNull(Buffer *buffer) {
return buffer->id.id == 0; return buffer->id.id == 0;
} }
void Close(BufferID id) {
Buffer *buffer = GetBuffer(id, NULL);
if (buffer) {
if (buffer->id.id == 0) {
return;
}
buffer->close = true;
RunGCThisFrame = true;
}
}
Buffer *CreateBuffer(Allocator allocator, String name, Int size) { Buffer *CreateBuffer(Allocator allocator, String name, Int size) {
Buffer *result = AllocBuffer(allocator, name, size); Buffer *result = AllocBuffer(allocator, name, size);
Add(&Buffers, result); Add(&Buffers, result);
@@ -1467,15 +1479,13 @@ void InitBuffers() {
Assert(null_buffer->id == NullBufferID && null_view->id == NullViewID); Assert(null_buffer->id == NullBufferID && null_view->id == NullViewID);
TraceBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "trace")); TraceBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "trace"));
TraceBuffer->special = true; TraceBuffer->special = true;
TraceView = CreateView(TraceBuffer->id); TraceBuffer->no_history = true;
GCInfoBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "gc")); GCInfoBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "gc"));
GCInfoBuffer->special = true; GCInfoBuffer->special = true;
GCInfoBuffer->no_history = true; GCInfoBuffer->no_history = true;
EventBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "events")); EventBuffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "events"));
EventBuffer->no_history = true; EventBuffer->no_history = true;
EventBuffer->special = true; EventBuffer->special = true;
ScratchBuffer = BufferOpenFile(GetUniqueBufferName(WorkDir, "scratch"));
ScratchBuffer->special = true;
} }
Int ConvertUTF8ToUTF16UnixLine(String string, char16_t *buffer, Int buffer_cap) { Int ConvertUTF8ToUTF16UnixLine(String string, char16_t *buffer, Int buffer_cap) {
@@ -1558,7 +1568,7 @@ bool BufferIsReferenced(BufferID buffer_id) {
return true; return true;
} }
if (FindView(buffer_id)) { if (FindView(buffer_id, NULL)) {
return true; return true;
} }

View File

@@ -40,7 +40,7 @@ struct Buffer {
unsigned changed_on_disk : 1; unsigned changed_on_disk : 1;
unsigned garbage : 1; unsigned garbage : 1;
unsigned dont_try_to_save_in_bulk_ops : 1; unsigned dont_try_to_save_in_bulk_ops : 1;
unsigned kill : 1; unsigned close : 1;
unsigned special : 1; unsigned special : 1;
}; };
}; };

View File

@@ -248,7 +248,7 @@ void ReportWarningf(const char *fmt, ...) {
void ReportDebugf(const char *fmt, ...) { void ReportDebugf(const char *fmt, ...) {
Scratch scratch; Scratch scratch;
STRING_FORMAT(scratch, fmt, string); STRING_FORMAT(scratch, fmt, string);
Appendf(TraceView, "%S\n", string); RawAppendf(TraceBuffer, "%S\n", string);
} }
void MoveCursorByPageSize(Window *window, int direction, bool shift = false) { void MoveCursorByPageSize(Window *window, int direction, bool shift = false) {
@@ -427,29 +427,6 @@ void NewDir(Window *window, String name = "") {
Open(name); Open(name);
} }
String CodeEndings[] = { ".c", ".cpp", ".h", ".hpp", ".py", ".lua", ".cxx", ".hxx", };
void ListFilesRecursive(Buffer *buffer, String dir) {
Scratch scratch(buffer->line_starts.allocator);
for (FileIter it = IterateFiles(scratch, dir); IsValid(it); Advance(&it)) {
if (it.filename == ".git") {
continue;
}
if (it.is_directory) {
ListFilesRecursive(buffer, it.absolute_path);
} else {
bool match = false;
ForItem (ending, CodeEndings) {
if (EndsWith(it.absolute_path, ending)) {
match = true;
break;
}
}
if (match) RawAppendf(buffer, "%-80S || %S\n", it.filename, it.absolute_path);
}
}
}
View *ExecHidden(String buffer_name, String cmd, String working_dir) { View *ExecHidden(String buffer_name, String cmd, String working_dir) {
View *view = OpenBufferView(buffer_name); View *view = OpenBufferView(buffer_name);
Buffer *buffer = GetBuffer(view->active_buffer); Buffer *buffer = GetBuffer(view->active_buffer);
@@ -668,14 +645,66 @@ void Command_SetWorkDir() {
WorkDir = ChopLastSlash(main.buffer->name); WorkDir = ChopLastSlash(main.buffer->name);
} RegisterCommand(Command_SetWorkDir, ""); } RegisterCommand(Command_SetWorkDir, "");
String CodeEndings[] = { ".c", ".cpp", ".h", ".hpp", ".py", ".lua", ".cxx", ".hxx", };
void ListFilesRecursive(Buffer *buffer, String dir) {
Scratch scratch(buffer->line_starts.allocator);
for (FileIter it = IterateFiles(scratch, dir); IsValid(it); Advance(&it)) {
if (it.filename == ".git") {
continue;
}
if (it.is_directory) {
ListFilesRecursive(buffer, it.absolute_path);
} else {
bool match = false;
ForItem (ending, CodeEndings) {
if (EndsWith(it.absolute_path, ending)) {
match = true;
break;
}
}
if (match) RawAppendf(buffer, "%-80S || %S\n", it.filename, it.absolute_path);
}
}
}
void OpenCodeRecursive(String dir) {
Scratch scratch;
for (FileIter it = IterateFiles(scratch, dir); IsValid(it); Advance(&it)) {
if (it.filename == ".git") {
continue;
}
if (it.filename == "SDL") {
continue;
}
if (it.is_directory) {
OpenCodeRecursive(it.absolute_path);
} else {
bool match = false;
ForItem (ending, CodeEndings) {
if (EndsWith(it.absolute_path, ending)) {
match = true;
break;
}
}
if (match) {
BufferOpenFile(it.absolute_path);
}
}
}
}
void Command_OpenCode() {
OpenCodeRecursive(WorkDir);
} RegisterCommand(Command_OpenCode, "");
void Command_KillProcess() { void Command_KillProcess() {
BSet main = GetBSet(LastActiveLayoutWindowID); BSet main = GetBSet(LastActiveLayoutWindowID);
KillProcess(main.view); KillProcess(main.view);
} RegisterCommand(Command_KillProcess, ""); } RegisterCommand(Command_KillProcess, "");
void Command_CloseWindow() { void Command_CloseWindow() {
BSet main = GetBSet(LastActiveLayoutWindowID); Close(LastActiveLayoutWindowID);
main.window->kill = true;
} RegisterCommand(Command_CloseWindow, ""); } RegisterCommand(Command_CloseWindow, "");
SaveResult TrySavingBuffer(Buffer *buffer) { SaveResult TrySavingBuffer(Buffer *buffer) {
@@ -717,7 +746,7 @@ void Command_Close() {
} }
main.window->active_view = FindInactiveView(); main.window->active_view = FindInactiveView();
main.view->kill = true; Close(main.view->id);
bool ref = false; bool ref = false;
For (Views) { For (Views) {
@@ -731,7 +760,7 @@ void Command_Close() {
} }
if (!ref) { if (!ref) {
main.buffer->kill = true; Close(main.buffer->id);
} }
} RegisterCommand(Command_Close, "ctrl-w"); } RegisterCommand(Command_Close, "ctrl-w");
@@ -747,13 +776,13 @@ void Command_CloseAll() {
if (it->special) { if (it->special) {
continue; continue;
} }
it->kill = true; Close(it->id);
} }
For (Buffers) { For (Buffers) {
if (it->special) { if (it->special) {
continue; continue;
} }
it->kill = true; Close(it->id);
} }
} }
} RegisterCommand(Command_CloseAll, ""); } RegisterCommand(Command_CloseAll, "");

View File

@@ -17,6 +17,7 @@ mco_coro *CoAdd(CoroutineProc *proc) {
} }
void CoUpdate(Event *event) { void CoUpdate(Event *event) {
ProfileFunction();
IterRemove(ActiveCoroutines) { IterRemove(ActiveCoroutines) {
IterRemovePrepare(ActiveCoroutines); IterRemovePrepare(ActiveCoroutines);

View File

@@ -100,6 +100,7 @@ void DrawUnderline(Window *window, View *view, Buffer *buffer, Range range, Colo
} }
void DrawWindow(Window *window, Event &event) { void DrawWindow(Window *window, Event &event) {
ProfileFunction();
View *view = GetView(window->active_view); View *view = GetView(window->active_view);
Buffer *buffer = GetBuffer(view->active_buffer); Buffer *buffer = GetBuffer(view->active_buffer);
Rect2 screen_rect = Rect0Size(event.xwindow, event.ywindow); Rect2 screen_rect = Rect0Size(event.xwindow, event.ywindow);

View File

@@ -5,6 +5,7 @@ int FullScreenPositionX, FullScreenPositionY;
bool Testing = false; bool Testing = false;
bool AppIsRunning = true; bool AppIsRunning = true;
bool WaitForEvents = true; bool WaitForEvents = true;
bool RunGCThisFrame;
WindowID WindowIDs; WindowID WindowIDs;
ViewID ViewIDs; ViewID ViewIDs;
@@ -40,7 +41,6 @@ Caret DocumentAnchor;
Buffer *GCInfoBuffer; Buffer *GCInfoBuffer;
Buffer *EventBuffer; Buffer *EventBuffer;
Buffer *ScratchBuffer;
Buffer *TraceBuffer; Buffer *TraceBuffer;
View *TraceView; View *TraceView;
@@ -50,8 +50,8 @@ Array<Event> EventPlayback;
BlockArena Perm; BlockArena Perm;
// clipboard // clipboard
BlockArena ClipboardArena; BlockArena ClipboardArena;
String16 SavedClipboardString; String16 SavedClipboardString;
Array<String16> SavedClipboardCarets = {SysAllocator}; Array<String16> SavedClipboardCarets = {SysAllocator};
struct InternTable { struct InternTable {

View File

@@ -5,6 +5,7 @@
// 'less' program which errors out and doesn't print anything // 'less' program which errors out and doesn't print anything
// @todo: maybe I should ask someone smarter about this! // @todo: maybe I should ask someone smarter about this!
void UpdateProcesses() { void UpdateProcesses() {
ProfileFunction();
IterRemove(ActiveProcesses) { IterRemove(ActiveProcesses) {
IterRemovePrepare(ActiveProcesses); IterRemovePrepare(ActiveProcesses);
Scratch scratch; Scratch scratch;

View File

@@ -1,12 +1,373 @@
#if 0 #if 1
#include "spall.h" // SPDX-FileCopyrightText: © 2023 Phillip Trudeau-Tavara <pmttavara@protonmail.com>
// SPDX-License-Identifier: MIT
/*
TODO: Optional Helper APIs:
- Compression API: would require a mutexed lockable context (yuck...)
- Either using a ZIP library, a name cache + TIDPID cache, or both (but ZIP is likely more than enough!!!)
- begin()/end() writes compressed chunks to a caller-determined destination
- The destination can be the buffered-writing API or a custom user destination
- Ultimately need to take a lock with some granularity... can that be the caller's responsibility?
- Counter Event: should allow tracking arbitrary named values with a single event, for memory and frame profiling
- Ring-buffer API
spall_ring_init
spall_ring_emit_begin
spall_ring_emit_end
spall_ring_flush
*/
#ifndef SPALL_H
#define SPALL_H
#if !defined(_MSC_VER) || defined(__clang__)
#define SPALL_NOINSTRUMENT __attribute__((no_instrument_function))
#define SPALL_FORCEINLINE __attribute__((always_inline))
#else
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#define SPALL_NOINSTRUMENT // Can't noinstrument on MSVC!
#define SPALL_FORCEINLINE __forceinline
#endif
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define SPALL_FN static inline SPALL_NOINSTRUMENT
#define SPALL_MIN(a, b) (((a) < (b)) ? (a) : (b))
#define SPALL_MAX(a, b) (((a) > (b)) ? (a) : (b))
#pragma pack(push, 1)
typedef struct SpallHeader {
uint64_t magic_header; // = 0x0BADF00D
uint64_t version; // = 3
double timestamp_unit;
uint64_t must_be_0;
} SpallHeader;
typedef enum {
SpallEventType_Invalid = 0,
SpallEventType_Custom_Data = 1, // Basic readers can skip this.
SpallEventType_StreamOver = 2,
SpallEventType_Begin = 3,
SpallEventType_End = 4,
SpallEventType_Instant = 5,
SpallEventType_Overwrite_Timestamp = 6, // Retroactively change timestamp units - useful for incrementally improving RDTSC frequency.
SpallEventType_Pad_Skip = 7,
SpallEventType_NameProcess = 8,
SpallEventType_NameThread = 9,
} SpallEventType;
typedef struct SpallBufferHeader {
uint32_t size;
uint32_t tid;
uint32_t pid;
uint64_t first_ts;
} SpallBufferHeader;
typedef struct SpallBeginEvent {
uint8_t type; // = SpallEventType_Begin
uint64_t when;
uint8_t name_length;
uint8_t args_length;
} SpallBeginEvent;
typedef struct SpallBeginEventMax {
SpallBeginEvent event;
char name_bytes[255];
char args_bytes[255];
} SpallBeginEventMax;
typedef struct SpallEndEvent {
uint8_t type; // = SpallEventType_End
uint64_t when;
} SpallEndEvent;
typedef struct SpallPadSkipEvent {
uint8_t type; // = SpallEventType_Pad_Skip
uint32_t size;
} SpallPadSkipEvent;
typedef struct SpallNameContainerEvent {
uint8_t type; // = SpallEventType_NameThread/Process
uint8_t name_length;
} SpallNameContainerEvent;
typedef struct SpallNameContainerEventMax {
SpallNameContainerEvent event;
char name_bytes[255];
} SpallNameContainerEventMax;
#pragma pack(pop)
typedef struct SpallProfile SpallProfile;
// Important!: If you define your own callbacks, mark them SPALL_NOINSTRUMENT!
typedef bool (*SpallWriteCallback)(SpallProfile *self, const void *data, size_t length);
typedef bool (*SpallFlushCallback)(SpallProfile *self);
typedef void (*SpallCloseCallback)(SpallProfile *self);
struct SpallProfile {
double timestamp_unit;
SpallWriteCallback write;
SpallFlushCallback flush;
SpallCloseCallback close;
void *data;
};
// Important!: If you are writing Begin/End events, then do NOT write
// events for the same PID + TID pair on different buffers!!!
typedef struct SpallBuffer {
void *data;
size_t length;
uint32_t tid;
uint32_t pid;
// Internal data - don't assign this
size_t head;
uint64_t first_ts;
} SpallBuffer;
#ifdef __cplusplus
extern "C" {
#endif
SPALL_FN SPALL_FORCEINLINE bool spall__file_write(SpallProfile *ctx, const void *p, size_t n) {
if (fwrite(p, n, 1, (FILE *)ctx->data) != 1) return false;
return true;
}
SPALL_FN bool spall__file_flush(SpallProfile *ctx) {
if (fflush((FILE *)ctx->data)) return false;
return true;
}
SPALL_FN void spall__file_close(SpallProfile *ctx) {
fclose((FILE *)ctx->data);
ctx->data = NULL;
}
SPALL_FN SPALL_FORCEINLINE bool spall__buffer_flush(SpallProfile *ctx, SpallBuffer *wb, uint64_t ts) {
wb->first_ts = SPALL_MAX(wb->first_ts, ts);
SpallBufferHeader hdr;
hdr.size = (uint32_t)(wb->head - sizeof(SpallBufferHeader));
hdr.pid = wb->pid;
hdr.tid = wb->tid;
hdr.first_ts = wb->first_ts;
memcpy(wb->data, &hdr, sizeof(hdr));
if (!ctx->write(ctx, wb->data, wb->head)) return false;
if (!ctx->flush(ctx)) return false;
wb->head = sizeof(SpallBufferHeader);
return true;
}
SPALL_FN bool spall_buffer_flush(SpallProfile *ctx, SpallBuffer *wb) {
if (!spall__buffer_flush(ctx, wb, 0)) return false;
return true;
}
SPALL_FN bool spall_buffer_quit(SpallProfile *ctx, SpallBuffer *wb) {
if (!spall_buffer_flush(ctx, wb)) return false;
return true;
}
SPALL_FN size_t spall_build_header(void *buffer, size_t rem_size, double timestamp_unit) {
size_t header_size = sizeof(SpallHeader);
if (header_size > rem_size) {
return 0;
}
SpallHeader *header = (SpallHeader *)buffer;
header->magic_header = 0x0BADF00D;
header->version = 3;
header->timestamp_unit = timestamp_unit;
header->must_be_0 = 0;
return header_size;
}
SPALL_FN SPALL_FORCEINLINE size_t spall_build_begin(void *buffer, size_t rem_size, const char *name, int32_t name_len, const char *args, int32_t args_len, uint64_t when) {
SpallBeginEventMax *ev = (SpallBeginEventMax *)buffer;
uint8_t trunc_name_len = (uint8_t)SPALL_MIN(name_len, 255); // will be interpreted as truncated in the app (?)
uint8_t trunc_args_len = (uint8_t)SPALL_MIN(args_len, 255); // will be interpreted as truncated in the app (?)
size_t ev_size = sizeof(SpallBeginEvent) + trunc_name_len + trunc_args_len;
if (ev_size > rem_size) {
return 0;
}
ev->event.type = SpallEventType_Begin;
ev->event.when = when;
ev->event.name_length = trunc_name_len;
ev->event.args_length = trunc_args_len;
memcpy(ev->name_bytes, name, trunc_name_len);
memcpy(ev->name_bytes + trunc_name_len, args, trunc_args_len);
return ev_size;
}
SPALL_FN SPALL_FORCEINLINE size_t spall_build_end(void *buffer, size_t rem_size, uint64_t when) {
size_t ev_size = sizeof(SpallEndEvent);
if (ev_size > rem_size) {
return 0;
}
SpallEndEvent *ev = (SpallEndEvent *)buffer;
ev->type = SpallEventType_End;
ev->when = when;
return ev_size;
}
SPALL_FN SPALL_FORCEINLINE size_t spall_build_name(void *buffer, size_t rem_size, const char *name, int32_t name_len, SpallEventType type) {
SpallNameContainerEventMax *ev = (SpallNameContainerEventMax *)buffer;
uint8_t trunc_name_len = (uint8_t)SPALL_MIN(name_len, 255); // will be interpreted as truncated in the app (?)
size_t ev_size = sizeof(SpallNameContainerEvent) + trunc_name_len;
if (ev_size > rem_size) {
return 0;
}
ev->event.type = type;
ev->event.name_length = trunc_name_len;
memcpy(ev->name_bytes, name, trunc_name_len);
return ev_size;
}
SPALL_FN void spall_quit(SpallProfile *ctx) {
if (!ctx) return;
if (ctx->close) ctx->close(ctx);
memset(ctx, 0, sizeof(*ctx));
}
SPALL_FN bool spall_init_callbacks(double timestamp_unit,
SpallWriteCallback write,
SpallFlushCallback flush,
SpallCloseCallback close,
void *userdata,
SpallProfile *ctx) {
if (timestamp_unit < 0) return false;
memset(ctx, 0, sizeof(*ctx));
ctx->timestamp_unit = timestamp_unit;
ctx->data = userdata;
ctx->write = write;
ctx->flush = flush;
ctx->close = close;
SpallHeader header;
size_t len = spall_build_header(&header, sizeof(header), timestamp_unit);
if (!ctx->write(ctx, &header, len)) {
spall_quit(ctx);
return false;
}
return true;
}
SPALL_FN bool spall_init_file(const char* filename, double timestamp_unit, SpallProfile *ctx) {
if (!filename) return false;
FILE *f = fopen(filename, "wb"); // TODO: handle utf8 and long paths on windows
if (f) { // basically freopen() but we don't want to force users to lug along another macro define
fclose(f);
f = fopen(filename, "ab");
}
if (!f) { return false; }
return spall_init_callbacks(timestamp_unit, spall__file_write, spall__file_flush, spall__file_close, (void *)f, ctx);
}
SPALL_FN bool spall_flush(SpallProfile *ctx) {
if (!ctx->flush(ctx)) return false;
return true;
}
SPALL_FN bool spall_buffer_init(SpallProfile *ctx, SpallBuffer *wb) {
// Fails if buffer is not big enough to contain at least one event!
if (wb->length < sizeof(SpallBufferHeader) + sizeof(SpallBeginEventMax)) {
return false;
}
wb->head = sizeof(SpallBufferHeader);
return true;
}
SPALL_FN SPALL_FORCEINLINE bool spall_buffer_begin_args(SpallProfile *ctx, SpallBuffer *wb, const char *name, int32_t name_len, const char *args, int32_t args_len, uint64_t when) {
if ((wb->head + sizeof(SpallBeginEventMax)) > wb->length) {
if (!spall__buffer_flush(ctx, wb, when)) {
return false;
}
}
wb->head += spall_build_begin((char *)wb->data + wb->head, wb->length - wb->head, name, name_len, args, args_len, when);
return true;
}
SPALL_FN bool spall_buffer_begin(SpallProfile *ctx, SpallBuffer *wb, const char *name, int32_t name_len, uint64_t when) {
return spall_buffer_begin_args(ctx, wb, name, name_len, "", 0, when);
}
SPALL_FN bool spall_buffer_end(SpallProfile *ctx, SpallBuffer *wb, uint64_t when) {
if ((wb->head + sizeof(SpallEndEvent)) > wb->length) {
if (!spall__buffer_flush(ctx, wb, when)) {
return false;
}
}
wb->head += spall_build_end((char *)wb->data + wb->head, wb->length - wb->head, when);
return true;
}
SPALL_FN bool spall_buffer_name_thread(SpallProfile *ctx, SpallBuffer *wb, const char *name, int32_t name_len) {
if ((wb->head + sizeof(SpallNameContainerEvent)) > wb->length) {
if (!spall__buffer_flush(ctx, wb, 0)) {
return false;
}
}
wb->head += spall_build_name((char *)wb->data + wb->head, wb->length - wb->head, name, name_len, SpallEventType_NameThread);
return true;
}
SPALL_FN bool spall_buffer_name_process(SpallProfile *ctx, SpallBuffer *wb, const char *name, int32_t name_len) {
if ((wb->head + sizeof(SpallNameContainerEvent)) > wb->length) {
if (!spall__buffer_flush(ctx, wb, 0)) {
return false;
}
}
wb->head += spall_build_name((char *)wb->data + wb->head, wb->length - wb->head, name, name_len, SpallEventType_NameProcess);
return true;
}
#ifdef __cplusplus
}
#endif
#endif // SPALL_H
static SpallProfile spall_ctx; static SpallProfile spall_ctx;
static SpallBuffer spall_buffer; static SpallBuffer spall_buffer;
double GetTimeMicros(void); double GetTimeMicros(void);
void BeginProfiler() { void BeginProfiler() {
spall_ctx = spall_init_file("hello_world.spall", 1); spall_init_file("te.spall", 1, &spall_ctx);
int buffer_size = 1 * 1024 * 1024; int buffer_size = 1 * 1024 * 1024;
unsigned char *buffer = (unsigned char *)malloc(buffer_size); unsigned char *buffer = (unsigned char *)malloc(buffer_size);
@@ -25,14 +386,14 @@ void _BeginProfileScope(const char *name, int len) {
spall_buffer_begin(&spall_ctx, &spall_buffer, spall_buffer_begin(&spall_ctx, &spall_buffer,
name, // name of your name name, // name of your name
len, // name len minus the null terminator len, // name len minus the null terminator
GetTimeMicros() // timestamp in microseconds -- start of your timing block (uint64_t)GetTimeMicros() // timestamp in microseconds -- start of your timing block
); );
} }
#define BeginProfileScope(name) _BeginProfileScope(#name, sizeof(#name) - 1) #define BeginProfileScope(name) _BeginProfileScope(#name, sizeof(#name) - 1)
void EndProfileScope() { void EndProfileScope() {
spall_buffer_end(&spall_ctx, &spall_buffer, spall_buffer_end(&spall_ctx, &spall_buffer,
GetTimeMicros() // timestamp in microseconds -- end of your timing block (uint64_t)GetTimeMicros() // timestamp in microseconds -- end of your timing block
); );
} }
#define ProfileScope(name) ProfileScope_ PROFILE_SCOPE_VAR_##name(#name, sizeof(#name) - 1) #define ProfileScope(name) ProfileScope_ PROFILE_SCOPE_VAR_##name(#name, sizeof(#name) - 1)

View File

@@ -412,32 +412,20 @@ void OnCommand(Event event) {
if (event.kind == EVENT_QUIT) { if (event.kind == EVENT_QUIT) {
Command_Quit(); Command_Quit();
} }
IF_DEBUG(AssertRanges(main.view->carets));
IF_DEBUG(AssertRanges(active.view->carets));
} }
void GarbageCollect() { void GarbageCollect() {
if (RunGCThisFrame == false) {
return;
}
RunGCThisFrame = false;
ProfileFunction();
Allocator sys_allocator = GetSystemAllocator(); Allocator sys_allocator = GetSystemAllocator();
For (Views) {
IF_DEBUG(AssertRanges(it->carets));
}
For (Windows) {
if (it->sync_visibility_with_focus) {
if (it->id == ActiveWindowID) {
it->visible = true;
} else {
it->visible = false;
}
}
}
Window *window = GetWindow(ActiveWindowID);
if (ActiveWindowID.id != LastActiveLayoutWindowID.id) {
if (window->layout) {
LastActiveLayoutWindowID = ActiveWindowID;
}
}
For(Buffers) { For(Buffers) {
if (it->file_mod_time) { if (it->file_mod_time) {
int64_t new_file_mod_time = GetFileModTime(it->name); int64_t new_file_mod_time = GetFileModTime(it->name);
@@ -451,8 +439,12 @@ void GarbageCollect() {
IterRemove(Views) { IterRemove(Views) {
IterRemovePrepare(Views); IterRemovePrepare(Views);
if (it->close && it->id.id == 0) {
InvalidCodepath();
}
Buffer *buffer = GetBuffer(it->active_buffer); Buffer *buffer = GetBuffer(it->active_buffer);
if (it->kill == 0) { if (!it->close) {
if (!buffer->garbage) { if (!buffer->garbage) {
continue; continue;
} }
@@ -472,13 +464,11 @@ void GarbageCollect() {
IterRemove(Buffers) { IterRemove(Buffers) {
IterRemovePrepare(Buffers); IterRemovePrepare(Buffers);
if (it->close && it->id.id == 0) {
if (it->id.id == 0) { InvalidCodepath();
it->kill = 0;
continue;
} }
if (it->kill == 0) { if (!it->close) {
if (!it->garbage) { if (!it->garbage) {
continue; continue;
} }
@@ -496,7 +486,11 @@ void GarbageCollect() {
IterRemove(Windows) { IterRemove(Windows) {
IterRemovePrepare(Windows); IterRemovePrepare(Windows);
if (it->kill) { if (it->close && it->id.id == 0) {
InvalidCodepath();
}
if (it->close) {
RawAppendf(GCInfoBuffer, "Wind %d %S\n", (int)it->id.id); RawAppendf(GCInfoBuffer, "Wind %d %S\n", (int)it->id.id);
Dealloc(&it->goto_history); Dealloc(&it->goto_history);
Dealloc(&it->goto_redo); Dealloc(&it->goto_redo);
@@ -512,10 +506,12 @@ void Update(Event event) {
Scratch scratch; Scratch scratch;
Array<Window *> order = GetWindowZOrder(scratch); Array<Window *> order = GetWindowZOrder(scratch);
For(order) { For(order) {
if (!it->visible) continue; if (!it->visible) {
View *view = GetView(it->active_view); continue;
}
View *view = GetView(it->active_view);
view->main_caret_on_begin_frame = view->carets[0]; view->main_caret_on_begin_frame = view->carets[0];
view->update_scroll = true; view->update_scroll = true;
} }
OnCommand(event); OnCommand(event);
@@ -524,7 +520,27 @@ void Update(Event event) {
CommandWindowUpdate(); CommandWindowUpdate();
UpdateProcesses(); UpdateProcesses();
CoUpdate(&event); CoUpdate(&event);
GarbageCollect();
{
ProfileScope(WindowEndOfFrameVisibilityAndLastActive);
For (Windows) {
if (it->sync_visibility_with_focus) {
if (it->id == ActiveWindowID) {
it->visible = true;
} else {
it->visible = false;
}
}
}
Window *window = GetWindow(ActiveWindowID);
if (ActiveWindowID.id != LastActiveLayoutWindowID.id) {
if (window->layout) {
LastActiveLayoutWindowID = ActiveWindowID;
}
}
}
For(IterateInReverse(&order)) { For(IterateInReverse(&order)) {
if (!it->visible) continue; if (!it->visible) continue;
@@ -532,6 +548,8 @@ void Update(Event event) {
View *view = GetView(it->active_view); View *view = GetView(it->active_view);
UpdateScroll(it, !AreEqual(view->main_caret_on_begin_frame, view->carets[0]) && view->update_scroll); UpdateScroll(it, !AreEqual(view->main_caret_on_begin_frame, view->carets[0]) && view->update_scroll);
} }
GarbageCollect();
} }
void Windows_SetupVCVarsall(mco_coro *co) { void Windows_SetupVCVarsall(mco_coro *co) {
@@ -564,9 +582,9 @@ void Windows_SetupVCVarsall(mco_coro *co) {
} }
void MainLoop() { void MainLoop() {
ProfileFunction();
Scratch scratch;
FrameID += 1; FrameID += 1;
Scratch scratch;
Array<Event> frame_events = GetEventsForFrame(scratch); Array<Event> frame_events = GetEventsForFrame(scratch);
Serializer ser = {EventBuffer}; Serializer ser = {EventBuffer};
For(frame_events) { For(frame_events) {

View File

@@ -80,6 +80,17 @@ API bool ViewIsReferenced(ViewID view) {
return ViewIsActive(view); return ViewIsActive(view);
} }
void Close(ViewID id) {
View *view = GetView(id);
if (view) {
if (view->id.id == 0) {
return;
}
view->close = true;
RunGCThisFrame = true;
}
}
ViewID FindInactiveView(ViewID default_view = NullViewID) { ViewID FindInactiveView(ViewID default_view = NullViewID) {
For (Views) { For (Views) {
if (!ViewIsActive(it->id)) return it->id; if (!ViewIsActive(it->id)) return it->id;

View File

@@ -13,7 +13,7 @@ struct View {
String16 prev_search_line; String16 prev_search_line;
struct { struct {
unsigned kill : 1; unsigned close : 1;
unsigned special : 1; unsigned special : 1;
}; };
}; };

View File

@@ -18,13 +18,24 @@ Window *CreateWind() {
return w; return w;
} }
inline Window *GetWindow(WindowID id, Window *default_window = Windows[0]) { Window *GetWindow(WindowID id, Window *default_window = Windows[0]) {
For(Windows) { For(Windows) {
if (it->id == id) return it; if (it->id == id) return it;
} }
return default_window; return default_window;
} }
void Close(WindowID id) {
Window *window = GetWindow(id, NULL);
if (window) {
if (window->id.id == 0) {
return;
}
window->close = true;
RunGCThisFrame = true;
}
}
Window *FindWindow(ViewID view_id, Window *default_window = NULL) { Window *FindWindow(ViewID view_id, Window *default_window = NULL) {
For(Windows) { For(Windows) {
if (it->active_view == view_id) { if (it->active_view == view_id) {
@@ -36,7 +47,7 @@ Window *FindWindow(ViewID view_id, Window *default_window = NULL) {
Window *FindWindow(String buffer_name, Window *default_window = NULL) { Window *FindWindow(String buffer_name, Window *default_window = NULL) {
For(Windows) { For(Windows) {
View *it_view = GetView(it->active_view); View *it_view = GetView(it->active_view);
Buffer *it_buffer = GetBuffer(it_view->active_buffer); Buffer *it_buffer = GetBuffer(it_view->active_buffer);
if (it_buffer->name == buffer_name) { if (it_buffer->name == buffer_name) {
return it; return it;
@@ -136,6 +147,7 @@ double WindowCalcEvenResizerValue(Int screen_size_x, Int *out_count = NULL) {
} }
void LayoutWindows(int16_t wx, int16_t wy) { void LayoutWindows(int16_t wx, int16_t wy) {
ProfileFunction();
Rect2I screen_rect = RectI0Size(wx, wy); Rect2I screen_rect = RectI0Size(wx, wy);
CommandWindowLayout(&screen_rect, wx, wy); CommandWindowLayout(&screen_rect, wx, wy);
@@ -237,8 +249,10 @@ void CheckpointBeforeGoto(Window *window) {
GotoCrumb GetCrumb(Array<GotoCrumb> *cr) { GotoCrumb GetCrumb(Array<GotoCrumb> *cr) {
for (; cr->len;) { for (; cr->len;) {
GotoCrumb c = Pop(cr); GotoCrumb c = Pop(cr);
View *view = FindView(c.view_id); View *view = GetView(c.view_id);
if (view) return c; if (view) {
return c;
}
} }
return {}; return {};
} }

View File

@@ -30,7 +30,7 @@ struct Window {
bool draw_line_highlight : 1; bool draw_line_highlight : 1;
bool visible : 1; bool visible : 1;
bool layout : 1; bool layout : 1;
bool kill : 1; bool close : 1;
bool sync_visibility_with_focus : 1; bool sync_visibility_with_focus : 1;
bool lose_focus_on_escape : 1; bool lose_focus_on_escape : 1;
bool jump_history : 1; bool jump_history : 1;

View File

@@ -28,6 +28,7 @@ void CommandWindowLayout(Rect2I *rect, Int wx, Int wy) {
} }
void CommandWindowUpdate() { void CommandWindowUpdate() {
ProfileFunction();
BSet active = GetBSet(ActiveWindowID); BSet active = GetBSet(ActiveWindowID);
if (active.window->id == CommandBarWindowID) { if (active.window->id == CommandBarWindowID) {
if (!ProcessIsActive(active.view->id)) { if (!ProcessIsActive(active.view->id)) {

View File

@@ -31,46 +31,51 @@ void DebugWindowLayout(Rect2I *rect, Int wx, Int wy) {
} }
void DebugWindowUpdate() { void DebugWindowUpdate() {
Buffer *buffer = GetBuffer(DebugBufferID); ProfileFunction();
BSet set = GetBSet(DebugWindowID);
if (!set.window->visible) {
return;
}
Window *window = GetActiveWind(); BSet active = GetBSet(ActiveWindowID);
View *view = GetView(window->active_view); if (active.buffer->id.id == set.buffer->id.id) {
if (view->active_buffer.id == buffer->id.id) return; return;
}
BSet main = GetBSet(LastActiveLayoutWindowID); BSet main = GetBSet(LastActiveLayoutWindowID);
Scratch scratch; Scratch scratch;
String s = Format(scratch, "wid: %d\nvid: %d\nbid: %d\nframe: %lld\n", (int)main.window->id.id, (int)main.view->id.id, (int)main.buffer->id.id, (long long)FrameID); String s = Format(scratch, "wid: %d\nvid: %d\nbid: %d\nframe: %lld\n", (int)main.window->id.id, (int)main.view->id.id, (int)main.buffer->id.id, (long long)FrameID);
String16 string = ToString16(scratch, s); String16 string = ToString16(scratch, s);
RawReplaceText(buffer, GetRange(buffer), string); RawReplaceText(set.buffer, GetRange(set.buffer), string);
float xmouse, ymouse; float xmouse, ymouse;
SDL_GetMouseState(&xmouse, &ymouse); SDL_GetMouseState(&xmouse, &ymouse);
RawAppendf(buffer, "mouse: [%f, %f]\n", roundf(DPIScale * xmouse), roundf(DPIScale * ymouse)); RawAppendf(set.buffer, "mouse: [%f, %f]\n", roundf(DPIScale * xmouse), roundf(DPIScale * ymouse));
RawAppendf(buffer, "BufferID id = %d\n", main.buffer->id.id); RawAppendf(set.buffer, "BufferID id = %d\n", main.buffer->id.id);
RawAppendf(buffer, "String name = %S\n", main.buffer->name); RawAppendf(set.buffer, "String name = %S\n", main.buffer->name);
RawAppendf(buffer, "Int change_id = %lld\n", (long long)main.buffer->change_id); RawAppendf(set.buffer, "Int change_id = %lld\n", (long long)main.buffer->change_id);
RawAppendf(buffer, "Int user_change_id = %lld\n", (long long)main.buffer->user_change_id); RawAppendf(set.buffer, "Int user_change_id = %lld\n", (long long)main.buffer->user_change_id);
RawAppendf(buffer, "Int file_mod_time = %lld\n", (long long)main.buffer->file_mod_time); RawAppendf(set.buffer, "Int file_mod_time = %lld\n", (long long)main.buffer->file_mod_time);
RawAppendf(buffer, "\n"); RawAppendf(set.buffer, "\n");
RawAppendf(buffer, "U16 *data = %zu\n", main.buffer->data); RawAppendf(set.buffer, "U16 *data = %zu\n", main.buffer->data);
RawAppendf(buffer, "Int len = %lld\n", (long long)main.buffer->len); RawAppendf(set.buffer, "Int len = %lld\n", (long long)main.buffer->len);
RawAppendf(buffer, "Int cap = %lld\n", (long long)main.buffer->cap); RawAppendf(set.buffer, "Int cap = %lld\n", (long long)main.buffer->cap);
RawAppendf(buffer, "Array<Int> line_starts = {len = %lld, cap = %lld, data = %zu}\n", (long long)main.buffer->line_starts.len, (long long)main.buffer->line_starts.cap, main.buffer->line_starts.data); RawAppendf(set.buffer, "Array<Int> line_starts = {len = %lld, cap = %lld, data = %zu}\n", (long long)main.buffer->line_starts.len, (long long)main.buffer->line_starts.cap, main.buffer->line_starts.data);
RawAppendf(buffer, "\n"); RawAppendf(set.buffer, "\n");
RawAppendf(buffer, "Array<HistoryEntry> undo_stack = {len = %lld, cap = %lld, data = %zu}\n", (long long)main.buffer->undo_stack.len, (long long)main.buffer->undo_stack.cap, main.buffer->undo_stack.data); RawAppendf(set.buffer, "Array<HistoryEntry> undo_stack = {len = %lld, cap = %lld, data = %zu}\n", (long long)main.buffer->undo_stack.len, (long long)main.buffer->undo_stack.cap, main.buffer->undo_stack.data);
RawAppendf(buffer, "Array<HistoryEntry> redo_stack = {len = %lld, cap = %lld, data = %zu}\n", (long long)main.buffer->redo_stack.len, (long long)main.buffer->redo_stack.cap, main.buffer->redo_stack.data); RawAppendf(set.buffer, "Array<HistoryEntry> redo_stack = {len = %lld, cap = %lld, data = %zu}\n", (long long)main.buffer->redo_stack.len, (long long)main.buffer->redo_stack.cap, main.buffer->redo_stack.data);
RawAppendf(buffer, "int edit_phase = %d", main.buffer->edit_phase); RawAppendf(set.buffer, "int edit_phase = %d", main.buffer->edit_phase);
RawAppendf(buffer, "\n"); RawAppendf(set.buffer, "\n");
RawAppendf(buffer, "int no_history = %d\n", main.buffer->no_history); RawAppendf(set.buffer, "int no_history = %d\n", main.buffer->no_history);
RawAppendf(buffer, "int no_line_starts = %d\n", main.buffer->no_line_starts); RawAppendf(set.buffer, "int no_line_starts = %d\n", main.buffer->no_line_starts);
RawAppendf(buffer, "int dirty = %d\n", main.buffer->dirty); RawAppendf(set.buffer, "int dirty = %d\n", main.buffer->dirty);
RawAppendf(buffer, "int changed_on_disk = %d\n", main.buffer->changed_on_disk); RawAppendf(set.buffer, "int changed_on_disk = %d\n", main.buffer->changed_on_disk);
RawAppendf(buffer, "int garbage = %d\n", main.buffer->garbage); RawAppendf(set.buffer, "int garbage = %d\n", main.buffer->garbage);
} }
void Command_ToggleDebug() { void Command_ToggleDebug() {

View File

@@ -25,6 +25,7 @@ void StatusWindowLayout(Rect2I *rect, Int wx, Int wy) {
} }
void StatusWindowUpdate() { void StatusWindowUpdate() {
ProfileFunction();
Window *status_bar_window = GetWindow(StatusBarWindowID, NULL); Window *status_bar_window = GetWindow(StatusBarWindowID, NULL);
if (status_bar_window == NULL) { if (status_bar_window == NULL) {
return; return;