Folly

repository·main·Indexed 12 days ago

https://github.com/facebook/folly

A collection of high-performance C++20 components designed to complement the C++ standard library and Boost, optimized for large-scale performance. Includes folly::coro for asynchronous programming with C++20 coroutines, SIMD-accelerated Base64 encoding and decoding, and an Exception Tracer library for runtime stack inspection.

Tokens
77.8K
Snippets
173
Records
329
Agent score
97%

What's inside Folly

  1. Introduction to folly::coro

    main
    folly::coro is an asynchronous C++ framework built on C++20 coroutines. It provides a developer-friendly way to write asynchronous code with better performance than folly::Future. It is fully compatible with folly::Future and folly::SemiFuture and includes asynchronous synchronization primitives like coro::Baton, coro::Mutex, and coro::SharedMutex.
  2. Overview of the Folly Logging Library

    main

    folly::logging is a C++ logging library designed for high-performance applications that require extensive debug logging in production.

    Its primary design goals are:

    1. Minimal overhead for disabled logs: Log statements are designed to be extremely cheap when the log level is disabled, using lazy evaluation of arguments to ensure no performance penalty in hot code paths.
    2. Hierarchical log categories: It uses a hierarchical model (similar to Apache Log4j) that allows you to control logging granularity. You can enable or disable specific parts of a codebase at runtime by adjusting settings for specific categories or parent categories.
  3. Key features and limitations of folly::fibers

    main

    Features

    • Scheduling: Fiber creation and scheduling are handled by FiberManager.
    • Event Loop Integration: Works with event-management systems (e.g., EventBase).
    • Synchronization: Includes low-level primitives (Baton) and higher-level ones (await, collectN, mutexes).
    • Timeouts: Synchronization primitives support timeouts.
    • Safety: Built-in mechanisms for fiber stack-overflow detection.
    • Local Storage: Supports optional fiber-local data (similar to thread-local storage).

    Limitations and Considerations

    • Scheduling Control: You cannot directly control the scheduling of individual fibers.
    • Thread Safety: FiberManager is not thread-safe. It is recommended to maintain one FiberManager per thread.
    • Stack Management: Fibers use fixed-size stacks; automatic stack size adjustment is not supported.
    • Memory Usage: Every fiber requires a pre-allocated stack. This can lead to high memory consumption if many concurrent tasks are used, or stack overflow risks if stack sizes are set too small.
  4. Key features and advantages of Folly logging

    main

    Folly logging is designed for high-performance debug logging with the following features:

    • Minimal Overhead: Disabled log statements are designed to be extremely cheap (ideally a single conditional check), ensuring that arguments for log messages are not evaluated if the log level is not met. This typically requires using preprocessor macros.
    • Flexible Formatting: Supports both basic concatenation via folly::to<std::string>() and advanced, type-safe formatting using fmt::format().
    • Security: Automatically escapes unprintable characters in log messages by default to prevent terminal escape sequence vulnerabilities.
    • Multi-line Support: The LogMessage class detects internal newlines, allowing LogHandler implementations to correctly apply log headers to every line of a multi-line message.
  5. Inspect exception stacks with the Exception Tracer library

    main

    The Exception Tracer library allows you to inspect the exception stack at runtime. Depending on your requirements for performance, portability, and ease of integration, you can use it in one of three ways:

    1. Low overhead / High portability: Link against exception_tracer_base. This provides access to the functions in ExceptionTracer.h without capturing stack traces. It has no runtime overhead and is C++ ABI compliant.
    2. Full stack traces (Link-time): Link against the full exception_tracer library. This automatically installs std::terminate and std::unexpected handlers and captures full stack traces for all exceptions. Note that this adds runtime overhead to throw and catch operations and depends on internal details of GNU's libstdc++.
    3. Full stack traces (Runtime injection): Use LD_PRELOAD to load libexceptiontracer.so. This provides the same functionality as the full library without requiring link-time changes. However, you must ensure libexceptiontracer.so is compiled with the same compiler and flags as your target binary, and be aware that LD_PRELOAD affects child processes.
  6. What is `folly/Synchronized.h`?

    main
    folly/Synchronized.h provides a simple abstraction for mutex-based concurrency by encapsulating data and its protecting mutex together. This prevents common errors such as accessing data without acquiring its lock, using the wrong lock, or modifying data while holding only a read lock. By using Synchronized<T>, the data is only accessible through a LockedPtr or a callback, ensuring that the lock is always acquired before access.
  7. What is Group Varint encoding in folly

    main

    Group Varint is a variable-length encoding scheme for 32-bit and 64-bit integers designed for efficient storage. It encodes integers in groups rather than individually:

    • 32-bit integers: A group of four uint32_t values is encoded into 5 to 17 bytes. The first byte specifies the length (in bytes) of each integer in the group.
    • 64-bit integers: A group of five uint64_t values is encoded into 7 to 42 bytes. The first two bytes specify the length (in bytes) of each integer in the group.

    This implementation is optimized for performance; the 32-bit version is significantly faster and can utilize the PSHUFB instruction on platforms supporting SSSE3 to accelerate lookups.

  8. What is IsRelocatable and why use it?

    main

    In C++, moving an object typically involves calling a move constructor and destroying the old instance. For many types, this is slower than a simple memcpy.

    folly::IsRelocatable<T>::value is a type trait that indicates whether a type T can be safely moved in memory using memcpy without breaking its internal semantics.

    When to use it:

    • Use it to optimize performance for types that do not contain internal pointers to their own memory buffers.
    • Use it when working with folly::fbvector, which requires types to be explicitly marked as relocatable to function correctly.
  9. What is folly::fibers?

    main

    folly::fibers is an asynchronous C++ framework that uses fibers (also known as coroutines) for parallelism. Fibers are lightweight application threads that run on top of a single system thread.

    Key characteristics:

    • Explicit Context Switching: Unlike system threads, context switching between fibers is explicit, making it extremely fast (capable of ~200 million switches per second on a single CPU core).
    • Task Management: It uses a FiberManager to execute scheduled tasks.
    • Synchronization: Provides fiber-compatible synchronization primitives like Baton.
    • Integration: Designed to integrate with event-management systems like folly::EventBase.
  10. What is folly::Poly and how does type-erasure work?

    main

    folly::Poly is a class template used to create type-erasing polymorphic object wrappers. Unlike inheritance-based polymorphism (virtual dispatch), folly::Poly provides:

    • Duck Typing: Types do not need to inherit from a specific base class; they only need to satisfy the required interface.
    • Value Semantics: Poly objects can be passed by value, avoiding the slicing issues and complexity of passing abstract base class pointers or references.
    • Automatic Memory Management: Poly can store small objects in-situ (in-place) to avoid heap allocation. It handles memory management automatically, leading to cleaner APIs.

    To define a Poly wrapper, you must define two components:

    1. An Interface: A struct containing a nested Interface template (which inherits from a Base parameter) defining the public member functions.
    2. A Mapping: A nested Members alias template that maps concrete types to their specific member function implementations.
  11. How Base64 encoding uses SIMD registers

    main

    The SIMD implementation of Base64 encoding in Folly optimizes performance by processing data within registers. To avoid expensive output size calculations during the encoding loop, the implementation uses a mathematical guarantee: as long as the Register size is greater than 16 bytes, providing 1.5 * Register of input space is sufficient to guarantee at least one full Register of output space.

    This holds true because:

    • Without padding: 0.5 * Register converts to 3/8 of a register, which is > 0.25 * Register.
    • With padding: The last dword of input might produce only 1 output byte, but the mathematical proof convertedSize(RegisterSize / 2 - 4) >= RegisterSize / 4 - 1 ensures sufficient space is always available for registers larger than 16 bytes.
  12. Use LogHandlers to process log messages

    main

    LogHandler objects can be attached to specific log categories. When a message is admitted at a category, it is passed to all LogHandler objects attached to that category.

    Handlers can be used to:

    • Write messages to local files.
    • Print messages to stdout or stderr.
    • Send messages to remote logging services.

    By default, handlers process all messages received at the category they are attached to, though they may implement their own additional log level checks.