From: Tudor Bosman Date: Thu, 20 Jun 2013 21:15:17 +0000 (-0700) Subject: Use libunwind instead of the heavyweight thing from libgcc X-Git-Tag: v0.22.0~945 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=b78098f785d00f9b37d43d958c5e9d0d74397d18;p=folly.git Use libunwind instead of the heavyweight thing from libgcc Test Plan: exception_tracer_test Reviewed By: bmaurer@fb.com FB internal diff: D858195 --- diff --git a/folly/experimental/exception_tracer/ExceptionTracerBenchmark.cpp b/folly/experimental/exception_tracer/ExceptionTracerBenchmark.cpp new file mode 100644 index 00000000..95c99eb1 --- /dev/null +++ b/folly/experimental/exception_tracer/ExceptionTracerBenchmark.cpp @@ -0,0 +1,63 @@ +/* + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include + +#include "folly/Benchmark.h" +#include "folly/experimental/exception_tracer/ExceptionTracer.h" + +void recurse(int level) { + if (level == 0) { + throw std::runtime_error(""); + } + recurse(level - 1); + folly::doNotOptimizeAway(0); // prevent tail recursion +} + +void loop(int iters) { + for (int i = 0; i < iters * 100; ++i) { + try { + recurse(100); + } catch (const std::exception& e) { + folly::exception_tracer::getCurrentExceptions(); + } + } +} + +BENCHMARK(ExceptionTracer, iters) { + std::vector threads; + constexpr size_t kNumThreads = 10; + threads.resize(10); + for (auto& t : threads) { + t = std::thread([iters] () { loop(iters); }); + } + for (auto& t : threads) { + t.join(); + } +} + +int main(int argc, char* argv[]) { + google::ParseCommandLineFlags(&argc, &argv, true); + google::InitGoogleLogging(argv[0]); + folly::runBenchmarks(); + return 0; +} + diff --git a/folly/experimental/exception_tracer/StackTrace.c b/folly/experimental/exception_tracer/StackTrace.c index a10fb1b9..7a3d5cef 100644 --- a/folly/experimental/exception_tracer/StackTrace.c +++ b/folly/experimental/exception_tracer/StackTrace.c @@ -18,8 +18,12 @@ #include "folly/experimental/exception_tracer/StackTrace.h" #include +#include #include -#include "unwind.h" + +#define UNW_LOCAL_ONLY 1 + +#include struct Context { StackTrace* trace; @@ -27,43 +31,69 @@ struct Context { size_t capacity; }; -static _Unwind_Reason_Code addIP(struct _Unwind_Context* ctx, void* varg) { - struct Context* arg = (struct Context*)varg; +static int checkError(const char* name, int err) { + if (err < 0) { + fprintf(stderr, "libunwind error: %s %d\n", name, err); + return -EINVAL; + } + return 0; +} - if (arg->skip) { - --arg->skip; - return _URC_NO_REASON; +static int addIP(struct Context* ctx, unw_cursor_t* cursor) { + if (ctx->skip) { + --ctx->skip; + return 0; } - if (arg->trace->frameCount == arg->capacity) { - size_t newCapacity = (arg->capacity < 8 ? 8 : arg->capacity * 1.5); + unw_word_t ip; + int r = unw_get_reg(cursor, UNW_REG_IP, &ip); + int err = checkError("unw_get_reg", r); + if (err) return err; + + if (ctx->trace->frameCount == ctx->capacity) { + size_t newCapacity = (ctx->capacity < 8 ? 8 : ctx->capacity * 1.5); uintptr_t* newBlock = - realloc(arg->trace->frameIPs, newCapacity * sizeof(uintptr_t)); + realloc(ctx->trace->frameIPs, newCapacity * sizeof(uintptr_t)); if (!newBlock) { - return _URC_FATAL_PHASE1_ERROR; + return -ENOMEM; } - arg->trace->frameIPs = newBlock; - arg->capacity = newCapacity; + ctx->trace->frameIPs = newBlock; + ctx->capacity = newCapacity; } - arg->trace->frameIPs[arg->trace->frameCount++] = _Unwind_GetIP(ctx); - return _URC_NO_REASON; /* success */ + ctx->trace->frameIPs[ctx->trace->frameCount++] = ip; + return 0; /* success */ } int getCurrentStackTrace(size_t skip, StackTrace* trace) { trace->frameIPs = NULL; trace->frameCount = 0; + struct Context ctx; ctx.trace = trace; ctx.skip = skip; ctx.capacity = 0; - if (_Unwind_Backtrace(addIP, &ctx) == _URC_END_OF_STACK) { - return 0; + unw_context_t uctx; + int r = unw_getcontext(&uctx); + int err = checkError("unw_get_context", r); + if (err) return err; + + unw_cursor_t cursor; + r = unw_init_local(&cursor, &uctx); + err = checkError("unw_init_local", r); + if (err) return err; + + while ((r = unw_step(&cursor)) > 0) { + if ((err = addIP(&ctx, &cursor)) != 0) { + destroyStackTrace(trace); + return err; + } } + err = checkError("unw_step", r); + if (err) return err; - destroyStackTrace(trace); - return -ENOMEM; + return 0; } void destroyStackTrace(StackTrace* trace) {