Transpiler Integration - The Renacer Book - Pure Rust System Call Tracing
Description: A comprehensive guide to renacer: syscall tracing, DWARF correlation, and performance analysis

# Transpiler Integration

Renacer supports source mapping for transpiled code, allowing you to trace binaries back to their original high-level source (Python, C, TypeScript, etc.) instead of just the generated Rust code.

## Overview

When you transpile code (e.g., Python → Rust via Depyler, C → Rust via Decy), Renacer can:

- Map syscalls back to original source files (`.py`, `.c`, `.ts`)
- Show original function names instead of generated ones
- Display original line numbers from your source code
- Track transpiler optimization decisions

## Supported Transpilers

### Depyler (Python → Rust)

    # Transpile Python to Rust with source map
    depyler transpile app.py --output app.rs --source-map app.map.json

    # Compile with debug info
    rustc app.rs -g -o app

    # Trace with source mapping
    renacer --transpiler-map app.map.json -- ./app

Output:

    read(3, buf, 1024) = 42    [app.py:15 in read_config]  ← Original Python!

### Decy (C → Rust)

    # Transpile C to Rust with source map
    decy convert main.c --output main.rs --source-map main.map.json

    # Compile with debug info
    rustc main.rs -g -o main

    # Trace with source mapping
    renacer --transpiler-map main.map.json -- ./main

Output:

    write(1, "Hello", 5) = 5   [main.c:42 in printf_wrapper]  ← Original C!

### Generic Transpiler Support

Renacer supports any transpiler that generates source maps in this format:

    {
      "version": 1,
      "source_language": "python",
      "target_language": "rust",
      "mappings": [
        {
          "generated_file": "app.rs",
          "generated_line": 150,
          "original_file": "app.py",
          "original_line": 15,
          "original_function": "read_config",
          "transpiler_decision": {
            "optimization": "inline_small_function",
            "reasoning": "Function body <10 lines"
          }
        }
      ]
    }

## Source Map Format

### Required Fields

- `version`: Source map format version (currently `1`)
- `source_language`: Original language (e.g., "python", "c", "typescript")
- `target_language`: Target language (typically "rust")
- `mappings`: Array of line mappings

### Mapping Entry

Each mapping entry contains:

    {
      "generated_file": "output.rs",      // Generated Rust file
      "generated_line": 100,              // Line in generated code
      "original_file": "input.py",        // Original source file
      "original_line": 25,                // Line in original source
      "original_function": "my_function", // Original function name (optional)
      "transpiler_decision": {            // Optimization metadata (optional)
        "optimization": "vectorize_loop",
        "reasoning": "Simple iteration pattern detected"
      }
    }

### Optional Fields

- `original_function`: Function name in original source
- `transpiler_decision`: Metadata about transpiler optimizations
  - `optimization`: Name of optimization applied
  - `reasoning`: Human-readable explanation

## Basic Usage

### 1. Simple Source Mapping

    renacer --transpiler-map source.map.json -- ./app

Shows original source locations:

    openat(AT_FDCWD, "/config.json", O_RDONLY) = 3
      [config.py:10 in load_settings]

    read(3, buf, 1024) = 512
      [config.py:11 in load_settings]

### 2. Combined with DWARF

    renacer --source --transpiler-map source.map.json -- ./app

Renacer prefers transpiler mappings over DWARF when available:

1. Check transpiler map first
2. Fall back to DWARF debug info if no mapping found
3. Fall back to no source info if neither available

### 3. With Function Profiling

    renacer --function-time --transpiler-map source.map.json -- ./app

Output:

    Function Profiling Summary:
    ========================
    Top 10 Hot Paths (by total time):
      1. load_settings [config.py:10]      - 45.2% (1.2s, 67 syscalls)
      2. process_data [main.py:25]         - 32.1% (850ms, 45 syscalls)
      3. write_output [output.py:100]      - 15.3% (400ms, 23 syscalls)

