From 031cd302dd4c0c019101dffd8c551e97303a2b3f Mon Sep 17 00:00:00 2001 From: Benjamin Doherty Date: Mon, 30 Oct 2023 14:42:24 -0700 Subject: [PATCH] Capture command callstacks for debugging --- .../include/private/backend/CommandStream.h | 20 +++++++++++++++++++ .../backend/include/private/backend/Driver.h | 3 +++ libs/utils/include/utils/CallStack.h | 13 ++++++++---- libs/utils/src/CallStack.cpp | 4 ++-- 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/filament/backend/include/private/backend/CommandStream.h b/filament/backend/include/private/backend/CommandStream.h index 1901361542..92c1f7a4be 100644 --- a/filament/backend/include/private/backend/CommandStream.h +++ b/filament/backend/include/private/backend/CommandStream.h @@ -73,14 +73,32 @@ public: // a cost here (writing and reading the stack at each iteration), in the end it's // probably better to pay the cost at just one location. intptr_t next; + driver.mCurrentExecutingCommand = this; mExecute(driver, this, &next); return reinterpret_cast(reinterpret_cast(this) + next); } + inline void captureCallstack() noexcept { + auto c = utils::CallStack::unwind(4); + size_t i = 0; + for (; i < c.getFrameCount() && i < 16; i++) { + mCallstack[i] = c[i]; + } + for (; i < 16; i++) { + mCallstack[i] = 0; + } + } + + void printCallstack() noexcept { + auto c = utils::CallStack(mCallstack); + utils::slog.d << c << utils::io::endl; + } + inline ~CommandBase() noexcept = default; private: Execute mExecute; + std::array mCallstack = {0}; }; // ------------------------------------------------------------------------------------------------ @@ -218,6 +236,7 @@ public: using Cmd = COMMAND_TYPE(methodName); \ void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); \ new(p) Cmd(mDispatcher.methodName##_, APPLY(std::move, params)); \ + ((Cmd*)p)->captureCallstack(); \ DEBUG_COMMAND_END(methodName, false); \ } @@ -237,6 +256,7 @@ public: using Cmd = COMMAND_TYPE(methodName##R); \ void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); \ new(p) Cmd(mDispatcher.methodName##_, RetType(result), APPLY(std::move, params)); \ + ((Cmd*)p)->captureCallstack(); \ DEBUG_COMMAND_END(methodName, false); \ return result; \ } diff --git a/filament/backend/include/private/backend/Driver.h b/filament/backend/include/private/backend/Driver.h index a8c31ef4bf..36fcf3102a 100644 --- a/filament/backend/include/private/backend/Driver.h +++ b/filament/backend/include/private/backend/Driver.h @@ -53,6 +53,7 @@ template class ConcreteDispatcher; class Dispatcher; class CommandStream; +class CommandBase; class Driver { public: @@ -83,6 +84,8 @@ public: virtual void debugCommandEnd(CommandStream* cmds, bool synchronous, const char* methodName) noexcept = 0; + CommandBase* mCurrentExecutingCommand = nullptr; + /* * Asynchronous calls here only to provide a type to CommandStream. They must be non-virtual * so that calling the concrete implementation won't go through a vtable. diff --git a/libs/utils/include/utils/CallStack.h b/libs/utils/include/utils/CallStack.h index 291a748ce4..56ef41cf5d 100644 --- a/libs/utils/include/utils/CallStack.h +++ b/libs/utils/include/utils/CallStack.h @@ -36,6 +36,13 @@ public: * @see CallStack::capture() */ CallStack() = default; + template + explicit CallStack(const std::array& symbols) + : m_frame_count(N) { + for (size_t i = 0; i < N; i++) { + m_stack[i] = symbols[i]; + } + } CallStack(const CallStack&) = default; ~CallStack() = default; @@ -114,12 +121,10 @@ private: static constexpr size_t NUM_FRAMES = 20; - struct StackFrameInfo { - intptr_t pc; - }; + using StackFrameInfo = intptr_t; size_t m_frame_count = 0; - StackFrameInfo m_stack[NUM_FRAMES]; + StackFrameInfo m_stack[NUM_FRAMES] = {0}; }; } // namespace utils diff --git a/libs/utils/src/CallStack.cpp b/libs/utils/src/CallStack.cpp index b41c18776d..c23d139d1a 100644 --- a/libs/utils/src/CallStack.cpp +++ b/libs/utils/src/CallStack.cpp @@ -70,7 +70,7 @@ intptr_t CallStack::operator[](size_t index) const { #endif std::abort(); } - return m_stack[index].pc; + return m_stack[index]; } size_t CallStack::getFrameCount() const noexcept { @@ -91,7 +91,7 @@ void CallStack::update_gcc(size_t ignore) noexcept { size -= ignore; #endif for (ssize_t i = 0; i < size; i++) { - m_stack[i].pc = intptr_t(array[ignore + i]); + m_stack[i] = intptr_t(array[ignore + i]); } size--; // the last one seems to always be 0x0