Skip to content

Instantly share code, notes, and snippets.

@MihaelIsaev
Last active April 18, 2025 04:57
Show Gist options
  • Save MihaelIsaev/fbb0135e9b1bb1d2691bb71a30528bc6 to your computer and use it in GitHub Desktop.
Save MihaelIsaev/fbb0135e9b1bb1d2691bb71a30528bc6 to your computer and use it in GitHub Desktop.

Revisions

  1. MihaelIsaev revised this gist Apr 2, 2025. 1 changed file with 13 additions and 0 deletions.
    13 changes: 13 additions & 0 deletions Instruction.md
    Original file line number Diff line number Diff line change
    @@ -3,6 +3,19 @@ According to the [Performance penalty from the Static Linux SDK](https://forums.
    ## Why?
    **It is important for swift apps – especially for server-side apps – to be performant**

    ## Doesn't Static Linux SDK already have mimalloc?

    Great question! Maybe in the future — who knows?

    If you're from the future, you can check your SDK by running
    ```bash
    llvm-nm libc.a | grep 'mi_'
    ```

    If it returns nothing, then `mimalloc` hasn't been integrated yet — and you can integrate it by following this instruction

    If it returns a lot of `mi_`, then congrats — you've already got `mimalloc` in your SDK 🎉

    ## Disclaimer

    You are doing it at your own risk 😱
  2. MihaelIsaev revised this gist Apr 2, 2025. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions Instruction.md
    Original file line number Diff line number Diff line change
    @@ -115,6 +115,11 @@ cd ../

    1. Download `mimalloc_v2.1.7.diff` and `patch_musl.sh`

    ```bash
    curl -LO https://gist.github.com/MihaelIsaev/fbb0135e9b1bb1d2691bb71a30528bc6/raw/4448da386e6d0dbd704716091be4818e56ba3d28/mimalloc_v2.1.7.diff
    curl -LO https://gist.github.com/MihaelIsaev/fbb0135e9b1bb1d2691bb71a30528bc6/raw/4448da386e6d0dbd704716091be4818e56ba3d28/patch_musl.sh
    ```

    2. Make `patch_musl.sh` executable

    ```bash
  3. MihaelIsaev created this gist Apr 2, 2025.
    155 changes: 155 additions & 0 deletions Instruction.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,155 @@
    According to the [Performance penalty from the Static Linux SDK](https://forums.swift.org/t/performance-penalty-from-the-static-linux-sdk/75003) post I would like to provide a step-by-step instruction of how to patch `static-linux-sdk` with `mimalloc`

    ## Why?
    **It is important for swift apps – especially for server-side apps – to be performant**

    ## Disclaimer

    You are doing it at your own risk 😱

    ## Requirements

    **`x86_64` and `arm64` ubuntu/debian environment**

    Or docker with QEMU, but I had no luck with it yet. So I used `x86_64` and `arm64` machines on [Hetzner Cloud](http://cloud.hetzner.com)

    `static-linux-sdk` gives you the ability to compile into x86 and ARM architectures, it means that it has two versions of `libc.a`, one for each platform

    We have to patch both

    # Step-by-step

    ## Get SDK

    I assume you already have it installed on your machine, but if not then install or just download it

    ### Install

    ```bash
    swift sdk install <URL> --checksum <CHECKSUM>
    ```

    ### Download SDK

    1. Go to [swift.org](https://www.swift.org/install/linux/)
    2. Choose Ubuntu or Debian
    3. Choose version of OS
    4.1. Hit the `Download Linux Static SDK` button
    4.2 Or copy link and download it with `curl` e.g. `curl -LO <URL>`

    #### Extract SDK archive

    Let's assume you downloaded `swift-6.1-RELEASE_static-linux-0.0.1.artifactbundle.tar.gz`

    Then, execute

    ```bash
    tar -xzf swift-6.1-RELEASE_static-linux-0.0.1.artifactbundle.tar.gz
    ```

    ## Take `libc.a` files from it

    Create `x86_64` and `aarch64` directories

    ```bash
    mkdir x86_64 && mkdir aarch64
    ```

    Copy both versions of `libc.a` into these directories

    If you have it installed then it is located at `~/.swiftpm/swift-sdks`

    If not then it is where you extracted it

    ```bash
    cp swift-6.1-RELEASE_static-linux-0.0.1.artifactbundle/swift-6.1-RELEASE_static-linux-0.0.1/swift-linux-musl/musl-1.2.5.sdk/x86_64/usr/lib/libc.a ./x86_64/libc.a
    cp swift-6.1-RELEASE_static-linux-0.0.1.artifactbundle/swift-6.1-RELEASE_static-linux-0.0.1/swift-linux-musl/musl-1.2.5.sdk/aarch64/usr/lib/libc.a ./aarch64/libc.a
    ```

    ## Patching

    Do the following steps on both `x86_64` and `arm64` machines

    ### Install required packages via `apt`

    ```bash
    # install required packages
    apt update
    apt install -y llvm software-properties-common build-essential libssl-dev clang
    ```

    ### Prepare cmake

    > [!Note]
    > `mimalloc` requires `cmake >= 3.18.0`
    Check your `cmake` version

    ```bash
    cmake --version
    ```

    If it is lower, then install `3.27.9` from sources by following these steps

    ```bash
    # download cmake
    curl -LO https://github.com/Kitware/CMake/releases/download/v3.27.9/cmake-3.27.9.tar.gz
    # extract cmake
    tar -xf cmake-3.27.9.tar.gz
    # go to cmake dir
    cd cmake-3.27.9
    # compile cmake
    ./bootstrap --prefix=$HOME/.local
    make -j$(nproc)
    make install
    # add cmake into PATH
    echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
    source ~/.bashrc
    # check cmake version
    cmake --version
    # go back to the parent dir
    cd ../
    ```

    ### Download

    1. Download `mimalloc_v2.1.7.diff` and `patch_musl.sh`

    2. Make `patch_musl.sh` executable

    ```bash
    chmod +x ./patch_musl.sh
    ```

    3. Upload`libc.a` for the current CPU architecture

    ### Patch `libc.a`

    It will create `libc.a.bak` backup of the original file

    ```bash
    ./patch_musl.sh
    ```

    🥳 **Now you have successfully patched `libc.a` with `mimalloc`**

    > [!Tip]
    > Don't forget to patch it for both architectures
    ## Copy `libc.a` back into your SDK

    I assume you have it installed, so copy proper `libc.a` files into their `usr/lib` directories

    ## Do I need to put `libmimalloc.a` alongside `libc.a`?

    No, `mimalloc` has been merged into `libc.a`

    ## Docker version?

    I tried to do it but had no luck yet. You are welcome to implement it and update this instruction 🤝

    ## Credits

    Credit to Sebastian Toivonen, aka [MarSe32m](https://forums.swift.org/u/MarSe32m) and his [post](https://forums.swift.org/t/performance-penalty-from-the-static-linux-sdk/75003)

    🫡 **Enjoy!**
    35 changes: 35 additions & 0 deletions mimalloc_v2.1.7.diff
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,35 @@
    diff --git a/CMakeLists.txt b/CMakeLists.txt
    index bcfe91d8..a5473c69 100644
    --- a/CMakeLists.txt
    +++ b/CMakeLists.txt
    @@ -481,7 +481,6 @@ endif()
    # static library
    if (MI_BUILD_STATIC)
    add_library(mimalloc-static STATIC ${mi_sources})
    - set_property(TARGET mimalloc-static PROPERTY POSITION_INDEPENDENT_CODE ON)
    target_compile_definitions(mimalloc-static PRIVATE ${mi_defines} MI_STATIC_LIB)
    target_compile_options(mimalloc-static PRIVATE ${mi_cflags} ${mi_cflags_static})
    target_link_libraries(mimalloc-static PRIVATE ${mi_libraries})
    diff --git a/src/alloc-override.c b/src/alloc-override.c
    index 12837cdd..e5bcda22 100644
    --- a/src/alloc-override.c
    +++ b/src/alloc-override.c
    @@ -191,7 +191,7 @@ typedef void* mi_nothrow_t;
    void* operator new[](std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return mi_new_aligned_nothrow(n, static_cast<size_t>(al)); }
    #endif

    -#elif (defined(__GNUC__) || defined(__clang__))
    +#elif (defined(__GNUC__) || defined(__clang__) || defined(do_we_need_this))
    // ------------------------------------------------------
    // Override by defining the mangled C++ names of the operators (as
    // used by GCC and CLang).
    @@ -289,7 +289,7 @@ mi_decl_weak int reallocarr(void* p, size_t count, size_t size) { return mi_r
    void __libc_free(void* p) MI_FORWARD0(mi_free, p)
    void* __libc_memalign(size_t alignment, size_t size) { return mi_memalign(alignment, size); }

    -#elif defined(__GLIBC__) && defined(__linux__)
    +#elif defined(__linux__) //defined(__GLIBC__) && defined(__linux__)
    // forward __libc interface (needed for glibc-based Linux distributions)
    void* __libc_malloc(size_t size) MI_FORWARD1(mi_malloc,size)
    void* __libc_calloc(size_t count, size_t size) MI_FORWARD2(mi_calloc,count,size)

    68 changes: 68 additions & 0 deletions patch_musl.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,68 @@
    #!/bin/bash
    set -euo pipefail

    echo "Looking for libc.a in current directory..."
    LIBC_PATH="./libc.a"
    if [ ! -f "$LIBC_PATH" ]; then
    echo "Error: libc.a not found in the current directory."
    exit 1
    fi

    echo "Backing up original libc.a to libc.a.bak"
    cp "$LIBC_PATH" libc.a.bak

    echo "Building mimalloc static library..."
    if [ ! -d mimalloc ]; then
    echo "Cloning mimalloc..."
    git clone https://github.com/microsoft/mimalloc
    else
    echo "Using existing mimalloc directory."
    fi
    cd mimalloc

    git fetch --tags
    git checkout tags/v2.1.7

    # Clean up any previous modifications
    git reset --hard
    git clean -fd

    # Check if patch is already applied
    if git apply --check ../mimalloc_v2.1.7.diff 2>/dev/null; then
    echo "Applying patch..."
    git apply ../mimalloc_v2.1.7.diff
    else
    echo "Patch already applied or incompatible. Skipping patch step."
    fi

    cmake -Bout -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DMI_BUILD_SHARED=OFF -DMI_BUILD_OBJECT=OFF -DMI_BUILD_TESTS=OFF .
    cmake --build out

    echo "Patching musl libc.a with mimalloc..."
    cp ./out/libmimalloc.a .
    cp "$OLDPWD/libc.a" .

    # Remove musl malloc-related object files
    for symbol in aligned_alloc calloc donate free free libc_calloc lite_malloc malloc malloc_usable_size memalign posix_memalign realloc realloc reallocarray valloc strdup strndup; do
    llvm-ar -d libc.a "${symbol}.lo" || true
    done

    # Verify removals
    for symbol in aligned_alloc calloc donate free libc_calloc lite_malloc malloc malloc_usable_size memalign posix_memalign realloc reallocarray valloc strdup strndup; do
    if llvm-ar -t libc.a | grep -q "${symbol}.lo"; then
    echo "Warning: ${symbol}.lo still exists in libc.a"
    fi
    done

    # Inject mimalloc object files
    llvm-ar -x libmimalloc.a
    llvm-ar -r libc.a *.o

    echo "Replacing original libc.a with patched version..."
    cp libc.a "$OLDPWD/libc.a"

    cd "$OLDPWD"
    rm -rf mimalloc

    echo "✅ Done! libc.a has been patched with mimalloc."