Original function names from your source code!

### 4. With OTLP Export

    renacer \
      --transpiler-map source.map.json \
      --otlp-endpoint http://localhost:4317 \
      -- ./app

Spans include transpiler attributes:

    {
      "source.file": "config.py",
      "source.line": 10,
      "source.function": "load_settings",
      "transpiler.source_language": "python",
      "transpiler.decision": "inline_small_function"
    }

## Advanced Features

### Tracking Transpiler Decisions

Source maps can include optimization metadata:

    {
      "generated_line": 200,
      "original_line": 50,
      "transpiler_decision": {
        "optimization": "simd_vectorization",
        "reasoning": "Loop with constant stride, vectorizable"
      }
    }

View in traces:

    renacer --transpiler-map source.map.json --show-transpiler-decisions -- ./app

Output:

    read(3, buf, 8192) = 8192
      [data.py:50 in process_batch]
      💡 Transpiler: simd_vectorization (Loop with constant stride, vectorizable)

### Multi-Language Projects

Support multiple transpiled modules:

    # Combine source maps
    renacer \
      --transpiler-map module1.map.json \
      --transpiler-map module2.map.json \
      --transpiler-map module3.map.json \
      -- ./app

Renacer automatically:

- Merges all mappings
- Detects conflicts (warns if same generated line maps to multiple sources)
- Routes each syscall to correct source map

### Ruchy Runtime Integration

Renacer integrates with Ruchy Runtime for transpiler decision tracking:

    # Trace with Ruchy runtime context
    renacer \
      --transpiler-map output.map.json \
      --ruchy-trace-decisions \
      --otlp-endpoint http://localhost:4317 \
      -- ./ruchy-transpiled-app

This links:

- Syscalls → Original source lines
- Source lines → Transpiler decisions
- Decisions → Runtime performance
- Performance → OTLP observability backend

### Trueno SIMD Block Tracing

When tracing Trueno-accelerated code:

    renacer \
      --transpiler-map trueno.map.json \
      --trace-simd-blocks \
      -- ./trueno-app

Renacer emits special spans for SIMD compute blocks:

    Span: simd_block
      source.file: stats.py
      source.line: 100
      source.function: calculate_percentiles
      simd.instruction_set: AVX2
      simd.vector_width: 256
      compute.block_id: trueno_block_42

## Generating Source Maps

### From Depyler

    depyler transpile input.py \
      --output output.rs \
      --source-map output.map.json \
      --track-decisions

### From Decy

    decy convert input.c \
      --output output.rs \
      --source-map output.map.json \
      --preserve-line-mapping

### Custom Transpiler

If building your own transpiler, implement source map generation:

    use serde::{Serialize, Deserialize};

    #[derive(Serialize, Deserialize)]
    struct SourceMap {
        version: u32,
        source_language: String,
        target_language: String,
        mappings: Vec<Mapping>,
    }

    #[derive(Serialize, Deserialize)]
    struct Mapping {
        generated_file: String,
        generated_line: u32,
        original_file: String,
        original_line: u32,
        original_function: Option<String>,
        transpiler_decision: Option<Decision>,
    }

    #[derive(Serialize, Deserialize)]
    struct Decision {
        optimization: String,
        reasoning: String,
    }

    // Generate mappings during transpilation
    fn transpile_with_mapping() {
        let mut mappings = Vec::new();

        // For each line transformation
        mappings.push(Mapping {
            generated_file: "output.rs".to_string(),
            generated_line: 100,
            original_file: "input.py".to_string(),
            original_line: 25,
            original_function: Some("process_data".to_string()),
            transpiler_decision: Some(Decision {
                optimization: "loop_unrolling".to_string(),
                reasoning: "Fixed iteration count detected".to_string(),
            }),
        });

        let source_map = SourceMap {
            version: 1,
            source_language: "python".to_string(),
            target_language: "rust".to_string(),
            mappings,
        };

        // Write to file
        std::fs::write(
            "output.map.json",
            serde_json::to_string_pretty(&source_map).unwrap()
        ).unwrap();
    }

