From f201231f52c3f81cb7f22d1f59069b1c7675b086 Mon Sep 17 00:00:00 2001 From: nakst <> Date: Sat, 4 Dec 2021 12:00:10 +0000 Subject: [PATCH] misc changes --- arch/x86_64/kernel.cpp | 4 +++ arch/x86_pc.cpp | 9 ++++++ desktop/api.cpp | 15 ++++++--- desktop/gui.cpp | 10 ------ desktop/list_view.cpp | 2 +- desktop/os.header | 3 +- desktop/posix.cpp | 2 +- desktop/profiling.cpp | 70 ++++++++++++++++++++---------------------- desktop/text.cpp | 7 ++--- kernel/scheduler.cpp | 7 ++++- kernel/syscall.cpp | 7 ++++- util/build_core.c | 4 +-- util/luigi.h | 26 ++++++++++++++-- 13 files changed, 100 insertions(+), 66 deletions(-) diff --git a/arch/x86_64/kernel.cpp b/arch/x86_64/kernel.cpp index 36d0b75..3470f58 100644 --- a/arch/x86_64/kernel.cpp +++ b/arch/x86_64/kernel.cpp @@ -382,6 +382,10 @@ extern "C" void InterruptHandler(InterruptContext *context) { CPULocalStorage *local = GetLocalStorage(); uintptr_t interrupt = context->interruptNumber; + if (local && local->currentThread) { + local->currentThread->lastInterruptTimeStamp = ProcessorReadTimeStamp(); + } + if (local && local->spinlockCount && context->cr8 != 0xE) { KernelPanic("InterruptHandler - Local spinlockCount is %d but interrupts were enabled (%x/%x).\n", local->spinlockCount, local, context); } diff --git a/arch/x86_pc.cpp b/arch/x86_pc.cpp index 580b1d8..3b62ba6 100644 --- a/arch/x86_pc.cpp +++ b/arch/x86_pc.cpp @@ -823,6 +823,15 @@ extern "C" bool PostContextSwitch(InterruptContext *context, MMSpace *oldAddress KernelPanic("PostContextSwitch - spinlockCount is non-zero (%x).\n", local); } + currentThread->timerAdjustTicks += ProcessorReadTimeStamp() - local->currentThread->lastInterruptTimeStamp; + + if (currentThread->timerAdjustAddress && MMArchIsBufferInUserRange(currentThread->timerAdjustAddress, sizeof(uint64_t))) { + // TODO If the MMArchSafeCopy fails, then the kernel will panic because interrupts are disabled here. + // We probably need a special version of MMArchSafeCopy that doesn't try to resolve page faults and fails faster. + // TODO Instead of timerAdjustAddress, maybe copy it onto a fixed location at the base of thread's stack? + MMArchSafeCopy(currentThread->timerAdjustAddress, (uintptr_t) &local->currentThread->timerAdjustTicks, sizeof(uint64_t)); + } + #ifdef ES_ARCH_X86_32 if (context->fromRing0) { // Returning to a kernel thread; we need to fix the stack. diff --git a/desktop/api.cpp b/desktop/api.cpp index b2cbed4..4bd6bf8 100644 --- a/desktop/api.cpp +++ b/desktop/api.cpp @@ -90,6 +90,7 @@ struct ThreadLocalStorage { ThreadLocalStorage *self; EsObjectID id; + uint64_t timerAdjustTicks; }; struct MountPoint : EsMountPoint { @@ -1105,13 +1106,12 @@ EsMessage *EsMessageReceive() { ProcessMessageTiming timing = {}; double start = EsTimeStampMs(); UIProcessWindowManagerMessage((EsWindow *) message.object, &message.message, &timing); - EsPrint("Processed message from WM %x in %Fms (%Fms logic, %Fms layout, %Fms paint, %Fms update screen). Profiling buffer %F%% full.\n", + EsPrint("Processed message from WM %x in %Fms (%Fms logic, %Fms layout, %Fms paint, %Fms update screen).\n", type, EsTimeStampMs() - start, timing.endLogic - timing.startLogic, timing.endLayout - timing.startLayout, timing.endPaint - timing.startPaint, - timing.endUpdate - timing.startUpdate, - profilingBufferSize ? profilingBufferPosition * 100.0 / profilingBufferSize : 0); + timing.endUpdate - timing.startUpdate); #else UIProcessWindowManagerMessage((EsWindow *) message.object, &message.message, nullptr); #endif @@ -1474,7 +1474,8 @@ void ThreadInitialise(ThreadLocalStorage *local) { EsMemoryZero(local, sizeof(ThreadLocalStorage)); EsSyscall(ES_SYSCALL_THREAD_GET_ID, ES_CURRENT_THREAD, (uintptr_t) &local->id, 0, 0); local->self = local; - EsSyscall(ES_SYSCALL_PROCESS_SET_TLS, (uintptr_t) local - tlsStorageOffset, 0, 0, 0); + EsSyscall(ES_SYSCALL_THREAD_SET_TLS, (uintptr_t) local - tlsStorageOffset, 0, 0, 0); + EsSyscall(ES_SYSCALL_THREAD_SET_TIMER_ADJUST_ADDRESS, (uintptr_t) &local->timerAdjustTicks, 0, 0, 0); } #include "desktop.cpp" @@ -1509,6 +1510,12 @@ extern "C" void _start(EsProcessStartupInformation *_startupInformation) { if (desktop) { EsPrint("Reached Desktop process.\n"); +#ifdef PROFILE_DESKTOP_FUNCTIONS + size_t profilingBufferSize = 64 * 1024 * 1024; + GfProfilingInitialise((ProfilingEntry *) EsHeapAllocate(profilingBufferSize, true), + profilingBufferSize / sizeof(ProfilingEntry), api.startupInformation->timeStampTicksPerMs); +#endif + // Process messages until we find the boot file system. while (!api.foundBootFileSystem) { diff --git a/desktop/gui.cpp b/desktop/gui.cpp index fb13a0c..f2428ad 100644 --- a/desktop/gui.cpp +++ b/desktop/gui.cpp @@ -8035,13 +8035,6 @@ void InspectorVisualizeLayoutBounds(EsInstance *instance, EsElement *, EsCommand EsElementRepaint(window); } -#ifdef PROFILE_DESKTOP_FUNCTIONS -void InspectorBeginProfiling(EsInstance *, EsElement *, EsCommand *) { - size_t entryCount = 3000000; - ProfilingSetup((ProfilingEntry *) EsHeapAllocate(sizeof(ProfilingEntry) * entryCount, false), entryCount); -} -#endif - void InspectorAddElement2(EsMenu *menu, EsGeneric context) { InspectorWindow *inspector = (InspectorWindow *) menu->instance; if (inspector->selectedElement == -1) return; @@ -8102,9 +8095,6 @@ void InspectorSetup(EsWindow *window) { inspector->visualizePaintSteps = EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR, 0, "Visualize paint steps"); EsButtonOnCommand(inspector->visualizePaintSteps, InspectorVisualizePaintSteps); EsSpacerCreate(toolbar, ES_CELL_H_FILL); -#ifdef PROFILE_DESKTOP_FUNCTIONS - EsButtonOnCommand(EsButtonCreate(toolbar, ES_BUTTON_TOOLBAR, 0, "Begin profiling"), InspectorBeginProfiling); -#endif } inspector->elementList = EsListViewCreate(panel1, ES_CELL_FILL | ES_LIST_VIEW_COLUMNS | ES_LIST_VIEW_SINGLE_SELECT); diff --git a/desktop/list_view.cpp b/desktop/list_view.cpp index 41b0cbf..c2a5d8b 100644 --- a/desktop/list_view.cpp +++ b/desktop/list_view.cpp @@ -1949,7 +1949,7 @@ struct EsListView : EsElement { selectedCellStyle = GetStyle(MakeStyleKey(ES_STYLE_LIST_SELECTED_CHOICE_CELL, 0), false); EsListViewChangeStyles(this, nullptr, nullptr, nullptr, nullptr, ES_FLAGS_DEFAULT, ES_FLAGS_DEFAULT); - } else if (message->type == ES_MSG_LIST_VIEW_GET_CONTENT && activeColumns.Length()) { + } else if (message->type == ES_MSG_LIST_VIEW_GET_CONTENT && (activeColumns.Length() || (flags & ES_LIST_VIEW_FIXED_ITEMS))) { uintptr_t index = message->getContent.index; ListViewFixedItemData data = {}; diff --git a/desktop/os.header b/desktop/os.header index e1eb481..f2cacfa 100644 --- a/desktop/os.header +++ b/desktop/os.header @@ -805,11 +805,12 @@ private enum EsSyscallType { ES_SYSCALL_PROCESS_GET_TLS ES_SYSCALL_PROCESS_OPEN ES_SYSCALL_PROCESS_PAUSE - ES_SYSCALL_PROCESS_SET_TLS ES_SYSCALL_PROCESS_TERMINATE ES_SYSCALL_SLEEP ES_SYSCALL_THREAD_CREATE ES_SYSCALL_THREAD_GET_ID + ES_SYSCALL_THREAD_SET_TLS + ES_SYSCALL_THREAD_SET_TIMER_ADJUST_ADDRESS ES_SYSCALL_THREAD_STACK_SIZE ES_SYSCALL_THREAD_TERMINATE ES_SYSCALL_WAIT diff --git a/desktop/posix.cpp b/desktop/posix.cpp index f16458a..b9bf5bc 100644 --- a/desktop/posix.cpp +++ b/desktop/posix.cpp @@ -670,7 +670,7 @@ long EsPOSIXSystemCall(long n, long a1, long a2, long a3, long a4, long a5, long case -1000: { // Update thread local storage: void *apiTLS = ProcessorTLSRead(tlsStorageOffset); - EsSyscall(ES_SYSCALL_PROCESS_SET_TLS, a1, 0, 0, 0); + EsSyscall(ES_SYSCALL_THREAD_SET_TLS, a1, 0, 0, 0); tlsStorageOffset = -a2; ProcessorTLSWrite(tlsStorageOffset, apiTLS); } break; diff --git a/desktop/profiling.cpp b/desktop/profiling.cpp index 02b8f18..c34c8cb 100644 --- a/desktop/profiling.cpp +++ b/desktop/profiling.cpp @@ -1,55 +1,51 @@ -// TODO Adjust time stamps for thread preemption. - -#include -#include +// TODO Include external events on the flame graph, such as context switches. struct ProfilingEntry { void *thisFunction; uint64_t timeStamp; }; -extern ptrdiff_t tlsStorageOffset; -extern "C" uintptr_t ProcessorTLSRead(uintptr_t offset); -extern "C" uint64_t ProcessorReadTimeStamp(); -void EnterDebugger(); +ProfilingEntry *gfProfilingBuffer; +size_t gfProfilingBufferSize; +uintptr_t gfProfilingBufferPosition; +volatile ThreadLocalStorage *gfProfilingThread; +uint64_t gfProfilingTicksPerMs; -extern size_t profilingBufferSize; -extern uintptr_t profilingBufferPosition; -void ProfilingSetup(ProfilingEntry *buffer, size_t size /* number of entries */); - -#ifdef PROFILING_IMPLEMENTATION - -ProfilingEntry *profilingBuffer; -size_t profilingBufferSize; -uintptr_t profilingBufferPosition; -uintptr_t profilingThread; - -#define PROFILING_FUNCTION(_exiting) \ +#define GF_PROFILING_FUNCTION(_exiting) \ (void) callSite; \ \ - if (profilingBufferPosition < profilingBufferSize && profilingThread == ProcessorTLSRead(tlsStorageOffset)) { \ - ProfilingEntry *entry = (ProfilingEntry *) &profilingBuffer[profilingBufferPosition++]; \ + if (gfProfilingBufferPosition < gfProfilingBufferSize \ + && gfProfilingThread == (ThreadLocalStorage *) ProcessorTLSRead(tlsStorageOffset)) { \ + ProfilingEntry *entry = (ProfilingEntry *) &gfProfilingBuffer[gfProfilingBufferPosition++]; \ entry->thisFunction = thisFunction; \ - entry->timeStamp = ProcessorReadTimeStamp() | ((uint64_t) _exiting << 63); \ - } else if (profilingBufferSize && profilingThread == ProcessorTLSRead(tlsStorageOffset)) { \ - profilingBufferSize = 0; \ - EnterDebugger(); \ + entry->timeStamp = (ProcessorReadTimeStamp() - gfProfilingThread->timerAdjustTicks) | ((uint64_t) _exiting << 63); \ } -extern "C" void __cyg_profile_func_enter(void *thisFunction, void *callSite) { - PROFILING_FUNCTION(0); +extern "C" __attribute__((no_instrument_function)) +void __cyg_profile_func_enter(void *thisFunction, void *callSite) { + GF_PROFILING_FUNCTION(0); } -extern "C" void __cyg_profile_func_exit(void *thisFunction, void *callSite) { - PROFILING_FUNCTION(1); +extern "C" __attribute__((no_instrument_function)) +void __cyg_profile_func_exit(void *thisFunction, void *callSite) { + GF_PROFILING_FUNCTION(1); } -void ProfilingSetup(ProfilingEntry *buffer, size_t size) { - profilingThread = ProcessorTLSRead(tlsStorageOffset); +__attribute__((no_instrument_function)) +void GfProfilingInitialise(ProfilingEntry *buffer, size_t size, uint64_t ticksPerMs) { + gfProfilingTicksPerMs = ticksPerMs; + gfProfilingBuffer = buffer; + gfProfilingBufferSize = size; +} + +__attribute__((no_instrument_function)) +void GfProfilingStart() { + gfProfilingThread = GetThreadLocalStorage(); + gfProfilingBufferPosition = 0; +} + +__attribute__((no_instrument_function)) +void GfProfilingStop() { + gfProfilingThread = nullptr; __sync_synchronize(); - profilingBuffer = buffer; - profilingBufferSize = size; - profilingBufferPosition = 0; } - -#endif diff --git a/desktop/text.cpp b/desktop/text.cpp index afd0342..32ec698 100644 --- a/desktop/text.cpp +++ b/desktop/text.cpp @@ -3385,6 +3385,8 @@ void EsTextboxEnsureCaretVisible(EsTextbox *textbox, bool verticallyCenter) { textbox->scroll.SetX(scrollX); } + + UIQueueEnsureVisibleMessage(textbox); } bool TextboxMoveCaret(EsTextbox *textbox, TextboxCaret *caret, bool right, int moveType, bool strongWhitespace = false) { @@ -4418,10 +4420,6 @@ int ProcessTextboxMessage(EsElement *element, EsMessage *message) { } TextboxRefreshVisibleLines(textbox); - - if (textbox->editing && (~textbox->flags & ES_TEXTBOX_MULTILINE)) { - EsTextboxEnsureCaretVisible(textbox); - } } else if (message->type == ES_MSG_DESTROY) { textbox->visibleLines.Free(); textbox->lines.Free(); @@ -4560,7 +4558,6 @@ int ProcessTextboxMessage(EsElement *element, EsMessage *message) { TextboxFindLongestLine(textbox); textbox->scroll.Refresh(); EsTextboxEnsureCaretVisible(textbox); - UIQueueEnsureVisibleMessage(textbox); } } else if (message->type == ES_MSG_MOUSE_LEFT_DOWN || message->type == ES_MSG_MOUSE_RIGHT_DOWN) { TextboxMoveCaretToCursor(textbox, message->mouseDown.positionX, message->mouseDown.positionY, message->type == ES_MSG_MOUSE_RIGHT_DOWN); diff --git a/kernel/scheduler.cpp b/kernel/scheduler.cpp index eb240b0..d4b26ec 100644 --- a/kernel/scheduler.cpp +++ b/kernel/scheduler.cpp @@ -84,10 +84,15 @@ struct Thread { uintptr_t userStackBase; uintptr_t kernelStackBase; uintptr_t kernelStack; - uintptr_t tlsAddress; size_t userStackReserve; volatile size_t userStackCommit; + uintptr_t tlsAddress; + + uintptr_t timerAdjustAddress; + uint64_t timerAdjustTicks; + uint64_t lastInterruptTimeStamp; + ThreadType type; bool isKernelThread, isPageGenerator; int8_t priority; diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp index bee3df8..97541e8 100644 --- a/kernel/syscall.cpp +++ b/kernel/syscall.cpp @@ -1313,12 +1313,17 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_OPEN) { } } -SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_SET_TLS) { +SYSCALL_IMPLEMENT(ES_SYSCALL_THREAD_SET_TLS) { currentThread->tlsAddress = argument0; // Set this first, otherwise we could get pre-empted and restore without TLS set. ProcessorSetThreadStorage(argument0); SYSCALL_RETURN(ES_SUCCESS, false); } +SYSCALL_IMPLEMENT(ES_SYSCALL_THREAD_SET_TIMER_ADJUST_ADDRESS) { + currentThread->timerAdjustAddress = argument0; + SYSCALL_RETURN(ES_SUCCESS, false); +} + SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_GET_TLS) { SYSCALL_RETURN(currentThread->tlsAddress, false); } diff --git a/util/build_core.c b/util/build_core.c index 1c15c38..bf74bff 100644 --- a/util/build_core.c +++ b/util/build_core.c @@ -571,9 +571,8 @@ void BuildDesktop(Application *application) { ExecuteForApp(application, toolchainNasm, buffer, "-MD", "bin/api1.d", "-o", "bin/api1.o", ArgString(commonAssemblyFlags)); ExecuteForApp(application, toolchainCXX, "-MD", "-c", "desktop/api.cpp", "-o", "bin/api2.o", ArgString(commonCompileFlags), ArgString(desktopProfilingFlags)); ExecuteForApp(application, toolchainCXX, "-MD", "-c", "desktop/posix.cpp", "-o", "bin/api3.o", ArgString(commonCompileFlags)); - ExecuteForApp(application, toolchainCXX, "-MD", "-c", "desktop/profiling.cpp", "-o", "bin/api4.o", "-DPROFILING_IMPLEMENTATION", ArgString(commonCompileFlags)); ExecuteForApp(application, toolchainCC, "-o", "bin/Desktop", "bin/crti.o", "bin/crtbegin.o", - "bin/api1.o", "bin/api2.o", "bin/api3.o", "bin/api4.o", "bin/crtend.o", "bin/crtn.o", + "bin/api1.o", "bin/api2.o", "bin/api3.o", "bin/crtend.o", "bin/crtn.o", ArgString(apiLinkFlags1), ArgString(apiLinkFlags2), ArgString(apiLinkFlags3)); ExecuteForApp(application, toolchainStrip, "-o", "bin/Desktop.no_symbols", "--strip-all", "bin/Desktop"); @@ -1579,7 +1578,6 @@ int main(int argc, char **argv) { ADD_DEPENDENCY_FILE(application, "bin/api1.d", "API1"); ADD_DEPENDENCY_FILE(application, "bin/api2.d", "API2"); ADD_DEPENDENCY_FILE(application, "bin/api3.d", "API3"); - ADD_DEPENDENCY_FILE(application, "bin/api4.d", "API4"); arrput(applications, application); } diff --git a/util/luigi.h b/util/luigi.h index e80750d..9485a63 100644 --- a/util/luigi.h +++ b/util/luigi.h @@ -514,7 +514,7 @@ typedef struct UITable { UIScrollBar *vScroll; int itemCount; char *columns; - int *columnWidths, columnCount; + int *columnWidths, columnCount, columnHighlight; } UITable; typedef struct UITextbox { @@ -633,6 +633,7 @@ void UITextboxMoveCaret(UITextbox *textbox, bool backward, bool word); UITable *UITableCreate(UIElement *parent, uint32_t flags, const char *columns /* separate with \t, terminate with \0 */); int UITableHitTest(UITable *table, int x, int y); // Returns item index. Returns -1 if not on an item. +int UITableHeaderHitTest(UITable *table, int x, int y); // Returns column index or -1. bool UITableEnsureVisible(UITable *table, int index); // Returns false if the item was already visible. void UITableResizeColumns(UITable *table); @@ -1366,7 +1367,6 @@ void UIDrawString(UIPainter *painter, UIRectangle r, const char *string, ptrdiff } } - for (; j < bytes; j++) { char c = *string++; uint32_t colorText = color; @@ -2633,6 +2633,26 @@ int UITableHitTest(UITable *table, int x, int y) { return y / rowHeight; } +int UITableHeaderHitTest(UITable *table, int x, int y) { + if (!table->columnCount) return -1; + UIRectangle header = table->e.bounds; + header.b = header.t + UI_SIZE_TABLE_HEADER * table->e.window->scale; + header.l += UI_SIZE_TABLE_COLUMN_GAP * table->e.window->scale; + int position = 0, index = 0; + + while (true) { + int end = position; + for (; table->columns[end] != '\t' && table->columns[end]; end++); + header.r = header.l + table->columnWidths[index]; + if (UIRectangleContains(header, x, y)) return index; + header.l += table->columnWidths[index] + UI_SIZE_TABLE_COLUMN_GAP * table->e.window->scale; + if (table->columns[end] != '\t') break; + position = end + 1, index++; + } + + return -1; +} + bool UITableEnsureVisible(UITable *table, int index) { int rowHeight = UI_SIZE_TABLE_ROW * table->e.window->scale; int y = index * rowHeight; @@ -2768,6 +2788,7 @@ int _UITableMessage(UIElement *element, UIMessage message, int di, void *dp) { header.r = header.l + table->columnWidths[index]; UIDrawString(painter, header, table->columns + position, end - position, ui.theme.text, UI_ALIGN_LEFT, NULL); + if (index == table->columnHighlight) UIDrawInvert(painter, header); header.l += table->columnWidths[index] + UI_SIZE_TABLE_COLUMN_GAP * table->e.window->scale; if (table->columns[end] == '\t') { @@ -2802,6 +2823,7 @@ UITable *UITableCreate(UIElement *parent, uint32_t flags, const char *columns) { UITable *table = (UITable *) UIElementCreate(sizeof(UITable), parent, flags, _UITableMessage, "Table"); table->vScroll = UIScrollBarCreate(&table->e, 0); table->columns = UIStringCopy(columns, -1); + table->columnHighlight = -1; return table; }