# Run and Profile

> Run a guest in Apogee's emulator from Rust or from the command line, compare it with your host build, and find out where its cycles go before you pay to prove them.

Running a guest costs almost nothing; proving it costs in proportion to the cycles it runs. So run first, compare against your host build, and look at the cycle profile before you prove anything.

## From Rust: the emulator

`emulator::run` executes a loaded image over a public input and advice, in host code, with no proof:

```rust title="Run a guest and compare it with the host build"
let elf = std::fs::read(elf_path)?;
let image = loader::load_elf(&elf).expect("the ELF loads");
let io = emulator::GuestIo { input: b"hi".to_vec(), advice: Vec::new() };
let run = emulator::run(&image, &io).expect("no fatal error");

assert_eq!(run.exit_code, 0);
assert_eq!(run.io.output, my_app::run(b"hi", &[]).unwrap()); // the host build agrees
println!("{} cycles", run.cycle_count);
```

`run` returns an `Execution`: the final registers, the exit status, the cycle count and the public values. A nonzero exit status is an execution, not an error, and comes back as `exit_code`. A fatal executor error, such as `OutOfBounds`, `Misaligned` or `NotAnInstruction`, comes back as an `EmuError`, and such a run has no proof ([Troubleshooting](https://apogee.gweb3networks.com/docs/launch/troubleshooting#fatal)).

The emulator is a pure function of the image and the input: no clock, no randomness, no threads. The same input gives the same execution, cycle for cycle, which is also what lets the prover execute twice and cut identical shards.

## From the command line: the profiler

```sh
cargo run --release -p profiler -- elf <elf> [--input <file>] [--advice <file>] [--top <n>] [--json ]
```

It runs the guest over the given files at the smallest table height its code fits, and prints a report. Its numbers are counts of executed cycles, the same on any machine.

```text
workload
  label                        hello
  guest cycles                 114
  exit status                  0
  journal bytes                13

cycles by semantic workload
  core runtime                             94   82.46%
  unattributed                             20   17.54%

cycles by family
  ADD_SUB_LUI_AUIPC            64
  JUMP_BRANCH_SLT              21
  MEM_WORD                     3
  MEM_SUBWORD                  26

top functions
            94   82.46%          1 calls        94.0 c/call  guest_sdk::commit  [core runtime]
             8    7.02%          1 calls         8.0 c/call  main  [unattributed]
```

How to read it:

- **Cycles by family** is what you pay for. Each family with rows costs at least one shard of its height, and more cycles in a family means more shards of it.
- **Top functions** charges each function for its own cycles, including everything the compiler inlined into it, but not its callees. Calls are counted at the function's first instruction.
- **Cycles by semantic workload** groups functions into fourteen categories by name, such as hashing, signatures and the core runtime. The unattributed share and the mnemonic mix are the checks on that attribution, since no symbol table can mislabel them.
- **Accelerator candidates** price the delegations a future version could add, as a ceiling: see [Delegations](https://apogee.gweb3networks.com/docs/launch/delegations#pricing).

The profiler has two more verbs, for the Ethereum workload: `block <stem>` runs the revm guest over a recorded fixture, and `record <number|latest>` records a block from `ETH_RPC_URL` and runs it.

## Make it cheaper

The order that usually pays:

1. **Build `--release`.** Optimization removes a quarter to over half of a guest's instructions.
2. **Delegate hashing and curve arithmetic.** Use `guest_sdk::keccak256`, `sha256`, `ec_add` and the vendored `k256` and `ark-ff`, instead of compiling a software implementation into the guest.
3. **Stop allocating in loops.** Each allocation is instructions, and with a bump allocator it is also memory you never get back ([the heap](https://apogee.gweb3networks.com/docs/launch/write#heap)).
4. **Check instead of compute.** If a result is expensive to find and cheap to verify, such as a sorted order, a square root or a path through a tree, let the prover supply it as advice and have the guest verify it.
5. **Avoid floating point.** It compiles to software routines; integer and fixed-point arithmetic are far cheaper.

Then measure again. Cycle counts are exact and repeatable, so every change shows up as a number.
