From 0cfca100a87f8845a322b17393732f259a8594f7 Mon Sep 17 00:00:00 2001 From: Jason Andrews Date: Mon, 9 Jun 2025 10:27:56 -0500 Subject: [PATCH] Optimizing Arm binaries and libraries with LLVM BOLT --- .../bolt-merge/_index.md | 55 +++++++ .../bolt-merge/_next-steps.md | 8 + .../bolt-merge/example-picture.png | Bin 0 -> 63167 bytes .../bolt-merge/how-to-1.md | 27 +++ .../bolt-merge/how-to-2.md | 89 ++++++++++ .../bolt-merge/how-to-3.md | 100 ++++++++++++ .../bolt-merge/how-to-4.md | 154 ++++++++++++++++++ .../bolt-merge/how-to-5.md | 68 ++++++++ 8 files changed, 501 insertions(+) create mode 100644 content/learning-paths/servers-and-cloud-computing/bolt-merge/_index.md create mode 100644 content/learning-paths/servers-and-cloud-computing/bolt-merge/_next-steps.md create mode 100644 content/learning-paths/servers-and-cloud-computing/bolt-merge/example-picture.png create mode 100644 content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-1.md create mode 100644 content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-2.md create mode 100644 content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-3.md create mode 100644 content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-4.md create mode 100644 content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-5.md diff --git a/content/learning-paths/servers-and-cloud-computing/bolt-merge/_index.md b/content/learning-paths/servers-and-cloud-computing/bolt-merge/_index.md new file mode 100644 index 0000000000..616f37d088 --- /dev/null +++ b/content/learning-paths/servers-and-cloud-computing/bolt-merge/_index.md @@ -0,0 +1,55 @@ +--- +title: Optimizing Arm binaries and libraries with LLVM-BOLT and profile merging + +draft: true +cascade: + draft: true + +minutes_to_complete: 30 + +who_is_this_for: Performance engineers, software developers working on Arm platforms who want to optimize both application binaries and shared libraries using LLVM-BOLT. + +learning_objectives: + - Instrument and optimize binaries for individual workload features using LLVM-BOLT. + - Collect separate BOLT profiles and merge them for comprehensive code coverage. + - Optimize shared libraries independently. + - Integrate optimized shared libraries into applications. + - Evaluate and compare application and library performance across baseline, isolated, and merged optimization scenarios. + +prerequisites: + - An Arm based system running Linux with BOLT and Linux Perf installed. The Linux kernel should be version 5.15 or later. + - (Optional) A second, more powerful Linux system to build the software executable and run BOLT. + +author: Gayathri Narayana Yegna Narayanan + +### Tags +skilllevels: Introductory +subjects: Performance and Architecture +armips: + - Neoverse + - Cortex-A +tools_software_languages: + - BOLT + - perf + - Runbook +operatingsystems: + - Linux + +further_reading: + - resource: + title: BOLT README + link: https://github.com/llvm/llvm-project/tree/main/bolt + type: documentation + - resource: + title: BOLT - A Practical Binary Optimizer for Data Centers and Beyond + link: https://research.facebook.com/publications/bolt-a-practical-binary-optimizer-for-data-centers-and-beyond/ + type: website + + +### FIXED, DO NOT MODIFY +# ================================================================================ +weight: 1 # _index.md always has weight of 1 to order correctly +layout: "learningpathall" # All files under learning paths have this same wrapper +learning_path_main_page: "yes" # This should be surfaced when looking for related content. Only set for _index.md of learning path content. +--- + diff --git a/content/learning-paths/servers-and-cloud-computing/bolt-merge/_next-steps.md b/content/learning-paths/servers-and-cloud-computing/bolt-merge/_next-steps.md new file mode 100644 index 0000000000..c3db0de5a2 --- /dev/null +++ b/content/learning-paths/servers-and-cloud-computing/bolt-merge/_next-steps.md @@ -0,0 +1,8 @@ +--- +# ================================================================================ +# FIXED, DO NOT MODIFY THIS FILE +# ================================================================================ +weight: 21 # Set to always be larger than the content in this path to be at the end of the navigation. +title: "Next Steps" # Always the same, html page title. +layout: "learningpathall" # All files under learning paths have this same wrapper for Hugo processing. +--- diff --git a/content/learning-paths/servers-and-cloud-computing/bolt-merge/example-picture.png b/content/learning-paths/servers-and-cloud-computing/bolt-merge/example-picture.png new file mode 100644 index 0000000000000000000000000000000000000000..c69844bed44b65c7f5bc6cf511f93987fdcd7b95 GIT binary patch literal 63167 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 q-Mv3pxc`&l*gyNt{xlEs;Qs>q{#983 literal 0 HcmV?d00001 diff --git a/content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-1.md b/content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-1.md new file mode 100644 index 0000000000..1d80f6e6e7 --- /dev/null +++ b/content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-1.md @@ -0,0 +1,27 @@ +--- +title: Overview of BOLT Merge +weight: 2 + +### FIXED, DO NOT MODIFY +layout: learningpathall +--- + +[BOLT](https://github.com/llvm/llvm-project/blob/main/bolt/README.md) is a post-link binary optimizer that uses Linux Perf data to re-order the executable code layout to reduce memory overhead and improve performance. + +In this Learning Path, you'll learn how to: +- Collect and merge BOLT profiles from multiple workload features (e.g., read-only and write-only) +- Independently optimize application binaries and external user-space libraries (e.g., `libssl.so`, `libcrypto.so`) +- Link the final optimized binary with the separately bolted libraries to deploy a fully optimized runtime stack + +While MySQL and sysbench are used as examples, this method applies to **any feature-rich application** that: +- Exhibits multiple runtime paths +- Uses dynamic libraries +- Requires full-stack binary optimization for performance-critical deployment + +The workflow includes: +1. Profiling each workload feature separately +2. Profiling external libraries independently +3. Merging profiles for broader code coverage +4. Applying BOLT to each binary and library +5. Linking bolted libraries with the merged-profile binary + diff --git a/content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-2.md b/content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-2.md new file mode 100644 index 0000000000..c67ed17850 --- /dev/null +++ b/content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-2.md @@ -0,0 +1,89 @@ +--- +title: BOLT Optimization - First feature +weight: 3 + +### FIXED, DO NOT MODIFY +layout: learningpathall +--- + +In this step, you will instrument an application binary (such as `mysqld`) with BOLT to collect runtime profile data for a specific feature — for example, a **read-only workload**. + +The collected profile will later be merged with others and used to optimize the application's code layout. + +### Step 1: Build or obtain the uninstrumented binary + +Make sure your application binary is: + +- Built from source (e.g., `mysqld`) +- Unstripped, with symbol information available +- Compiled with frame pointers enabled (`-fno-omit-frame-pointer`) + +You can verify this with: + +```bash +readelf -s /path/to/mysqld | grep main +``` + +If the symbols are missing, rebuild the binary with debug info and no stripping. + +--- + +### Step 2: Instrument the binary with BOLT + +Use `llvm-bolt` to create an instrumented version of the binary: + +```bash +llvm-bolt /path/to/mysqld \\ + -instrument \\ + -o /path/to/mysqld.instrumented \\ + --instrumentation-file=/path/to/profile-readonly.fdata \\ + --instrumentation-sleep-time=5 \\ + --instrumentation-no-counters-clear \\ + --instrumentation-wait-forks +``` + +### Explanation of key options + +- `-instrument`: Enables profile generation instrumentation +- `--instrumentation-file`: Path where the profile output will be saved +- `--instrumentation-wait-forks`: Ensures the instrumentation continues through forks (important for daemon processes) + +--- + +### Step 3: Run the instrumented binary under a feature-specific workload + +Use a workload generator to stress the binary in a feature-specific way. For example, to simulate **read-only traffic** with sysbench: + +```bash +taskset -c 9 ./src/sysbench \\ + --db-driver=mysql \\ + --mysql-host=127.0.0.1 \\ + --mysql-db=bench \\ + --mysql-user=bench \\ + --mysql-password=bench \\ + --mysql-port=3306 \\ + --tables=8 \\ + --table-size=10000 \\ + --threads=1 \\ + src/lua/oltp_read_only.lua run +``` + +> Adjust this command as needed for your workload and CPU/core binding. + +The `.fdata` file defined in `--instrumentation-file` will be populated with runtime execution data. + +--- + +### Step 4: Verify the profile was created + +After running the workload: + +```bash +ls -lh /path/to/profile-readonly.fdata +``` + +You should see a non-empty file. This file will later be merged with other profiles (e.g., for write-only traffic) to generate a complete merged profile. + +--- + + diff --git a/content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-3.md b/content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-3.md new file mode 100644 index 0000000000..f1ea41f09c --- /dev/null +++ b/content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-3.md @@ -0,0 +1,100 @@ +--- +title: BOLT Optimization - Second Feature & BOLT Merge to combine +weight: 4 + +### FIXED, DO NOT MODIFY +layout: learningpathall +--- + +In this step, you'll collect profile data for a **write-heavy** workload and also **instrument external libraries** such as `libcrypto.so` and `libssl.so` used by the application (e.g., MySQL). + + +### Step 1: Run Write-Only Workload for Application Binary + +Use the same BOLT-instrumented MySQL binary and drive it with a write-only workload to capture `profile-writeonly.fdata`: + +```bash +taskset -c 9 ./src/sysbench \\ + --db-driver=mysql \\ + --mysql-host=127.0.0.1 \\ + --mysql-db=bench \\ + --mysql-user=bench \\ + --mysql-password=bench \\ + --mysql-port=3306 \\ + --tables=8 \\ + --table-size=10000 \\ + --threads=1 \\ + src/lua/oltp_write_only.lua run +``` + +Make sure that the `--instrumentation-file` is set appropriately to save `profile-writeonly.fdata`. +--- +### Step 2: Verify the Second Profile Was Generated + +```bash +ls -lh /path/to/profile-writeonly.fdata +``` + +Both `.fdata` files should now exist and contain valid data: + +- `profile-readonly.fdata` +- `profile-writeonly.fdata` + +--- + +### Step 3: Merge the Feature Profiles + +Use `merge-fdata` to combine the feature-specific profiles into one comprehensive `.fdata` file: + +```bash +merge-fdata /path/to/profile-readonly.fdata /path/to/profile-writeonly.fdata \\ + -o /path/to/profile-merged.fdata +``` + +**Example command from an actual setup:** + +```bash +/home/ubuntu/llvm-latest/build/bin/merge-fdata prof-instrumentation-readonly.fdata prof-instrumentation-writeonly.fdata \\ + -o prof-instrumentation-readwritemerged.fdata +``` + +Output: + +``` +Using legacy profile format. +Profile from 2 files merged. +``` + +This creates a single merged profile (`profile-merged.fdata`) covering both read-only and write-only workload behaviors. + +--- + +### Step 4: Verify the Merged Profile + +Check the merged `.fdata` file: + +```bash +ls -lh /path/to/profile-merged.fdata +``` + +--- +### Step 5: Generate the Final Binary with the Merged Profile + +Use LLVM-BOLT to generate the final optimized binary using the merged `.fdata` file: + +```bash +llvm-bolt build/bin/mysqld \\ + -o build/bin/mysqldreadwrite_merged.bolt_instrumentation \\ + -data=/home/ubuntu/mysql-server-8.0.33/sysbench/prof-instrumentation-readwritemerged.fdata \\ + -reorder-blocks=ext-tsp \\ + -reorder-functions=hfsort \\ + -split-functions \\ + -split-all-cold \\ + -split-eh \\ + -dyno-stats \\ + --print-profile-stats 2>&1 | tee bolt_orig.log +``` + +This command optimizes the binary layout based on the merged workload profile, creating a single binary (`mysqldreadwrite_merged.bolt_instrumentation`) that is optimized across both features. + + diff --git a/content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-4.md b/content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-4.md new file mode 100644 index 0000000000..376c249164 --- /dev/null +++ b/content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-4.md @@ -0,0 +1,154 @@ +--- +title: BOLT the Libraries separately +weight: 5 + +### FIXED, DO NOT MODIFY +layout: learningpathall +--- +### Step 1: Instrument Shared Libraries (e.g., libcrypto, libssl) + +If system libraries like `/usr/lib/libssl.so` are stripped, rebuild OpenSSL from source with relocations: + +```bash +git clone https://github.com/openssl/openssl.git +cd openssl +./config -O2 -Wl,--emit-relocs --prefix=$HOME/bolt-libs/openssl +make -j$(nproc) +make install +``` + +--- + +### Step 2: BOLT-Instrument libssl.so.3 + +Use `llvm-bolt` to instrument `libssl.so.3`: + +```bash +llvm-bolt $HOME/bolt-libs/openssl/lib/libssl.so.3 \\ + -instrument \\ + -o $HOME/bolt-libs/openssl/lib/libssl.so.3.instrumented \\ + --instrumentation-file=libssl-readwrite.fdata \\ + --instrumentation-sleep-time=5 \\ + --instrumentation-no-counters-clear \\ + --instrumentation-wait-forks +``` + +Then launch MySQL using the **instrumented shared library** and run a **read+write** sysbench test to populate the profile: + +--- + +### Step 3: Optimize 'libssl.so' Using Its Profile + +After running the read+write test, ensure `libssl-readwrite.fdata` is populated. + + +Run BOLT on the uninstrumented `libssl.so` with the collected read-write profile: + +```bash +llvm-bolt /path/to/libssl.so.3 \\ + -o /path/to/libssl.so.optimized \\ + -data=/path/to/prof-instrumentation-libssl-readwrite.fdata \\ + -reorder-blocks=ext-tsp \\ + -reorder-functions=hfsort \\ + -split-functions \\ + -split-all-cold \\ + -split-eh \\ + -dyno-stats \\ + --print-profile-stats +``` + +--- + +### Step 3: Replace the Library at Runtime + +Copy the optimized version over the original and export the path: + +```bash +cp /path/to/libssl.so.optimized /path/to/libssl.so.3 +export LD_LIBRARY_PATH=/path/to/ +``` + +This ensures MySQL will dynamically load the optimized `libssl.so`. + +--- + +### Step 4: Run Final Workload and Validate Performance + +Start the BOLT-optimized MySQL binary and link it against the optimized `libssl.so`. Run the combined workload: + +```bash +taskset -c 9 ./src/sysbench \\ + --db-driver=mysql \\ + --mysql-host=127.0.0.1 \\ + --mysql-db=bench \\ + --mysql-user=bench \\ + --mysql-password=bench \\ + --mysql-port=3306 \\ + --tables=8 \\ + --table-size=10000 \\ + --threads=1 \\ + src/lua/oltp_read_write.lua run +``` + +--- + +In the next step, you'll optimize an additional critical external library (`libcrypto.so`) using BOLT, following a similar process as `libssl.so`. Afterward, you'll interpret performance results to validate and compare optimizations across baseline and merged + scenarios. + +### Step 1: BOLT optimization for 'libcrypto.so' + +Follow these steps to instrument and optimize `libcrypto.so`: + +#### Instrument `libcrypto.so`: + +```bash +llvm-bolt /path/to/libcrypto.so.3 \\ + -instrument \\ + -o /path/to/libcrypto.so.3.instrumented \\ + --instrumentation-file=libcrypto-readwrite.fdata \\ + --instrumentation-sleep-time=5 \\ + --instrumentation-no-counters-clear \\ + --instrumentation-wait-forks +``` + +Run MySQL under the read-write workload to populate `libcrypto-readwrite.fdata`: + +```bash +export LD_LIBRARY_PATH=/path/to/libcrypto-instrumented +taskset -c 9 ./src/sysbench \\ + --db-driver=mysql \\ + --mysql-host=127.0.0.1 \\ + --mysql-db=bench \\ + --mysql-user=bench \\ + --mysql-password=bench \\ + --mysql-port=3306 \\ + --tables=8 \\ + --table-size=10000 \\ + --threads=1 \\ + src/lua/oltp_read_write.lua run +``` + +#### Optimize the `libcrypto.so` library: + +```bash +llvm-bolt /path/to/original/libcrypto.so.3 \\ + -o /path/to/libcrypto.so.optimized \\ + -data=libcrypto-readwrite.fdata \\ + -reorder-blocks=ext-tsp \\ + -reorder-functions=hfsort \\ + -split-functions \\ + -split-all-cold \\ + -split-eh \\ + -dyno-stats \\ + --print-profile-stats +``` + +Replace the original at runtime: + +```bash +cp /path/to/libcrypto.so.optimized /path/to/libcrypto.so.3 +export LD_LIBRARY_PATH=/path/to/ +``` + +Run a final validation workload to ensure functionality and measure performance improvements. + diff --git a/content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-5.md b/content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-5.md new file mode 100644 index 0000000000..07cd298c5f --- /dev/null +++ b/content/learning-paths/servers-and-cloud-computing/bolt-merge/how-to-5.md @@ -0,0 +1,68 @@ +--- +title: Performance Results - Baseline, BOLT Merge, and Full Optimization +weight: 6 + +### FIXED, DO NOT MODIFY +layout: learningpathall +--- + +This step presents the performance comparisons across various BOLT optimization scenarios. You'll see how baseline performance compares with BOLT-optimized binaries using merged profiles and bolted external libraries. + +### 1. Baseline Performance (No BOLT) + +| Metric | Read-Only (Baseline) | Write-Only (Baseline) | Read+Write (Baseline) | +|---------------------------|----------------------|------------------------|------------------------| +| Transactions/sec (TPS) | 1006.33 | 2113.03 | 649.15 | +| Queries/sec (QPS) | 16,101.24 | 12,678.18 | 12,983.09 | +| Latency avg (ms) | 0.99 | 0.47 | 1.54 | +| Latency 95th % (ms) | 1.04 | 0.83 | 1.79 | +| Total time (s) | 9.93 | 4.73 | 15.40 | + +--- + +### 2. Performance Comparison: Merged vs Non-Merged Instrumentation + +| Metric | Regular BOLT R+W (No Merge, system libssl) | Merged BOLT (BOLTed Read+Write + BOLTed libssl) | +|---------------------------|---------------------------------------------|-------------------------------------------------| +| Transactions/sec (TPS) | 850.32 | 879.18 | +| Queries/sec (QPS) | 17,006.35 | 17,583.60 | +| Latency avg (ms) | 1.18 | 1.14 | +| Latency 95th % (ms) | 1.52 | 1.39 | +| Total time (s) | 11.76 | 11.37 | + +Second run: + +| Metric | Regular BOLT R+W (No Merge, system libssl) | Merged BOLT (BOLTed Read+Write + BOLTed libssl) | +|---------------------------|---------------------------------------------|-------------------------------------------------| +| Transactions/sec (TPS) | 853.16 | 887.14 | +| Queries/sec (QPS) | 17,063.22 | 17,742.89 | +| Latency avg (ms) | 1.17 | 1.13 | +| Latency 95th % (ms) | 1.39 | 1.37 | +| Total time (s) | 239.9 | 239.9 | + +--- + +### 3. BOLTed READ, BOLTed WRITE, MERGED BOLT (Read+Write+BOLTed Libraries) + +| Metric | Bolted Read-Only | Bolted Write-Only | Merged BOLT (Read+Write+libssl) | Merged BOLT (Read+Write+libcrypto) | Merged BOLT (Read+Write+libssl+libcrypto) | +|---------------------------|---------------------|-------------------|----------------------------------|------------------------------------|-------------------------------------------| +| Transactions/sec (TPS) | 1348.47 | 3170.92 | 887.14 | 896.58 | 902.98 | +| Queries/sec (QPS) | 21575.45 | 19025.52 | 17742.89 | 17931.57 | 18059.52 | +| Latency avg (ms) | 0.74 | 0.32 | 1.13 | 1.11 | 1.11 | +| Latency 95th % (ms) | 0.77 | 0.55 | 1.37 | 1.34 | 1.34 | +| Total time (s) | 239.8 | 239.72 | 239.9 | 239.9 | 239.9 | + +--- + +### Key Metrics to Analyze + +- **TPS (Transactions Per Second)**: Higher is better. +- **QPS (Queries Per Second)**: Higher is better. +- **Latency (Average and 95th Percentile)**: Lower is better. + +--- + +### Conclusion +- BOLT substantially improves performance over non-optimized binaries due to better instruction cache utilization and reduced execution path latency. +- Merging feature-specific profiles does not negatively affect performance; instead, it captures a broader set of runtime behaviors, making the binary better tuned for varied real-world workloads. +- Separately optimizing external user-space libraries, even though providing smaller incremental gains, further complements the overall application optimization, delivering a fully optimized execution environment.