diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-09 18:34:20 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-09 18:34:20 +0100 |
| commit | 26915d8c47260f90d67df8c6af1f16ba7607a3d5 (patch) | |
| tree | c01f1e6bfe0cb85a27f5fc94ed01dea7aa9b969e /doc/SIZE_MEASUREMENT.md | |
| parent | 82fcfd2656a9f7085c54407d9c390a7d413c4b5a (diff) | |
feat: Implement Task #76 external library size measurement
- Use ma_backend_null for audio (100-200KB savings)
- Stub platform/gpu abstractions instead of external APIs
- Add DEMO_STRIP_EXTERNAL_LIBS build mode
- Create stub_types.h with minimal WebGPU opaque types
- Add scripts/measure_size.sh for automated measurement
Results: Demo=4.4MB, External=2.0MB (69% vs 31%)
handoff(Claude): Task #76 complete. Binary compiles but doesn't run (size measurement only).
Diffstat (limited to 'doc/SIZE_MEASUREMENT.md')
| -rw-r--r-- | doc/SIZE_MEASUREMENT.md | 383 |
1 files changed, 124 insertions, 259 deletions
diff --git a/doc/SIZE_MEASUREMENT.md b/doc/SIZE_MEASUREMENT.md index b997ea5..96c8e6c 100644 --- a/doc/SIZE_MEASUREMENT.md +++ b/doc/SIZE_MEASUREMENT.md @@ -2,340 +2,205 @@ ## Goal -Measure the true binary size of demo code vs external library overhead by stubbing out all system dependencies with minimal implementations. +Measure true demo code size by stubbing external library dependencies. -**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 +**Motivation:** STRIP_ALL builds (~5MB) include wgpu_native (~3.5MB), GLFW (~500KB), miniaudio. Need to isolate demo code size for 64KB target tracking. -## Problem Statement +## Strategy -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 +Two-part approach: -## 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; -} +### 1. Audio: Use miniaudio's Null Backend -WGPUAdapter wgpuInstanceRequestAdapter(...) { - return (WGPUAdapter)0; -} +miniaudio has built-in `ma_backend_null` that excludes platform audio drivers: -// ~200 functions to stub +```cmake +target_compile_definitions(demo64k PRIVATE + MA_ENABLE_ONLY_SPECIFIC_BACKENDS + MA_ENABLE_NULL +) ``` -**Strategy:** -- Parse `webgpu.h` to generate stubs automatically -- All pointers return nullptr -- All numeric returns = 0 -- All void functions are empty +**Savings:** ~100-200KB (excludes CoreAudio/WASAPI/ALSA/etc.) +**Benefit:** Audio synthesis still runs, but no driver overhead -#### 2. GLFW Stubs (`third_party/stubs/glfw3.c`) +### 2. GPU/Platform: Stub Our Own Abstractions -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 -``` +Instead of stubbing ~300 external functions, stub our ~10 platform/gpu wrappers: -#### 3. miniaudio Stubs (`third_party/stubs/miniaudio.c`) +**`src/platform/stub_types.h` (STRIP_EXTERNAL_LIBS only):** +```cpp +// Minimal WebGPU opaque types +typedef void* WGPUInstance; +typedef void* WGPUAdapter; +typedef void* WGPUDevice; +typedef void* WGPUBuffer; +typedef void* WGPUTexture; +// ... all types as void* -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 +struct WGPUBufferDescriptor {}; +struct WGPUTextureDescriptor {}; +// ... all descriptor structs empty ``` -#### 4. System Library Stubs +**`src/platform/stub_platform.cc`:** +```cpp +#if defined(STRIP_EXTERNAL_LIBS) +#include "stub_types.h" -**pthread:** -```c -int pthread_create(...) { return 0; } -int pthread_join(...) { return 0; } -int pthread_mutex_init(...) { return 0; } -// ~20 functions -``` +PlatformState platform_init(bool, int w, int h) { + return {w, h, nullptr, nullptr}; +} -**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 +void platform_poll_events() {} +bool platform_should_close() { return false; } +void platform_shutdown() {} +void platform_present() {} +double platform_get_time() { return 0.0; } +#endif ``` -**Platform-specific (macOS):** -```c -// Stub Metal/Foundation/Cocoa frameworks -// Minimal Objective-C stubs if needed +**`src/gpu/stub_gpu.cc`:** +```cpp +#if defined(STRIP_EXTERNAL_LIBS) +WGPUDevice gpu_create_device() { return nullptr; } +WGPUBuffer gpu_create_buffer(const WGPUBufferDescriptor*) { return nullptr; } +// ... stub ~20 gpu wrapper functions +#endif ``` -### Build System Integration +**Benefits:** +- Stub our API (~30 functions) vs external APIs (~300 functions) +- Opaque pointers only (no real struct definitions needed) +- Don't link wgpu_native or GLFW at all +- Actually measures demo code, not stub code + +## 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) + # Audio: Use null backend + target_compile_definitions(demo64k PRIVATE + MA_ENABLE_ONLY_SPECIFIC_BACKENDS + MA_ENABLE_NULL + ) - # Override library targets - set(DEMO_LIBS wgpu_stub glfw_stub miniaudio_stub system_stub) + # GPU/Platform: Use stubs + target_compile_definitions(demo64k PRIVATE STRIP_EXTERNAL_LIBS) + target_sources(demo64k PRIVATE + src/platform/stub_platform.cc + src/gpu/stub_gpu.cc + ) - # Minimal flags (no LTO to see unoptimized size) + # Don't link external libs + # (only math/pthread from system) + + # Size measurement flags set(CMAKE_C_FLAGS "-Os") set(CMAKE_CXX_FLAGS "-Os") endif() ``` -**Build command:** +**Build:** ```bash cmake -S . -B build_size -DDEMO_STRIP_EXTERNAL_LIBS=ON cmake --build build_size -j4 +strip build_size/demo64k ls -lh build_size/demo64k # True demo size ``` -## Implementation Plan - -### Phase 1: Stub Generation Tool +## Expected Results -**Script: `scripts/generate_stubs.py`** +``` +STRIP_ALL build: 5.1 MB +├── wgpu_native: 3.5 MB +├── GLFW: 0.5 MB +├── miniaudio (full): 0.3 MB +├── System libs: 0.3 MB +└── Demo code: 0.5 MB -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/ +STRIP_EXTERNAL_LIBS: 0.5 MB +└── Demo code only: 0.5 MB (100%) ``` -**Input:** Header files with annotations -**Output:** Complete stub .c files +Binary compiles but does NOT run (all I/O stubbed). -**Heuristics:** -- Pointer returns → nullptr -- Numeric returns → 0 -- Boolean returns → true/1 -- Void functions → empty body -- Enum returns → first enum value +## Implementation Plan -### Phase 2: Build System Integration +### Phase 1: Stub Type Definitions (1 hour) -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) +Create `src/platform/stub_types.h`: +- Define all WebGPU types as `typedef void*` +- Define all descriptor structs as empty `struct {}` +- Include guards for `STRIP_EXTERNAL_LIBS` -### Phase 3: Compatibility Layer +### Phase 2: Platform Stubs (1 hour) -Some demo code expects valid objects. Add thin shims: +Create `src/platform/stub_platform.cc`: +- Implement ~10 platform functions as no-ops +- Return dummy PlatformState with reasonable dimensions +- Compile only when `STRIP_EXTERNAL_LIBS` defined -**`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 -``` +### Phase 3: GPU Stubs (1 hour) -**`src/audio/stub_audio.cc`:** -```cpp -#if defined(STRIP_EXTERNAL_LIBS) -// Override audio_init to skip miniaudio -void audio_init() {} -void audio_start() {} -#endif -``` +Create `src/gpu/stub_gpu.cc`: +- Implement ~20 gpu wrapper functions as no-ops +- All pointer returns = nullptr +- All void functions = empty body + +### Phase 4: Build Integration (1 hour) -### Phase 4: Validation +Update `CMakeLists.txt`: +- Add `DEMO_STRIP_EXTERNAL_LIBS` option +- Enable ma_backend_null defines +- Add stub source files conditionally +- Remove external library linking + +### Phase 5: Validation (1 hour) -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 +size build_size/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) +**Estimated time: 5 hours** ## Use Cases -### 1. Size Budget Tracking +**Weekly size tracking:** ```bash -# Weekly measurement -./scripts/measure_size.sh -# Outputs: Demo=512KB, External=4.5MB +./scripts/measure_size.sh # Demo=512KB, External=4.5MB ``` -### 2. Optimization Targeting -Identify which subsystems contribute most to demo size: +**Subsystem attribution:** - GPU effects: 150KB - 3D rendering: 120KB - Audio synthesis: 100KB - Asset system: 80KB -### 3. CI Integration -Track size growth over time: +**CI size monitoring:** ```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" +- run: cmake -B build_size -DDEMO_STRIP_EXTERNAL_LIBS=ON +- run: size build_size/demo64k | tee size_report.txt ``` -## 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 +1. Binary compiles with `STRIP_EXTERNAL_LIBS=ON` +2. Size < 1MB (confirms external lib isolation) +3. Repeatable builds +4. Tracks size changes over time ## 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 +**New:** +- `src/platform/stub_types.h` - WebGPU opaque types +- `src/platform/stub_platform.cc` - Platform stubs (~10 functions) +- `src/gpu/stub_gpu.cc` - GPU stubs (~20 functions) - `scripts/measure_size.sh` - Size measurement script -**Modified files:** +**Modified:** - `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) |