## Validation

Renacer validates source maps on load:

### Version Check

    Error: Unsupported source map version: 2 (expected: 1)

Solution: Update Renacer or regenerate source map with version 1.

### Required Fields

    Error: Missing required field: source_language

Solution: Ensure source map includes all required fields.

### Line Number Bounds

    Warning: Mapping references line 1000 in output.rs (file only has 500 lines)

Solution: Regenerate source map after modifying generated code.

## Best Practices

### 1. Always Generate with Debug Symbols

    # ✅ Good: Debug symbols + source map
    rustc output.rs -g -o app
    renacer --transpiler-map output.map.json -- ./app

    # ❌ Bad: Source map without debug symbols (limited utility)
    rustc output.rs -o app
    renacer --transpiler-map output.map.json -- ./app

### 2. Keep Source Maps Up-to-Date

    # Regenerate after each transpilation
    depyler transpile app.py --output app.rs --source-map app.map.json

### 3. Include Function Names

    {
      "original_function": "load_config",  // ✅ Helpful for profiling
      "original_function": null             // ❌ Less useful
    }

### 4. Track Important Decisions

    {
      "transpiler_decision": {
        "optimization": "vectorize_loop",      // ✅ Useful for debugging
        "reasoning": "Performance boost +40%"
      }
    }

### 5. Combine with OTLP for Observability

    # Full stack observability with original source
    renacer \
      --source \
      --transpiler-map app.map.json \
      --otlp-endpoint http://localhost:4317 \
      -- ./app

## Troubleshooting

### Source Map Not Found

    Error: Failed to read source map: No such file or directory

Solution:

    # Verify file exists
    ls -la output.map.json

    # Use absolute path if needed
    renacer --transpiler-map /absolute/path/to/output.map.json -- ./app

### Mappings Not Applied

    Warning: No mapping found for output.rs:150

Causes:

1. Source map incomplete (missing lines)
2. Source map out of date (code changed after generation)
3. Generated code modified after transpilation

Solution: Regenerate source map.

### Conflicting Mappings

    Warning: Multiple mappings for output.rs:100 (using first)

Solution: Check for duplicate entries in source map:

    # Validate source map
    jq '.mappings[] | select(.generated_line == 100)' output.map.json

### Original File Not Found

    Warning: Original file not found: input.py

Solution: Ensure original source files are accessible:

    # Use absolute paths in source map
    # Or ensure files are in working directory

## Performance Impact

Transpiler mapping overhead:

- Loading source map: One-time cost at startup (<10ms for 10K mappings)
- Lookup per syscall: <1μs (hash map lookup)
- Total overhead: <0.1% (negligible)

## Example: Python → Rust Workflow

Complete example with Depyler:

    # 1. Write Python code
    cat > app.py << 'EOF'
    def read_config(path):
        with open(path) as f:
            return f.read()

    def main():
        config = read_config("/etc/app.conf")
        print(f"Config: {config}")

    if __name__ == "__main__":
        main()
    EOF

    # 2. Transpile to Rust with source map
    depyler transpile app.py \
      --output app.rs \
      --source-map app.map.json \
      --track-decisions

    # 3. Compile with debug symbols
    rustc app.rs -g -o app

    # 4. Trace with full observability
    renacer \
      --source \
      --function-time \
      --transpiler-map app.map.json \
      --otlp-endpoint http://localhost:4317 \
      -- ./app

    # Output shows Python source!
    openat(AT_FDCWD, "/etc/app.conf", O_RDONLY) = 3
      [app.py:2 in read_config]

    read(3, buf, 8192) = 156
      [app.py:3 in read_config]
      💡 Transpiler: buffered_io_optimization

## Next Steps

- OpenTelemetry Integration - Export transpiler metadata
- Distributed Tracing - Trace across services
- Function Profiling - Profile with original names