> ## Documentation Index
> Fetch the complete documentation index at: https://dragonwingdocs.qualcomm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# libqcperf

> A lightweight C library for real-time performance monitoring on Qualcomm chipsets, with pluggable backends for CPU, NPU, and power/thermal metrics.

libqcperf is an open-source C library for real-time hardware performance monitoring on Qualcomm platforms. It provides a unified API that dispatches to pluggable backends, each targeting a specific hardware subsystem. Data is collected asynchronously on a background thread and delivered to your application through a registered callback at a configurable streaming rate.

Source code and issue tracker: [github.com/qualcomm/libqcperf](https://github.com/qualcomm/libqcperf)

## Backends

Each backend targets a specific subsystem and platform. You select which backends to compile in at build time.

| Backend   | Platform      | Key metrics                                                                                           |
| --------- | ------------- | ----------------------------------------------------------------------------------------------------- |
| `DUMMY`   | All           | Synthetic metrics across two capabilities — useful for integration testing without hardware           |
| `CPU`     | Linux ARM64   | Per-core and aggregate CPU load (%), frequency (MHz), effective utilization (%), DCVS frequency limit |
| `NPU`     | Linux ARM64   | DSP/NPU Q6 utilization (%), Q6 clock (KHz), HVX utilization (%), HMX utilization (%)                  |
| `POWER`   | Windows ARM64 | Power consumption (mW) across CPU, GPU, and system components                                         |
| `THERMAL` | Windows ARM64 | Temperature (°C) across 22 thermal zones including CPU clusters and GPU                               |

## Build

### Linux ARM64 (cross-compile)

<Steps>
  <Step title="Install prerequisites">
    Download the ARM GNU Toolchain for your host and set the path:

    ```bash theme={null}
    export AARCH64_TOOLCHAIN_PATH=/path/to/arm-gnu-toolchain
    ```
  </Step>

  <Step title="Configure with CMake">
    ```bash theme={null}
    cmake -S qcperf -B build \
        -DTARGET_ARCH=linux-aarch64 \
        -DCMAKE_BUILD_TYPE=Release \
        -DProjectVersion="0.1.0.0" \
        -DBACKENDS="CPU;NPU;DUMMY" \
        -DBUILD_SHARED=OFF
    ```

    Key flags:

    | Flag                 | Values              | Description                                                                                        |
    | -------------------- | ------------------- | -------------------------------------------------------------------------------------------------- |
    | `-DTARGET_ARCH`      | `linux-aarch64`     | Selects the cross-compilation toolchain                                                            |
    | `-DCMAKE_BUILD_TYPE` | `Release` / `Debug` | Optimized build or debug symbols                                                                   |
    | `-DProjectVersion`   | `"0.1.0.0"`         | Version string embedded in the library                                                             |
    | `-DBACKENDS`         | `"CPU;NPU;DUMMY"`   | Semicolon-separated list of backends to compile in; omit to enable all platform-supported backends |
    | `-DBUILD_SHARED`     | `OFF` / `ON`        | Static `.a` or shared `.so`                                                                        |
  </Step>

  <Step title="Build">
    ```bash theme={null}
    cmake --build build
    ```

    Outputs land in the build directory root: `libQcPerfCore.a` (static) or `libQcPerfCore.so` (shared), and the `QcPerfCoreTest` executable.
  </Step>
</Steps>

### CMake presets

Edit `qcperf/CMakeUserPresets.json` to set `AARCH64_TOOLCHAIN_PATH` and `ProjectVersion` once, then use the named presets:

```bash theme={null}
cd qcperf
cmake --preset linux-aarch64-release
cmake --build --preset linux-aarch64-release
```

Available presets: `linux-aarch64-debug`, `linux-aarch64-release`, `linux-aarch64-debug-shared`, `linux-aarch64-release-shared`.

### Windows ARM64

```bash theme={null}
git submodule update --init --recursive
cmake -B build -G "Visual Studio 17 2022" -A ARM64 -DProjectVersion="0.1.0.0"
cmake --build build --config Release
```

## API overview

All functions return a `QcPerfReturnCode`. Include `qcperf.h` and `qcperf_common.h`.

| Function                                 | Description                                                                |
| ---------------------------------------- | -------------------------------------------------------------------------- |
| `qcperf_init()`                          | Initialize the library. Must be called first.                              |
| `qcperf_version(info)`                   | Retrieve the library version (build.major.minor.patch).                    |
| `qcperf_connect_backend(id, msg_cb)`     | Connect to a backend and optionally register a message callback.           |
| `qcperf_get_capabilities_info(id, info)` | Query a connected backend's capabilities, metrics, and supported rates.    |
| `qcperf_set_data_callback(id, data_cb)`  | Register the data callback invoked on each streaming interval.             |
| `qcperf_start(id, request)`              | Start monitoring a capability with the given sampling and streaming rates. |
| `qcperf_stop(id, request)`               | Stop an active monitoring session.                                         |
| `qcperf_disconnect_backend(id)`          | Disconnect from a backend and release its resources.                       |
| `qcperf_deinit()`                        | Deinitialize the library and free all resources.                           |
| `qcperf_get_error_info(code, info)`      | Translate a return code into a human-readable string.                      |

## Test application

The build produces `QcPerfCoreTest`, a single-file C program that exercises the complete library lifecycle. It is the canonical usage example.

### Running the test application

```bash theme={null}
./QcPerfCoreTest <backend_id> <sampling_rate_ms> <streaming_rate_ms> <verbose_mode>
```

| Argument            | Description                                                                                           |
| ------------------- | ----------------------------------------------------------------------------------------------------- |
| `backend_id`        | Integer backend identifier (0 = DUMMY, 1 = CPU, 2 = NPU, 3 = POWER, 4 = THERMAL)                      |
| `sampling_rate_ms`  | Hardware sampling interval in ms; pass `0` to use the backend's first supported rate                  |
| `streaming_rate_ms` | Callback delivery interval in ms; pass `0` to use the backend's first supported rate                  |
| `verbose_mode`      | `0` = print metric ID and value only; any other value = also print metric name, unit, and description |

**Examples:**

```bash theme={null}
# Dummy backend, verbose output, 100 ms sampling, 500 ms streaming
./QcPerfCoreTest 0 100 500 1

# CPU backend, basic output, backend default rates
./QcPerfCoreTest 1 0 0 0
```

### Lifecycle

The test application walks through the full API sequence:

<Steps>
  <Step title="Initialize">
    ```c theme={null}
    qcperf_init();
    ```
  </Step>

  <Step title="Connect to backend">
    ```c theme={null}
    qcperf_connect_backend(backend_id, &message_callback);
    ```
  </Step>

  <Step title="Discover capabilities">
    ```c theme={null}
    qcperf_get_capabilities_info(backend_id, backend_info);
    ```
  </Step>

  <Step title="Register data callback">
    ```c theme={null}
    qcperf_set_data_callback(backend_id, &result_callback);
    ```
  </Step>

  <Step title="Start, collect, stop — for each capability">
    ```c theme={null}
    qcperf_start(backend_id, &request);
    sleep(10);
    qcperf_stop(backend_id, &request);
    ```
  </Step>

  <Step title="Disconnect and deinitialize">
    ```c theme={null}
    qcperf_disconnect_backend(backend_id);
    qcperf_deinit();
    ```
  </Step>
</Steps>

### Callback implementations

The message callback receives backend log messages and prints them with a severity prefix, suppressing debug-level output:

```c theme={null}
enum QcPerfReturnCode message_callback(struct QcPerfMessage *message) {
    if (message->message_level != QC_PERF_MESSAGE_LEVEL_DEBUG) {
        printf("[%s] Backend message: %s\n", level_str, message->message);
    }
    return QC_PERF_RETURN_CODE_SUCCESS;
}
```

The data callback is invoked on every streaming interval. In verbose mode it looks up the metric name, unit, and description from a pre-copied `QcPerfBackendInfo`; in basic mode it prints the metric ID and raw value:

```c theme={null}
enum QcPerfReturnCode result_callback(struct QcPerfData *data) {
    printf("[DATA] Capability ID: %d, Metrics count: %d\n",
           data->capabilityId, data->metric_response_len);

    for (uint32_t i = 0; i < data->metric_response_len; i++) {
        if (g_is_verbose_print && metric_found) {
            // verbose: name, value, unit, description
            printf("  [%llu] %s: ", timestamp, metric_name);
            print_metric_value(&data->metric_response[i].metric_value);
            printf(" %s (%s)\n", metric_unit, metric_desc);
        } else {
            // basic: metric ID and value only
            printf("  [%llu] Metric ID %d: ", timestamp,
                   data->metric_response[i].metric_id);
            print_metric_value(&data->metric_response[i].metric_value);
            printf("\n");
        }
    }
    return QC_PERF_RETURN_CODE_SUCCESS;
}
```

<Note>
  The data callback runs on the library's internal background thread. The test application deep-copies `QcPerfBackendInfo` before starting any monitoring session so the callback can safely read metric metadata without holding a lock.
</Note>

## Resources

* [Source code on GitHub](https://github.com/qualcomm/libqcperf)
