Commit dd9f39e2 authored by Kenton Varda's avatar Kenton Varda

Add API to disable stack traces and use it to speed up fuzz-test and enable it on Windows.

On Linux this cuts 56% off the run time of the fuzz test (aka 2.28x speedup).

On Windows this makes it practical to run the fuzz test at all -- previously it was wayyyyyyy too slow.
parent c68ecf4f
...@@ -28,12 +28,6 @@ ...@@ -28,12 +28,6 @@
#include <kj/miniposix.h> #include <kj/miniposix.h>
#include "test-util.h" #include "test-util.h"
#if !_WIN32
// This test is super-slow on Windows seemingly due to generating exception stack traces being
// expensive.
//
// TODO(perf): Maybe create an API to disable stack traces, and use it here.
namespace capnp { namespace capnp {
namespace _ { // private namespace _ { // private
namespace { namespace {
...@@ -47,6 +41,16 @@ bool skipFuzzTest() { ...@@ -47,6 +41,16 @@ bool skipFuzzTest() {
} }
} }
class DisableStackTraces: public kj::ExceptionCallback {
// This test generates a lot of exceptions. Performing a backtrace on each one can be slow,
// especially on Windows (where it is very, very slow). So, disable them.
public:
StackTraceMode stackTraceMode() override {
return StackTraceMode::NONE;
}
};
uint64_t traverse(AnyPointer::Reader reader); uint64_t traverse(AnyPointer::Reader reader);
uint64_t traverse(AnyStruct::Reader reader); uint64_t traverse(AnyStruct::Reader reader);
uint64_t traverse(AnyList::Reader reader); uint64_t traverse(AnyList::Reader reader);
...@@ -163,6 +167,7 @@ struct StructChecker { ...@@ -163,6 +167,7 @@ struct StructChecker {
KJ_TEST("fuzz-test struct pointer") { KJ_TEST("fuzz-test struct pointer") {
if (skipFuzzTest()) return; if (skipFuzzTest()) return;
DisableStackTraces disableStackTraces;
MallocMessageBuilder builder; MallocMessageBuilder builder;
builder.getRoot<TestAllTypes>().setTextField("foo"); builder.getRoot<TestAllTypes>().setTextField("foo");
...@@ -183,6 +188,7 @@ struct ListChecker { ...@@ -183,6 +188,7 @@ struct ListChecker {
KJ_TEST("fuzz-test list pointer") { KJ_TEST("fuzz-test list pointer") {
if (skipFuzzTest()) return; if (skipFuzzTest()) return;
DisableStackTraces disableStackTraces;
MallocMessageBuilder builder; MallocMessageBuilder builder;
auto list = builder.getRoot<AnyPointer>().initAs<List<uint32_t>>(2); auto list = builder.getRoot<AnyPointer>().initAs<List<uint32_t>>(2);
...@@ -207,6 +213,7 @@ struct StructListChecker { ...@@ -207,6 +213,7 @@ struct StructListChecker {
KJ_TEST("fuzz-test struct list pointer") { KJ_TEST("fuzz-test struct list pointer") {
if (skipFuzzTest()) return; if (skipFuzzTest()) return;
DisableStackTraces disableStackTraces;
MallocMessageBuilder builder; MallocMessageBuilder builder;
auto list = builder.getRoot<AnyPointer>().initAs<List<test::TestAllTypes>>(2); auto list = builder.getRoot<AnyPointer>().initAs<List<test::TestAllTypes>>(2);
...@@ -230,6 +237,7 @@ struct TextChecker { ...@@ -230,6 +237,7 @@ struct TextChecker {
KJ_TEST("fuzz-test text pointer") { KJ_TEST("fuzz-test text pointer") {
if (skipFuzzTest()) return; if (skipFuzzTest()) return;
DisableStackTraces disableStackTraces;
MallocMessageBuilder builder; MallocMessageBuilder builder;
builder.template getRoot<AnyPointer>().setAs<Text>("foo"); builder.template getRoot<AnyPointer>().setAs<Text>("foo");
...@@ -238,6 +246,7 @@ KJ_TEST("fuzz-test text pointer") { ...@@ -238,6 +246,7 @@ KJ_TEST("fuzz-test text pointer") {
KJ_TEST("fuzz-test far pointer") { KJ_TEST("fuzz-test far pointer") {
if (skipFuzzTest()) return; if (skipFuzzTest()) return;
DisableStackTraces disableStackTraces;
MallocMessageBuilder builder(1, AllocationStrategy::FIXED_SIZE); MallocMessageBuilder builder(1, AllocationStrategy::FIXED_SIZE);
initTestMessage(builder.getRoot<TestAllTypes>()); initTestMessage(builder.getRoot<TestAllTypes>());
...@@ -251,6 +260,7 @@ KJ_TEST("fuzz-test far pointer") { ...@@ -251,6 +260,7 @@ KJ_TEST("fuzz-test far pointer") {
KJ_TEST("fuzz-test double-far pointer") { KJ_TEST("fuzz-test double-far pointer") {
if (skipFuzzTest()) return; if (skipFuzzTest()) return;
DisableStackTraces disableStackTraces;
MallocMessageBuilder builder(1, AllocationStrategy::FIXED_SIZE); MallocMessageBuilder builder(1, AllocationStrategy::FIXED_SIZE);
...@@ -274,5 +284,3 @@ KJ_TEST("fuzz-test double-far pointer") { ...@@ -274,5 +284,3 @@ KJ_TEST("fuzz-test double-far pointer") {
} // namespace } // namespace
} // namespace _ (private) } // namespace _ (private)
} // namespace capnp } // namespace capnp
#endif
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
#include <dbghelp.h> #include <dbghelp.h>
#endif #endif
#if (__linux__ || __APPLE__) && defined(KJ_DEBUG) #if (__linux__ || __APPLE__)
#include <stdio.h> #include <stdio.h>
#include <pthread.h> #include <pthread.h>
#endif #endif
...@@ -156,6 +156,10 @@ ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount, ...@@ -156,6 +156,10 @@ ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount,
#endif #endif
ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount) { ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount) {
if (getExceptionCallback().stackTraceMode() == ExceptionCallback::StackTraceMode::NONE) {
return nullptr;
}
#if _WIN32 && _M_X64 #if _WIN32 && _M_X64
CONTEXT context; CONTEXT context;
RtlCaptureContext(&context); RtlCaptureContext(&context);
...@@ -170,11 +174,11 @@ ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount) { ...@@ -170,11 +174,11 @@ ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount) {
String stringifyStackTrace(ArrayPtr<void* const> trace) { String stringifyStackTrace(ArrayPtr<void* const> trace) {
if (trace.size() == 0) return nullptr; if (trace.size() == 0) return nullptr;
if (getExceptionCallback().stackTraceMode() != ExceptionCallback::StackTraceMode::FULL) {
#ifndef KJ_DEBUG
return nullptr; return nullptr;
}
#elif _WIN32 && _M_X64 && _MSC_VER #if _WIN32 && _M_X64 && _MSC_VER
// Try to get file/line using SymGetLineFromAddr64(). We don't bother if we aren't on MSVC since // Try to get file/line using SymGetLineFromAddr64(). We don't bother if we aren't on MSVC since
// this requires MSVC debug info. // this requires MSVC debug info.
...@@ -641,6 +645,10 @@ void ExceptionCallback::logMessage( ...@@ -641,6 +645,10 @@ void ExceptionCallback::logMessage(
next.logMessage(severity, file, line, contextDepth, mv(text)); next.logMessage(severity, file, line, contextDepth, mv(text));
} }
ExceptionCallback::StackTraceMode ExceptionCallback::stackTraceMode() {
return next.stackTraceMode();
}
class ExceptionCallback::RootExceptionCallback: public ExceptionCallback { class ExceptionCallback::RootExceptionCallback: public ExceptionCallback {
public: public:
RootExceptionCallback(): ExceptionCallback(*this) {} RootExceptionCallback(): ExceptionCallback(*this) {}
...@@ -687,6 +695,14 @@ public: ...@@ -687,6 +695,14 @@ public:
} }
} }
StackTraceMode stackTraceMode() override {
#ifdef KJ_DEBUG
return StackTraceMode::FULL;
#else
return StackTraceMode::ADDRESS_ONLY;
#endif
}
private: private:
void logException(LogSeverity severity, Exception&& e) { void logException(LogSeverity severity, Exception&& e) {
// We intentionally go back to the top exception callback on the stack because we don't want to // We intentionally go back to the top exception callback on the stack because we don't want to
......
...@@ -193,6 +193,29 @@ public: ...@@ -193,6 +193,29 @@ public:
// //
// The global default implementation writes the text to stderr. // The global default implementation writes the text to stderr.
enum class StackTraceMode {
FULL,
// Stringifying a stack trace will attempt to determine source file and line numbers. This may
// be expensive. For example, on Linux, this shells out to `addr2line`.
//
// This is the default in debug builds.
ADDRESS_ONLY,
// Stringifying a stack trace will only generate a list of code addresses.
//
// This is the default in release builds.
NONE
// Generating a stack trace will always return an empty array.
//
// This avoids ever unwinding the stack. On Windows in particular, the stack unwinding library
// has been observed to be pretty slow, so exception-heavy code might benefit significantly
// from this setting. (But exceptions should be rare...)
};
virtual StackTraceMode stackTraceMode();
// Returns the current preferred stack trace mode.
protected: protected:
ExceptionCallback& next; ExceptionCallback& next;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment