# ZView, a Zephyr RTOS runtime visualizer

Zephyr RTOS system-wide runtime visualizer via SWD probe!

Take a broader look on your Zephyr application with a non-heavy, small footprint, Kconfig-only thread stats analyser.

> **Looking for the standalone pip installation?** See [README_pip.md](README_pip.md).

---

## Prerequisites

To properly analyze your Zephyr app, your ELF binary must be compiled with specific Kconfig options enabled:

```
## prj.conf
CONFIG_INIT_STACKS=y            # Required for stack watermarks
CONFIG_THREAD_MONITOR=y         # Required for thread discovery
CONFIG_THREAD_STACK_INFO=y      # Required for thread metadata

# Optional Features
CONFIG_THREAD_NAME=y            # Enables thread name display
CONFIG_THREAD_RUNTIME_STATS=y   # Enables CPU usage tracking
CONFIG_SYS_HEAP_RUNTIME_STATS=y # Enables heap runtime stats
```


## Installation

Add this snippet to your west manifest:

```yaml
manifest:
  projects:
    - name: zview
      url: https://github.com/wkhadgar/zview
      revision: main
      path: modules/tools/zview
      west-commands: scripts/west-commands.yml
```

Then fetch it with:

```
west update zview
```


## How to Use

If your board is already flashed and probed, ZView can often infer the ELF path and runner from the build directory — just run:

```
# From project root
west zview
```

Or pass arguments explicitly:

```
# Example: nRF5340 DK via JLink
west zview -e build/zephyr/zephyr.elf -r jlink -t nRF5340_xxAA
```


## Arguments

| Argument | Description |
| --- | --- |
| `-e, --elf-file` | Path to the firmware `.elf` file (e.g. `build/zephyr/zephyr.elf`). |
| `-r, --runner` | Debug runner to use: `jlink`, `pyocd`, or `gdb`. |
| `-t, --runner-target` | MCU descriptor for the chosen runner (see below). |
| `--period` | Update period in seconds, can be a float. |

<details>
<summary><strong>Finding the right value for <code>-t</code></strong></summary>
<br>

The `-t` argument is the MCU descriptor name **as expected by your chosen runner**. How to find it depends on the runner:

**JLink (`-r jlink`)**
Use the device name from the [J-Link Supported Devices list](https://www.segger.com/downloads/supported-devices.php).
```
# Example: Nordic nRF5340 DK
west zview -e build/zephyr/zephyr.elf -r jlink -t nRF5340_xxAA
```

**pyOCD (`-r pyocd`)**
Run `pyocd list --targets` to see the available target names for your installed packs.
```
pyocd list --targets          # find your target name

# Example: STM32F401 Nucleo
west zview -e build/zephyr/zephyr.elf -r pyocd -t stm32f401xe
```

**GDB server (`-r gdb`)**
Pass the `host:port` of your GDB server instead of a device name.
```
west zview -e build/zephyr/zephyr.elf -r gdb -t localhost:1234
```

> **Tip:** The runner and target are often already defined in `build/zephyr/runners.yaml` (generated by `west build`). In that case you can omit `-r` and `-t` entirely and ZView will pick them up automatically.

</details>


## Navigation

ZView acts as a TUI. Navigate with **UP** and **DOWN** arrows from the default view:

* **ENTER**: Track CPU usage for a specific thread (hit ENTER again to return).
* **S / I**: Sort the data and invert the sorting order.
* **H**: Access the **Heap Runtime** visualization.

[![TUI navigation](https://github.com/wkhadgar/zview/raw/main/docs/assets/default_view_1.png)](https://github.com/wkhadgar/zview/blob/main/docs/assets/default_view_1.png)

[![TUI navigation 2](https://github.com/wkhadgar/zview/raw/main/docs/assets/default_view_2.png)](https://github.com/wkhadgar/zview/blob/main/docs/assets/default_view_2.png)

[![TUI thread tracking](https://github.com/wkhadgar/zview/raw/main/docs/assets/thread_detail_1.png)](https://github.com/wkhadgar/zview/blob/main/docs/assets/thread_detail_1.png)

[![TUI heap navigation](https://github.com/wkhadgar/zview/raw/main/docs/assets/heaps_view_1.png)](https://github.com/wkhadgar/zview/blob/main/docs/assets/heaps_view_1.png)

[![TUI heap navigation 2](https://github.com/wkhadgar/zview/raw/main/docs/assets/heaps_view_2.png)](https://github.com/wkhadgar/zview/blob/main/docs/assets/heaps_view_2.png)

---

## Advanced

<details>
<summary><strong>QEMU/GDB Targets</strong></summary>
<br>

If `debugserver` is available:

```
west debugserver
```

Or launch a GDB server from QEMU directly with `-s` — this will be necessary if you have no `runners.yaml` (e.g. `mps2/an385`):

```
qemu-system-arm \
  -machine mps2-an385 \
  -cpu cortex-m3 \
  -kernel build/zephyr/zephyr.elf \
  -nographic \
  -serial mon:stdio \
  -s -S
```

Then attach ZView:

```
west zview -r gdb -t localhost:1234
```

> **Note:** Due to GDB server limitations, when using `-r gdb` the target is briefly halted prior to memory reads. Be aware of this side effect.

</details>

<details>
<summary><strong>How it works</strong></summary>
<br>

ZView achieves a minimal footprint by avoiding on-target processing or UART/Shell output. It utilizes the debug probe's ability to read memory via the APB bus without halting the CPU. By parsing the ELF file, ZView identifies kernel object locations and performs analysis of stack watermarks and CPU usage.

> **Note:** The `idle` thread is implicit and only expresses itself on the used CPU %, when available.

</details>


## Roadmap

Based on community feedback, the following features are in development:

* Heap fragmentation visualization.
* Detailed thread metrics (e.g., context switch counts).

Feel free to open an [issue](https://github.com/wkhadgar/zview/issues) if you feel like this has some potential!
