# External Library Size Measurement (Task #76) ## Goal Measure the true binary size of demo code vs external library overhead by stubbing out all system dependencies with minimal implementations. **Motivation:** Current STRIP_ALL builds include wgpu_native (~3-4MB), GLFW, and system libraries. We need to isolate core demo size to: - Track size budget accurately - Identify optimization targets - Measure progress toward 64KB goal ## Problem Statement Current size breakdown is opaque: ``` STRIP_ALL build: ~5.1MB total ├── wgpu_native: ~3-4MB (estimate) ├── GLFW: ~500KB (estimate) ├── System libs: ~500KB (estimate) └── Demo code: ??? KB (unknown) ``` **Goal:** Measure demo code size precisely by replacing external dependencies with stubs. ## Approach Create `STRIP_EXTERNAL_LIBS` build mode: - Replaces real libraries with minimal stub implementations - Functions compile but do nothing (return nullptr, no-ops) - Binary compiles successfully but **does not run** - Purpose: Size measurement only ## Architecture ### Stub Implementations #### 1. wgpu_native Stubs (`third_party/stubs/wgpu_native.c`) Minimal WebGPU API implementation: ```c // All functions return nullptr or void WGPUInstance wgpuCreateInstance(const WGPUInstanceDescriptor* desc) { (void)desc; return (WGPUInstance)0; } WGPUAdapter wgpuInstanceRequestAdapter(...) { return (WGPUAdapter)0; } // ~200 functions to stub ``` **Strategy:** - Parse `webgpu.h` to generate stubs automatically - All pointers return nullptr - All numeric returns = 0 - All void functions are empty #### 2. GLFW Stubs (`third_party/stubs/glfw3.c`) Window/input API stubs: ```c int glfwInit(void) { return 1; } void glfwTerminate(void) {} GLFWwindow* glfwCreateWindow(...) { return (GLFWwindow*)0; } void glfwPollEvents(void) {} int glfwWindowShouldClose(GLFWwindow* w) { (void)w; return 0; } // ~100 functions ``` #### 3. miniaudio Stubs (`third_party/stubs/miniaudio.c`) Audio backend stubs: ```c ma_result ma_context_init(...) { return MA_SUCCESS; } ma_result ma_device_init(...) { return MA_SUCCESS; } ma_result ma_device_start(...) { return MA_SUCCESS; } void ma_device_stop(...) {} void ma_device_uninit(...) {} // ~50 functions used by demo ``` #### 4. System Library Stubs **pthread:** ```c int pthread_create(...) { return 0; } int pthread_join(...) { return 0; } int pthread_mutex_init(...) { return 0; } // ~20 functions ``` **Math (libm):** ```c double sin(double x) { (void)x; return 0.0; } double cos(double x) { (void)x; return 0.0; } float sinf(float x) { (void)x; return 0.0f; } // ~30 functions ``` **Platform-specific (macOS):** ```c // Stub Metal/Foundation/Cocoa frameworks // Minimal Objective-C stubs if needed ``` ### Build System Integration **CMakeLists.txt:** ```cmake if(DEMO_STRIP_EXTERNAL_LIBS) # Build stub libraries add_library(wgpu_stub STATIC third_party/stubs/wgpu_native.c) add_library(glfw_stub STATIC third_party/stubs/glfw3.c) add_library(miniaudio_stub STATIC third_party/stubs/miniaudio.c) add_library(system_stub STATIC third_party/stubs/system.c) # Override library targets set(DEMO_LIBS wgpu_stub glfw_stub miniaudio_stub system_stub) # Minimal flags (no LTO to see unoptimized size) set(CMAKE_C_FLAGS "-Os") set(CMAKE_CXX_FLAGS "-Os") endif() ``` **Build command:** ```bash cmake -S . -B build_size -DDEMO_STRIP_EXTERNAL_LIBS=ON cmake --build build_size -j4 ls -lh build_size/demo64k # True demo size ``` ## Implementation Plan ### Phase 1: Stub Generation Tool **Script: `scripts/generate_stubs.py`** Parses header files and generates stub implementations: ```python # Parse webgpu.h, glfw3.h, miniaudio.h # Extract function signatures # Generate minimal implementations # Output to third_party/stubs/ ``` **Input:** Header files with annotations **Output:** Complete stub .c files **Heuristics:** - Pointer returns → nullptr - Numeric returns → 0 - Boolean returns → true/1 - Void functions → empty body - Enum returns → first enum value ### Phase 2: Build System Integration 1. Add `DEMO_STRIP_EXTERNAL_LIBS` option 2. Create stub library targets 3. Override `DEMO_LIBS` when flag enabled 4. Disable features requiring runtime (audio playback, window creation) ### Phase 3: Compatibility Layer Some demo code expects valid objects. Add thin shims: **`src/platform/stub_platform.cc`:** ```cpp #if defined(STRIP_EXTERNAL_LIBS) // Override platform_init to skip GLFW PlatformState platform_init(bool, int, int) { PlatformState state = {}; state.width = 1280; state.height = 720; return state; } #endif ``` **`src/audio/stub_audio.cc`:** ```cpp #if defined(STRIP_EXTERNAL_LIBS) // Override audio_init to skip miniaudio void audio_init() {} void audio_start() {} #endif ``` ### Phase 4: Validation Ensure binary compiles and links: ```bash # Should compile successfully cmake -S . -B build_size -DDEMO_STRIP_EXTERNAL_LIBS=ON cmake --build build_size -j4 # Size measurement ls -lh build_size/demo64k # Strip debug symbols strip build_size/demo64k ls -lh build_size/demo64k # Compare with real build ls -lh build_strip/demo64k ``` ## Expected Results **Size Breakdown (Projected):** ``` Real STRIP_ALL build: 5.1 MB ├── wgpu_native: 3.5 MB (68%) ├── GLFW: 0.5 MB (10%) ├── System libs: 0.6 MB (12%) └── Demo code: 0.5 MB (10%) STRIP_EXTERNAL_LIBS build: 0.5 MB └── Demo code only: 0.5 MB (100%) ``` **Validation:** - Binary compiles without errors - All symbols resolve - Size is significantly smaller (< 1MB) - Binary does NOT run (expected) ## Use Cases ### 1. Size Budget Tracking ```bash # Weekly measurement ./scripts/measure_size.sh # Outputs: Demo=512KB, External=4.5MB ``` ### 2. Optimization Targeting Identify which subsystems contribute most to demo size: - GPU effects: 150KB - 3D rendering: 120KB - Audio synthesis: 100KB - Asset system: 80KB ### 3. CI Integration Track size growth over time: ```yaml # .github/workflows/size_check.yml - name: Measure demo size run: | cmake -B build_size -DDEMO_STRIP_EXTERNAL_LIBS=ON size=$(stat -f%z build_size/demo64k) echo "Demo size: $size bytes" ``` ## Trade-offs ### Pros - Accurate size measurement - Identifies optimization targets - Simple implementation (stubs) - No runtime required ### Cons - Maintenance burden (stubs must match real APIs) - Binary doesn't run (testing impossible) - Platform-specific stubbing (macOS frameworks complex) - Stub generation tool needs maintenance ### Alternative Approaches **1. Link-time size analysis:** ```bash # Use linker map to attribute size -Wl,-map,output.map # Parse map file to see per-symbol sizes ``` **Pro:** No stubs needed **Con:** Complex parsing, less accurate **2. Binary diff analysis:** ```bash # Build with/without each library # Diff binary sizes ``` **Pro:** Simpler **Con:** Doesn't isolate demo code cleanly **3. Compiler size reports:** ```bash -ffunction-sections -fdata-sections -Wl,--print-gc-sections ``` **Pro:** Built-in tooling **Con:** Still includes external library overhead **Chosen:** Stub approach (most accurate, clear results) ## Implementation Effort **Estimated time: 8-12 hours** - Phase 1: Stub generation (3-4 hours) - Phase 2: Build integration (2-3 hours) - Phase 3: Compatibility layer (2-3 hours) - Phase 4: Validation & documentation (1-2 hours) **Priority:** Low (measurement tool, not critical for demo) ## Success Criteria 1. Binary compiles successfully with `STRIP_EXTERNAL_LIBS=ON` 2. Size < 1MB (proves external lib overhead is measured) 3. Repeatable builds produce consistent sizes 4. Can track size changes over time 5. Documentation clear for future use ## Related Files **New files:** - `third_party/stubs/wgpu_native.c` - WebGPU stubs (~200 functions) - `third_party/stubs/glfw3.c` - GLFW stubs (~100 functions) - `third_party/stubs/miniaudio.c` - Audio stubs (~50 functions) - `third_party/stubs/system.c` - System library stubs (pthread, math) - `scripts/generate_stubs.py` - Stub generation tool - `scripts/measure_size.sh` - Size measurement script **Modified files:** - `CMakeLists.txt` - Add STRIP_EXTERNAL_LIBS mode - `src/platform/platform.cc` - Conditional stub overrides - `src/audio/audio.cc` - Conditional stub overrides ## Notes - This is a **measurement tool**, not a runtime mode - Binary will not execute (all APIs stubbed) - Useful for tracking optimization progress - Can reveal surprising size contributors - Platform-specific (stubs may differ on Windows/Linux/macOS)