mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-30 05:30:51 +00:00
Add FiberStack
This commit is contained in:
parent
319d36a3b7
commit
0fae325d76
45
src/Common/FiberStack.h
Normal file
45
src/Common/FiberStack.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#include <boost/context/stack_context.hpp>
|
||||||
|
#include <Common/Allocator.h>
|
||||||
|
|
||||||
|
#if defined(BOOST_USE_VALGRIND)
|
||||||
|
#include <valgrind/valgrind.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// This is an implementation of allocator for fiber stack.
|
||||||
|
/// It uses internal allocator, so we track memory usage. It is the main reason why this class is needed.
|
||||||
|
/// The reference implementations are pooled_fixedsize_stack and protected_fixedsize_stack from boost::context.
|
||||||
|
template <typename TAllocator = Allocator<false, false>>
|
||||||
|
class FiberStack
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
size_t stack_size;
|
||||||
|
public:
|
||||||
|
/// 8MB of memory per fiber stack may seem too expensive. It is indeed.
|
||||||
|
/// The reason is that current (patched) libunwind needs > 4MB of stack memory to unwind stack.
|
||||||
|
/// If we allocate less memory, any thrown exception inside fiber will cause segfault.
|
||||||
|
static constexpr size_t default_stack_size = 8 * 1024 * 1024;
|
||||||
|
|
||||||
|
explicit FiberStack(size_t stack_size_ = default_stack_size) : stack_size(stack_size_) {}
|
||||||
|
|
||||||
|
boost::context::stack_context allocate()
|
||||||
|
{
|
||||||
|
void * vp = TAllocator().alloc(stack_size);
|
||||||
|
|
||||||
|
boost::context::stack_context sctx;
|
||||||
|
sctx.size = stack_size;
|
||||||
|
sctx.sp = static_cast< char * >(vp) + sctx.size;
|
||||||
|
#if defined(BOOST_USE_VALGRIND)
|
||||||
|
sctx.valgrind_stack_id = VALGRIND_STACK_REGISTER(sctx.sp, vp);
|
||||||
|
#endif
|
||||||
|
return sctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(boost::context::stack_context & sctx)
|
||||||
|
{
|
||||||
|
#if defined(BOOST_USE_VALGRIND)
|
||||||
|
VALGRIND_STACK_DEREGISTER( sctx.valgrind_stack_id);
|
||||||
|
#endif
|
||||||
|
void * vp = static_cast< char * >(sctx.sp) - sctx.size;
|
||||||
|
TAllocator().free(vp, stack_size);
|
||||||
|
}
|
||||||
|
};
|
@ -1,26 +1,90 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
/// #define BOOST_USE_UCONTEXT
|
||||||
#include <boost/context/fiber.hpp>
|
#include <boost/context/fiber.hpp>
|
||||||
|
#include <boost/context/pooled_fixedsize_stack.hpp>
|
||||||
|
#include <boost/context/segmented_stack.hpp>
|
||||||
|
#include <Common/Exception.h>
|
||||||
|
#include <Common/FiberStack.h>
|
||||||
|
|
||||||
|
void __attribute__((__noinline__)) foo(std::exception_ptr exception)
|
||||||
|
{
|
||||||
|
if (exception)
|
||||||
|
std::rethrow_exception(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((__noinline__)) bar(int a)
|
||||||
|
{
|
||||||
|
std::cout << StackTrace().toString() << std::endl;
|
||||||
|
|
||||||
|
if (a > 0)
|
||||||
|
throw DB::Exception(0, "hello");
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((__noinline__)) gar(int a)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
buf[1023] = a & 255;
|
||||||
|
if (a > 2)
|
||||||
|
return gar(a - 1);
|
||||||
|
else
|
||||||
|
bar(a);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int, char **)
|
int main(int, char **)
|
||||||
{
|
try {
|
||||||
namespace ctx=boost::context;
|
namespace ctx=boost::context;
|
||||||
int a;
|
int a;
|
||||||
ctx::fiber source{[&a](ctx::fiber&& sink)
|
std::exception_ptr exception;
|
||||||
|
// ctx::protected_fixedsize allocator
|
||||||
|
// ctx::pooled_fixedsize_stack(1024 * 64 + 2 * 2 * 1024 * 1024 * 16, 1)
|
||||||
|
ctx::fiber source{std::allocator_arg_t(), FiberStack(), [&](ctx::fiber&& sink)
|
||||||
{
|
{
|
||||||
a=0;
|
a=0;
|
||||||
int b=1;
|
int b=1;
|
||||||
while (true)
|
for (size_t i = 0; i < 9; ++i)
|
||||||
{
|
{
|
||||||
sink=std::move(sink).resume();
|
sink=std::move(sink).resume();
|
||||||
int next=a+b;
|
int next=a+b;
|
||||||
a=b;
|
a=b;
|
||||||
b=next;
|
b=next;
|
||||||
}
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
gar(1024);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
std::cout << "Saving exception\n";
|
||||||
|
exception = std::current_exception();
|
||||||
|
}
|
||||||
return std::move(sink);
|
return std::move(sink);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
for (int j=0;j<10;++j)
|
for (int j=0;j<10;++j)
|
||||||
{
|
{
|
||||||
source=std::move(source).resume();
|
try
|
||||||
|
{
|
||||||
|
source=std::move(source).resume();
|
||||||
|
}
|
||||||
|
catch (DB::Exception & e)
|
||||||
|
{
|
||||||
|
std::cout << "Caught exception in resume " << e.getStackTraceString() << std::endl;
|
||||||
|
}
|
||||||
std::cout << a << " ";
|
std::cout << a << " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foo(exception);
|
||||||
|
}
|
||||||
|
catch (const DB::Exception & e)
|
||||||
|
{
|
||||||
|
std::cout << e.getStackTraceString() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
std::cerr << "Uncaught exception\n";
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user