diff --git a/.clang-format b/.clang-format index c3a8300..2205a9f 100644 --- a/.clang-format +++ b/.clang-format @@ -1,28 +1,28 @@ -Language: Cpp -BasedOnStyle: Google -IndentWidth: 4 -ContinuationIndentWidth: 4 -UseTab: Never -MaxEmptyLinesToKeep: 1 -ColumnLimit: 200 -PenaltyBreakAssignment: 2 -PenaltyReturnTypeOnItsOwnLine: 400 -PointerAlignment: Left -SpaceBeforeParens: ControlStatements -IndentCaseLabels: false -SortIncludes: false -AlignConsecutiveAssignments: true -BreakBeforeBraces: Custom -BraceWrapping: - AfterClass: false - AfterControlStatement: false - AfterEnum: false - AfterFunction: false - AfterNamespace: false - AfterObjCDeclaration: false - AfterStruct: false - AfterUnion: false - BeforeCatch: false - BeforeElse: false - IndentBraces: false -AlignTrailingComments: true +Language: Cpp +BasedOnStyle: Google +IndentWidth: 4 +ContinuationIndentWidth: 4 +UseTab: Never +MaxEmptyLinesToKeep: 1 +ColumnLimit: 200 +PenaltyBreakAssignment: 2 +PenaltyReturnTypeOnItsOwnLine: 400 +PointerAlignment: Left +SpaceBeforeParens: ControlStatements +IndentCaseLabels: false +SortIncludes: false +AlignConsecutiveAssignments: true +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false +AlignTrailingComments: true diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 46b93fd..006117b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,55 +1,55 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '[BUG] ' -labels: bug -assignees: '' - ---- - -## Bug Description -A clear and concise description of what the bug is. - -## Steps to Reproduce -Steps to reproduce the behavior: -1. Initialize library with '...' -2. Connect to backend '...' -3. function call stack '...' -4. See error - -## Expected Behavior -A clear and concise description of what you expected to happen. - -## Actual Behavior -A clear and concise description of what actually happened. - -## Environment -- OS: [e.g., Windows 11 ARM64, Linux] -- Arch : [e.g., ARM, ARM64, X64] -- Compiler: [e.g., Visual Studio 2022, GCC 11.2] -- libqcperf Version: [e.g., 0.1.0] -- Backend: [e.g., Thermal, Power, Dummy] -- Hardware: [e.g., Snapdragon 8cx Gen 3] - -## Logs/Error Messages -``` -Paste any relevant log output or error messages here -``` - -## Code Sample -If applicable, provide a minimal code sample that reproduces the issue: -```c -// Your code here -``` - -## Additional Context -Add any other context about the problem here, such as: -- Does this happen consistently or intermittently? -- Did this work in a previous version? -- Any workarounds you've found? - -## Checklist -- [ ] I have searched existing issues to ensure this is not a duplicate -- [ ] I have provided all the information requested above -- [ ] I have included relevant logs and error messages -- [ ] I have tested with the latest version of libqcperf +--- +name: Bug report +about: Create a report to help us improve +title: '[BUG] ' +labels: bug +assignees: '' + +--- + +## Bug Description +A clear and concise description of what the bug is. + +## Steps to Reproduce +Steps to reproduce the behavior: +1. Initialize library with '...' +2. Connect to backend '...' +3. function call stack '...' +4. See error + +## Expected Behavior +A clear and concise description of what you expected to happen. + +## Actual Behavior +A clear and concise description of what actually happened. + +## Environment +- OS: [e.g., Windows 11 ARM64, Linux] +- Arch : [e.g., ARM, ARM64, X64] +- Compiler: [e.g., Visual Studio 2022, GCC 11.2] +- libqcperf Version: [e.g., 0.1.0] +- Backend: [e.g., Thermal, Power, Dummy] +- Hardware: [e.g., Snapdragon 8cx Gen 3] + +## Logs/Error Messages +``` +Paste any relevant log output or error messages here +``` + +## Code Sample +If applicable, provide a minimal code sample that reproduces the issue: +```c +// Your code here +``` + +## Additional Context +Add any other context about the problem here, such as: +- Does this happen consistently or intermittently? +- Did this work in a previous version? +- Any workarounds you've found? + +## Checklist +- [ ] I have searched existing issues to ensure this is not a duplicate +- [ ] I have provided all the information requested above +- [ ] I have included relevant logs and error messages +- [ ] I have tested with the latest version of libqcperf diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 216b65c..3eef8eb 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,57 +1,57 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '[FEATURE] ' -labels: enhancement -assignees: '' - ---- - -## Feature Description -A clear and concise description of the feature you'd like to see added. - -## Problem Statement -Describe the problem this feature would solve. Ex. I'm always frustrated when [...] - -## Proposed Solution -A clear and concise description of what you want to happen. Include: -- How the feature would work -- What API changes (if any) would be needed -- Example usage code if applicable - -## Example Usage -If applicable, provide example code showing how you envision using this feature: -```c -// Example code here -``` - -## Alternatives Considered -Describe any alternative solutions or features you've considered. - -## Use Case -Describe your specific use case for this feature: -- What are you trying to accomplish? -- How would this feature help you? -- Are there workarounds you're currently using? - -## Target Environment -- OS: [e.g., Windows 11, Linux] -- Arch: [e.g., ARM, ARM64, X64] -- Backend: [e.g., Thermal, Power, Dummy, or New Backend] -- Hardware: [e.g., Snapdragon 8cx Gen 3] - -## Additional Context -Add any other context, screenshots, or examples about the feature request here. - -## Implementation Considerations -If you have thoughts on implementation: -- Which backend(s) would this affect? -- Would this require new dependencies? -- Are there performance implications? -- Would this be a breaking change? - -## Checklist -- [ ] I have searched existing issues to ensure this is not a duplicate -- [ ] I have clearly described the problem this feature would solve -- [ ] I have provided example usage if applicable -- [ ] I have considered backwards compatibility +--- +name: Feature request +about: Suggest an idea for this project +title: '[FEATURE] ' +labels: enhancement +assignees: '' + +--- + +## Feature Description +A clear and concise description of the feature you'd like to see added. + +## Problem Statement +Describe the problem this feature would solve. Ex. I'm always frustrated when [...] + +## Proposed Solution +A clear and concise description of what you want to happen. Include: +- How the feature would work +- What API changes (if any) would be needed +- Example usage code if applicable + +## Example Usage +If applicable, provide example code showing how you envision using this feature: +```c +// Example code here +``` + +## Alternatives Considered +Describe any alternative solutions or features you've considered. + +## Use Case +Describe your specific use case for this feature: +- What are you trying to accomplish? +- How would this feature help you? +- Are there workarounds you're currently using? + +## Target Environment +- OS: [e.g., Windows 11, Linux] +- Arch: [e.g., ARM, ARM64, X64] +- Backend: [e.g., Thermal, Power, Dummy, or New Backend] +- Hardware: [e.g., Snapdragon 8cx Gen 3] + +## Additional Context +Add any other context, screenshots, or examples about the feature request here. + +## Implementation Considerations +If you have thoughts on implementation: +- Which backend(s) would this affect? +- Would this require new dependencies? +- Are there performance implications? +- Would this be a breaking change? + +## Checklist +- [ ] I have searched existing issues to ensure this is not a duplicate +- [ ] I have clearly described the problem this feature would solve +- [ ] I have provided example usage if applicable +- [ ] I have considered backwards compatibility diff --git a/.gitignore b/.gitignore index 9367dbb..a83f386 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ build* -.vscode -qcperf/third-party/* +.vscode/settings.json diff --git a/.gitmodules b/.gitmodules index 20f5746..402e7fa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,5 @@ [submodule "qcperf/third-party/krabs"] path = qcperf/third-party/krabs url = https://github.com/microsoft/krabsetw.git + update = checkout + branch = eaa17e2f9204496af81e3ca207450fdc7c6956f7 diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..bc39da9 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,39 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Launch QcPerfCoreTest", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/QcPerfCoreTest", + "args": [ + "1", + "200", + "1000", + "1" + ], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Set Disassembly Flavor to Intel", + "text": "-gdb-set disassembly-flavor intel", + "ignoreFailures": true + } + ], + "preLaunchTask": "", + "miDebuggerPath": "/usr/bin/gdb" + } + ] +} diff --git a/DEVELOPMENT-GUIDE.md b/DEVELOPMENT-GUIDE.md index 38e9a6f..4c0bd03 100644 --- a/DEVELOPMENT-GUIDE.md +++ b/DEVELOPMENT-GUIDE.md @@ -3,34 +3,84 @@ This document provides comprehensive information for developers who want to contribute to or extend the libqcperf library. It covers coding standards, architecture details, and guides for implementing new backends. ## Table of Contents -- [Project Architecture](#project-architecture) - - [Core Library](#core-library) - - [Backend Interface](#backend-interface) - - [Data Flow](#data-flow) - - [API Workflow](#api-workflow) -- [Core Functionalities](#core-functionalities) - - [Backend Abstraction](#backend-abstraction-and-extensibility) - - [Dynamic Backend Management](#dynamic-backend-management) - - [Data Collection](#data-collection) - - [Error Handling](#error-handling-and-reporting) - - [Backend Implementations](#backend-implementations) -- [Adding New Backends](#adding-new-backends) - - [Step 1: Create Backend Header Files](#step-1-create-backend-header-files) - - [Step 2: Implement Backend Source Files](#step-2-implement-backend-source-files) - - [Step 3: Register the Backend](#step-3-register-the-backend-with-qcperf) - - [Step 4: Update Build Configuration](#step-4-update-build-configuration) - - [Testing Your Backend](#testing-your-backend) -- [Coding Guidelines](#coding-guidelines) - - [Naming Conventions](#naming-conventions) - - [Type Definitions](#type-definitions) - - [File Organization](#file-organization) - - [Code Structure](#code-structure) - - [Documentation](#documentation) - - [Control Flow](#control-flow) - - [Formatting](#formatting) - - [Error Handling](#error-handling) - - [Best Practices](#best-practices) - - [Summary Checklist](#summary-checklist) +- [libqcperf Development Guide](#libqcperf-development-guide) + - [Table of Contents](#table-of-contents) + - [Project Architecture](#project-architecture) + - [Core Library](#core-library) + - [Backend Interface](#backend-interface) + - [Data Flow](#data-flow) + - [API Workflow](#api-workflow) + - [Core Functionalities](#core-functionalities) + - [Backend Abstraction and Extensibility](#backend-abstraction-and-extensibility) + - [Dynamic Backend Management](#dynamic-backend-management) + - [Data Collection](#data-collection) + - [Error Handling and Reporting](#error-handling-and-reporting) + - [Backend Implementations](#backend-implementations) + - [Dummy Backend](#dummy-backend) + - [Thermal Backend](#thermal-backend) + - [Power Backend](#power-backend) + - [Adding New Backends](#adding-new-backends) + - [Step 1: Create Backend Header Files](#step-1-create-backend-header-files) + - [Main Backend Header (`your_backend.h`)](#main-backend-header-your_backendh) + - [Backend Info Header (`your_backend_info.h`)](#backend-info-header-your_backend_infoh) + - [Step 2: Implement Backend Source Files](#step-2-implement-backend-source-files) + - [Backend Info Implementation (`your_backend_info.c`)](#backend-info-implementation-your_backend_infoc) + - [Main Backend Implementation (`your_backend.c`)](#main-backend-implementation-your_backendc) + - [Step 3: Register the Backend with QcPerf](#step-3-register-the-backend-with-qcperf) + - [Update Backend Enum (`qcperf_backend_enum.h`)](#update-backend-enum-qcperf_backend_enumh) + - [Update Backend Registry (`qcperf_backends.h`)](#update-backend-registry-qcperf_backendsh) + - [Step 4: Update CMake Build Files](#step-4-update-cmake-build-files) + - [How `QCPERF_ENABLED_*` flags are derived](#how-qcperf_enabled_-flags-are-derived) + - [4a. Register the Backend in `cmake/BuildConfig.cmake`](#4a-register-the-backend-in-cmakebuildconfigcmake) + - [4b. Create `backends/your-backend/CMakeLists.txt`](#4b-create-backendsyour-backendcmakeliststxt) + - [4c. Update `backends/CMakeLists.txt`](#4c-update-backendscmakeliststxt) + - [4d. Update `backends/inc/CMakeLists.txt`](#4d-update-backendsinccmakeliststxt) + - [CMake Files Summary](#cmake-files-summary) + - [Testing Your Backend](#testing-your-backend) + - [Best Practices](#best-practices) + - [Coding Guidelines](#coding-guidelines) + - [Naming Conventions](#naming-conventions) + - [Variables and Functions](#variables-and-functions) + - [Structures and Enums](#structures-and-enums) + - [Defines and Macros](#defines-and-macros) + - [Header Guards](#header-guards) + - [Type Definitions](#type-definitions) + - [Typedef Usage](#typedef-usage) + - [Pointer Type Definitions](#pointer-type-definitions) + - [File Organization](#file-organization) + - [Include Order](#include-order) + - [End of File](#end-of-file) + - [Cross-Platform Implementation](#cross-platform-implementation) + - [Code Structure](#code-structure) + - [Variable Declaration](#variable-declaration) + - [Code Blocks](#code-blocks) + - [Documentation](#documentation) + - [Doxygen Documentation](#doxygen-documentation) + - [Inline Comments](#inline-comments) + - [File Headers](#file-headers) + - [Control Flow](#control-flow) + - [Single Return (Single Exit Point)](#single-return-single-exit-point) + - [No goto Statements](#no-goto-statements) + - [Avoid Always-True Loops](#avoid-always-true-loops) + - [Formatting](#formatting) + - [Indentation](#indentation) + - [Spacing](#spacing) + - [Code Formatting Before Commit](#code-formatting-before-commit) + - [Error Handling](#error-handling) + - [Return Error Codes](#return-error-codes) + - [Null Pointer Checks](#null-pointer-checks) + - [Assertions for Debug Builds](#assertions-for-debug-builds) + - [Best Practices](#best-practices-1) + - [Pointer Comparisons](#pointer-comparisons) + - [Const Correctness](#const-correctness) + - [Memory Management](#memory-management) + - [Magic Numbers](#magic-numbers) + - [Function Length](#function-length) + - [Header File Organization](#header-file-organization) + - [Backend Header Organization](#backend-header-organization) + - [Resource Cleanup](#resource-cleanup) + - [Thread Safety](#thread-safety) + - [Summary Checklist](#summary-checklist) --- @@ -412,11 +462,13 @@ enum QcPerfReturnCode qcperf_your_backend_create(struct QcPerfBackendPrivate* ba #### Update Backend Enum (`qcperf_backend_enum.h`) -Add your backend to the `QcPerfBackendId` enum: +Add your backend's enum value to `QcPerfBackendId`. ```c enum QcPerfBackendId { QC_PERF_BACKEND_DUMMY = 0, + QC_PERF_BACKEND_QCOM_LINUX_CPU, + QC_PERF_BACKEND_DSP_NPU, QC_PERF_BACKEND_POWER, QC_PERF_BACKEND_THERMAL, QC_PERF_BACKEND_YOUR_BACKEND, // Add your backend here @@ -424,70 +476,166 @@ enum QcPerfBackendId { }; ``` +> **Important:** The enum order must match the array order in `qcperf_backends.h` exactly. + #### Update Backend Registry (`qcperf_backends.h`) -Add your backend to the `backend_init_fns` array: +Add your backend's include and a `NULL`/`&init_fn` entry in `backend_init_fns[]`, guarded by `QCPERF_ENABLED_YOUR_BACKEND`. The `NULL` entry ensures the array index stays aligned with the enum even when the backend is not compiled in: ```c +#if defined(QCPERF_ENABLED_YOUR_BACKEND) #include "your_backend.h" +#endif static backend_init_t backend_init_fns[] = { - &qcperf_dummy_create, - &wos_power_backend_create, - &qcperf_wos_thermal_create, - &qcperf_your_backend_create // Add your backend here + /* ... existing entries ... */ +#if defined(QCPERF_ENABLED_YOUR_BACKEND) + &qcperf_your_backend_create, /* QC_PERF_BACKEND_YOUR_BACKEND */ +#else + NULL, /* QC_PERF_BACKEND_YOUR_BACKEND (disabled) */ +#endif }; ``` -### Step 4: Update Build Configuration +### Step 4: Update CMake Build Files + +The build system uses a **selective backend mechanism**: registering a backend name in `cmake/BuildConfig.cmake` automatically derives a `QCPERF_ENABLED_*` compile definition that gates both the CMake build targets and the C preprocessor includes in `qcperf_backends.h`. Four files must be updated. + +#### How `QCPERF_ENABLED_*` flags are derived + +The flag name is constructed from the backend name as registered in `QCPERF_PLATFORM_SUPPORTED_BACKENDS`: + +- If no OS prefix is set, the flag is `QCPERF_ENABLED_`. + Example: registering `QCOM_LINUX_CPU` → `QCPERF_ENABLED_QCOM_LINUX_CPU` +- If an OS prefix is configured via `QCPERF_BACKEND_OS_PREFIX_`, the flag becomes `QCPERF_ENABLED__`. + Example: registering `THERMAL` with prefix `WOS` → `QCPERF_ENABLED_WOS_THERMAL` + +Use this flag consistently across all four files below. + +--- + +#### 4a. Register the Backend in `cmake/BuildConfig.cmake` + +Each platform has its own `list(APPEND QCPERF_PLATFORM_SUPPORTED_BACKENDS ...)` call in `cmake/BuildConfig.cmake`. **Append your backend's nickname to the list for the target OS.** The table below shows the existing nicknames per platform and the `QCPERF_ENABLED_*` flag each one produces: + +| Platform | CMake guard variable | Registered nicknames | Derived `QCPERF_ENABLED_*` flag | +|----------|---------------------|----------------------|----------------------------------| +| All platforms | *(always included)* | `DUMMY` | `QCPERF_ENABLED_DUMMY` | +| Linux ARM64 | `QCPERF_PLATFORM_LINUX_ARM64` | `QCOM_LINUX_CPU` | `QCPERF_ENABLED_QCOM_LINUX_CPU` | +| Linux ARM64 | `QCPERF_PLATFORM_LINUX_ARM64` | `QCOM_LINUX_NPU` | `QCPERF_ENABLED_QCOM_LINUX_NPU` | +| Windows ARM64 | `QCPERF_PLATFORM_WINDOWS_ARM64` | `WOS_THERMAL` | `QCPERF_ENABLED_WOS_THERMAL` | +| Windows ARM64 | `QCPERF_PLATFORM_WINDOWS_ARM64` | `WOS_POWER` | `QCPERF_ENABLED_WOS_POWER` | + +Add your backend's nickname to the appropriate platform block. This is the **only change needed** in `BuildConfig.cmake` for most backends: + +```cmake +# Example: register YOUR_BACKEND for Linux ARM64 +# Append YOUR_BACKEND to the existing Linux ARM64 list +if(QCPERF_PLATFORM_LINUX_ARM64) + list(APPEND QCPERF_PLATFORM_SUPPORTED_BACKENDS QCOM_LINUX_CPU QCOM_LINUX_NPU YOUR_BACKEND) +endif() + +# Example: register YOUR_BACKEND for Windows ARM64 +# Append YOUR_BACKEND to the existing Windows ARM64 list +if(QCPERF_PLATFORM_WINDOWS_ARM64) + list(APPEND QCPERF_PLATFORM_SUPPORTED_BACKENDS WOS_THERMAL WOS_POWER YOUR_BACKEND) +endif() +``` + +The compile definition `QCPERF_ENABLED_YOUR_BACKEND` will be set automatically — no further changes to `BuildConfig.cmake` are needed. + +> **Note:** If your backend requires an OS prefix (e.g., `WOS` for Windows on Snapdragon backends), set `QCPERF_BACKEND_OS_PREFIX_YOUR_BACKEND` to the appropriate prefix so the flag becomes `QCPERF_ENABLED_WOS_YOUR_BACKEND`. Existing WOS backends use this pattern. + +--- -#### Create CMakeLists.txt for Your Backend +#### 4b. Create `backends/your-backend/CMakeLists.txt` -Create a `CMakeLists.txt` file in your backend directory: +Create a `CMakeLists.txt` in your backend directory. Follow the naming and include conventions used by existing backends: ```cmake -# Your backend CMakeLists.txt -cmake_minimum_required(VERSION 3.15) +# ============================================================================ +# QcPerf Your Backend +# ============================================================================ +# Brief description of what this backend monitors. -# Define source files -set(YOUR_BACKEND_SOURCES +message("Added your-backend backend") + +# Create the backend library — use QcPerfBackend naming convention +add_library(QcPerfYourBackend STATIC src/your_backend.c src/your_backend_info.c ) -# Define header files -set(YOUR_BACKEND_HEADERS - inc/your_backend.h - inc/your_backend_info.h +target_include_directories(QcPerfYourBackend PUBLIC + inc + ${CMAKE_SOURCE_DIR}/core/inc + ${CMAKE_SOURCE_DIR}/core/inc/internal + ${CMAKE_SOURCE_DIR}/backends/inc + ${CMAKE_SOURCE_DIR}/utils/qthread/inc + ${CMAKE_SOURCE_DIR}/utils/qtime/inc ) -# Create library target -add_library(your_backend STATIC ${YOUR_BACKEND_SOURCES} ${YOUR_BACKEND_HEADERS}) - -# Set include directories -target_include_directories(your_backend - PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/inc - PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/src +target_link_libraries(QcPerfYourBackend + QcPerfQThread + QcPerfQTime + ${_OS_M} ) +``` -# Link dependencies -target_link_libraries(your_backend - PUBLIC - qcperf_core -) +Key conventions to follow: +- **Library target name**: `QcPerfBackend` (e.g., `QcPerfDummyBackend`, `QcPerfQcomLinuxCpuBackend`) +- **Always include** `${CMAKE_SOURCE_DIR}/core/inc`, `${CMAKE_SOURCE_DIR}/core/inc/internal`, and `${CMAKE_SOURCE_DIR}/backends/inc` so the backend can access the core API and backend interface headers +- **Always link** `QcPerfQThread` and `QcPerfQTime` for threading and timing utilities +- **`${_OS_M}`** links the math library on Linux (set automatically by `BuildConfig.cmake`) +- Do **not** add `cmake_minimum_required()` — it is set once in the top-level `CMakeLists.txt` + +--- + +#### 4c. Update `backends/CMakeLists.txt` + +Add an `add_subdirectory` call guarded by the `QCPERF_ENABLED_*` flag. Place it in the appropriate platform section: + +```cmake +# Linux ARM64 backends +if(QCPERF_ENABLED_YOUR_BACKEND) + add_subdirectory(your-backend) +endif() ``` -#### Update Main CMakeLists.txt +The directory name passed to `add_subdirectory` must match the actual directory name under `backends/`. -Add your backend to the main `backends/CMakeLists.txt`: +--- + +#### 4d. Update `backends/inc/CMakeLists.txt` + +Add your backend's include directory and link its library into the `QcPerfBackends` interface target. The `QcPerfBackends` target is what the core library links against, so this step makes your backend available to the core: ```cmake -# Add your backend subdirectory -add_subdirectory(your_backend) +if(QCPERF_ENABLED_YOUR_BACKEND) + target_include_directories(QcPerfBackends INTERFACE + ${CMAKE_SOURCE_DIR}/backends/your-backend/inc + ) + target_link_libraries(QcPerfBackends INTERFACE + QcPerfYourBackend + ) +endif() ``` +The library name in `target_link_libraries` must match the `add_library` target name defined in your backend's `CMakeLists.txt` (step 4b). + +--- + +#### CMake Files Summary + +The table below lists every file that must be modified when adding a new backend: + +| File | What to add | +|------|-------------| +| `cmake/BuildConfig.cmake` | Add backend name to `QCPERF_PLATFORM_SUPPORTED_BACKENDS` for the target platform | +| `backends/your-backend/CMakeLists.txt` | **Create new file** — `add_library(QcPerfYourBackend ...)` with correct includes and link libraries | +| `backends/CMakeLists.txt` | Add `if(QCPERF_ENABLED_YOUR_BACKEND) add_subdirectory(your-backend) endif()` | +| `backends/inc/CMakeLists.txt` | Add `if(QCPERF_ENABLED_YOUR_BACKEND)` block with `target_include_directories` and `target_link_libraries` into `QcPerfBackends` | + ### Testing Your Backend 1. Build the QcPerf library with your new backend diff --git a/README.md b/README.md index e08ad9c..ea45c9e 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,27 @@ A lightweight, open-source performance profiling library for Qualcomm chipsets. ## Table of Contents -- [Introduction](#introduction) -- [Framework Features](#framework-features) -- [Build System](#build-system) -- [Compilation Instructions](#compilation-instructions) -- [Design Diagrams](#design-diagrams) -- [Documentation](#documentation) +- [libqcperf](#libqcperf) + - [Table of Contents](#table-of-contents) + - [Introduction](#introduction) + - [Framework Features](#framework-features) + - [Core Capabilities](#core-capabilities) + - [Available Backends](#available-backends) + - [Technical Foundation](#technical-foundation) + - [Build System](#build-system) + - [Compilation Instructions](#compilation-instructions) + - [Linux ARM64](#linux-arm64) + - [Command Line](#command-line) + - [CMake Presets](#cmake-presets) + - [Windows ARM64](#windows-arm64) + - [Design Diagrams](#design-diagrams) + - [Sequence Diagram](#sequence-diagram) + - [Flow Diagram](#flow-diagram) + - [Backend Architecture](#backend-architecture) + - [Documentation for backend developers](#documentation-for-backend-developers) + - [Contributing](#contributing) + - [Security](#security) + - [License](#license) ## Introduction @@ -30,16 +45,20 @@ Originally inspired by the Qualcomm Profiler tool, libqcperf is now available as ### Available Backends -| Backend | Description | Metrics & Configuration Reference | -|---------|-------------|-----------------------------------| -| **Thermal Backend** | Monitors temperature and passive cooling metrics across 22 thermal zones | [wos_thermal_info.h](qcperf/backends/wos-thermal/inc/wos_thermal_info.h) | -| **Power Backend** | Measures power consumption across various system components | [wos_power_backend_info.h](qcperf/backends/wos-power-backend/inc/wos_power_backend_info.h) | -| **Dummy Backend** | Reference implementation for testing and development | [dummy_info.h](qcperf/backends/dummy/inc/dummy_info.h) | +| Backend | OS / Platform | `-DBACKENDS` Flag | Compile Definition | Description | Metrics & Configuration Reference | +|---------|--------------|-------------------|--------------------|-------------|-----------------------------------| +| **Thermal Backend** | Windows on Snapdragon (WoS) | `THERMAL` | `QCPERF_ENABLED_WOS_THERMAL` | Monitors temperature and passive cooling metrics across 22 thermal zones | [wos_thermal_info.h](qcperf/backends/wos-thermal/inc/wos_thermal_info.h) | +| **Power Backend** | Windows on Snapdragon (WoS) | `POWER` | `QCPERF_ENABLED_WOS_POWER` | Measures power consumption across various system components | [wos_power_backend_info.h](qcperf/backends/wos-power-backend/inc/wos_power_backend_info.h) | +| **Linux CPU Backend** | Qcom Linux | `CPU` | `QCPERF_ENABLED_QCOM_LINUX_CPU` | Monitors CPU load, frequency, effective utilization, steal time, and DCVS frequency limit per core (up to 18 cores) | [qcom_linux_cpu_info.h](qcperf/backends/qcom-linux-cpu/inc/qcom_linux_cpu_info.h) | +| **DSP NPU Backend** | Qcom Linux | `NPU` | `QCPERF_ENABLED_QCOM_LINUX_NPU` | Monitors Neural Processing Unit (NPU) performance metrics including Q6 utilization, Q6 clock frequency, HVX utilization, and HMX utilization | [qcom_dsp_npu_info.h](qcperf/backends/qcom-dsp-npu/inc/qcom_dsp_npu_info.h) | +| **Dummy Backend** | All | `DUMMY` | `QCPERF_ENABLED_DUMMY` | Reference implementation for testing and development | [dummy_info.h](qcperf/backends/dummy/inc/dummy_info.h) | > **Note:** Each backend's info.h file contains detailed information about supported capability, metrics, sampling rates, and streaming rates. +> ### Technical Foundation -- Relies on publicly available Windows driver APIs (ETW, PEP, IOCTL) +- WoS backends rely on publicly available Windows driver APIs (ETW, IOCTL) +- Linux backends rely on standard Linux kernel interfaces (sysfs, procfs) - Comprehensive error handling and resource management - Thread-safe operations for multi-threaded applications @@ -48,9 +67,84 @@ Originally inspired by the Qualcomm Profiler tool, libqcperf is now available as - **CMake** - **Compiler** - Windows on Snapdragon - Visual Studio 2022 + - Linux ARM64 - ARM GNU Toolchain (`aarch64-none-linux-gnu-gcc`) ## Compilation Instructions +### Linux ARM64 + +To cross-compile the library for Linux on ARM64 platforms, you need the [ARM GNU Toolchain](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads) (`arm-gnu-toolchain-**.*.rel1-x86_64-aarch64-none-linux-gnu`). + +#### Command Line + +```bash +# Set the toolchain path (adjust to your installation directory) +export AARCH64_TOOLCHAIN_PATH=/path/to/arm-gnu-toolchain + +# Configure and generate build files +cmake -S qcperf -B build-linux-aarch64-release \ + -DTARGET_ARCH=linux-aarch64 \ + -DCMAKE_BUILD_TYPE=Release \ + -DProjectVersion="0.1.0.0" \ + -DBACKENDS="CPU;NPU;DUMMY" \ + -DBUILD_SHARED=OFF + +# Compile the project +cmake --build build-linux-aarch64-release +``` + +| Flag | Value | Description | +|------|-------|-------------| +| `-S qcperf` | `qcperf` | Source directory containing the top-level `CMakeLists.txt` | +| `-B build-linux-aarch64-release` | `build-linux-aarch64-release` | Output directory for generated build files and compiled artifacts | +| `-DTARGET_ARCH` | `linux-aarch64` | Selects the cross-compilation toolchain for Linux ARM64; requires `AARCH64_TOOLCHAIN_PATH` to be set | +| `-DCMAKE_BUILD_TYPE` | `Release` / `Debug` | Build type: `Release` produces an optimized binary; `Debug` includes debug symbols | +| `-DProjectVersion` | `"0.1.0.0"` | Sets the library version string embedded in the build | +| `-DBACKENDS` | `"CPU;NPU;DUMMY"` | Semicolon-separated list of backends to compile (case-insensitive); omit this flag to compile all backends supported on the target platform | +| `-DBUILD_SHARED` | `OFF` / `ON` | `OFF` builds a static library (`.a`); `ON` builds a shared library (`.so`) | + +> **Note:** Only backends supported on the target platform are compiled even if listed explicitly (e.g., specifying `power` on Linux ARM64 will be silently skipped with a warning). + +#### CMake Presets + +The build is configured via CMake presets defined in `qcperf/CMakePresets.json` (shared base) and `qcperf/CMakeUserPresets.json` (user-local overrides). + +**Toolchain path — priority order:** +1. Environment variable `AARCH64_TOOLCHAIN_PATH` (takes precedence if set) +2. Value defined in the `linux-aarch64-user-base` hidden preset in `qcperf/CMakeUserPresets.json` (fallback default) + +To change the toolchain path or project version, edit **only** the `linux-aarch64-user-base` preset in `qcperf/CMakeUserPresets.json` — all other presets inherit from it automatically. + +| Preset | Build Type | Library Type | Output Directory | +|--------|-----------|--------------|-----------------| +| `linux-aarch64-debug` | Debug | Static | `build-linux-aarch64-debug/` | +| `linux-aarch64-release` | Release | Static | `build-linux-aarch64-release/` | +| `linux-aarch64-debug-shared` | Debug | Shared (`.so`) | `build-linux-aarch64-debug-shared/` | +| `linux-aarch64-release-shared` | Release | Shared (`.so`) | `build-linux-aarch64-release-shared/` | + +e.g. for a debug build: + +```bash +# Configure +cd qcperf +cmake --preset linux-aarch64-debug + +# Compile the project +cmake --build --preset linux-aarch64-debug +``` + +e.g. for a release shared library build: + +```bash +# Configure +cd qcperf +cmake --preset linux-aarch64-release-shared + +# Compile the project +cmake --build --preset linux-aarch64-release-shared +``` + + ### Windows ARM64 To build the library for Windows on ARM64 platforms: diff --git a/assets/libqcperf_backend_architecture.mmd b/assets/libqcperf_backend_architecture.mmd index a484f12..87a7837 100644 --- a/assets/libqcperf_backend_architecture.mmd +++ b/assets/libqcperf_backend_architecture.mmd @@ -33,7 +33,7 @@ graph TD - CPU Clusters Temperature - GPU Temperature - Passive Cooling States"] - + PowerCap["Power Capabilities - CPU Power - GPU Power diff --git a/assets/libqcperf_sequence.mmd b/assets/libqcperf_sequence.mmd index 964f007..185c6b6 100644 --- a/assets/libqcperf_sequence.mmd +++ b/assets/libqcperf_sequence.mmd @@ -1,98 +1,98 @@ -sequenceDiagram - participant CoreTest - participant Core - participant Backend - participant BackendThread - participant Driver - - Note over CoreTest,Core: CoreTest is a test application that uses the Core API to perform profiling. - Note over Backend,BackendThread: The backend thread is created in qcperf_backend_start() and destroyed in qcperf_backend_stop(). - - %% Step 1: Initialize QCPerf - CoreTest->>Core: qcperf_init() - Core->>Core: Allocate QcPerfBackendPrivate* array - Core->>Core: Initialize OS dependencies if any - Core-->>CoreTest: Return initialization status - - %% Step 2: Connect to backend - CoreTest->>Core: qcperf_connect_backend(enum QcPerfBackendId, QcPerfMessageCallback) - Core->>Backend: backend_create(QcPerfBackendPrivate*) - Backend->>Core: Fill function pointers map with backend implementations - Core->>Backend: Set message callback if provided by user - Backend-->>Core: Set message callback response - Core->>Backend: Initialize backend - Backend->>Driver: Send initialization command - Driver-->>Backend: Initialization response - Backend->>Backend: Fill capability map data - Backend-->>Core: Return response code - Core-->>CoreTest: Return response code - - %% Step 3: Get capabilities info - CoreTest->>Core: qcperf_get_capabilities_info(enum QcPerfBackendId, struct QcPerfBackendInfo*) - Core->>Backend: qcperf_backend_info(struct QcPerfBackendInfo*) - Backend-->>Core: Response with capability data - Core-->>CoreTest: Return capability data - - %% Step 4: Create deep copy of backend info (if verbose mode enabled) - alt Verbose Mode Enabled - CoreTest->>CoreTest: create_backend_info_copy(backend_info) - Note over CoreTest: Deep copy capability and metric information for verbose printing - end - - %% Step 5: Set data callback - CoreTest->>Core: qcperf_set_data_callback(enum QcPerfBackendId, QcPerfDataCallback) - Core->>Backend: set_data_callback(QcPerfDataCallback) - Backend-->>Core: Return response code - Core-->>CoreTest: Return response code - - %% Step 6: Test capability - %% Step 6.1: Start profiling - CoreTest->>Core: qcperf_start(enum QcPerfBackendId, struct QcPerfRequest*) - Core->>Backend: qcperf_backend_start(struct QcPerfRequest*) - Backend->>BackendThread: Create thread for receiving data from driver - Backend->>Driver: Send start command to driver - - %% Step 6.2: Data collection - loop Thread Execution - Note over Backend,BackendThread: Background thread created by the backend - BackendThread->>Driver: Request data as per request parameters - Driver-->>BackendThread: Send data back to consumer thread - BackendThread->>CoreTest: Send data to result callback function - CoreTest->>CoreTest: Process and display metric data - end - - Driver-->>Backend: Start response - Backend-->>Core: Return response code - Core-->>CoreTest: Return response code - - %% Step 6.3: Wait for data collection - CoreTest->>CoreTest: Wait for data collection (sleep) - - %% Step 6.4: Stop profiling - CoreTest->>Core: qcperf_stop(enum QcPerfBackendId, struct QcPerfRequest*) - Core->>Backend: qcperf_backend_stop(struct QcPerfRequest*) - Backend->>Driver: Send stop command to driver - Backend->>BackendThread: Signal thread to terminate - Driver-->>Backend: Stop response - Backend-->>Core: Return response code - Core-->>CoreTest: Return response code - - %% Step 7: Disconnect backend - CoreTest->>Core: qcperf_disconnect_backend(enum QcPerfBackendId) - Core->>Backend: qcperf_backend_deinit() - Backend->>Driver: Send deinit command to driver - Driver-->>Backend: Deinit response - Backend->>Backend: Free all allocated memory - Backend-->>Core: Return response code - Core->>Core: Cleanup backend registered data - Core-->>CoreTest: Return response code - - %% Step 8: Deinitialize QCPerf - CoreTest->>Core: qcperf_deinit() - Core->>Core: Cleanup core data structures - Core-->>CoreTest: Return response code - - %% Step 9: Clean up resources - CoreTest->>CoreTest: Free request memory - CoreTest->>CoreTest: Free backend info memory - CoreTest->>CoreTest: Call cleanup_backend_info() +sequenceDiagram + participant CoreTest + participant Core + participant Backend + participant BackendThread + participant Driver + + Note over CoreTest,Core: CoreTest is a test application that uses the Core API to perform profiling. + Note over Backend,BackendThread: The backend thread is created in qcperf_backend_start() and destroyed in qcperf_backend_stop(). + + %% Step 1: Initialize QCPerf + CoreTest->>Core: qcperf_init() + Core->>Core: Allocate QcPerfBackendPrivate* array + Core->>Core: Initialize OS dependencies if any + Core-->>CoreTest: Return initialization status + + %% Step 2: Connect to backend + CoreTest->>Core: qcperf_connect_backend(enum QcPerfBackendId, QcPerfMessageCallback) + Core->>Backend: backend_create(QcPerfBackendPrivate*) + Backend->>Core: Fill function pointers map with backend implementations + Core->>Backend: Set message callback if provided by user + Backend-->>Core: Set message callback response + Core->>Backend: Initialize backend + Backend->>Driver: Send initialization command + Driver-->>Backend: Initialization response + Backend->>Backend: Fill capability map data + Backend-->>Core: Return response code + Core-->>CoreTest: Return response code + + %% Step 3: Get capabilities info + CoreTest->>Core: qcperf_get_capabilities_info(enum QcPerfBackendId, struct QcPerfBackendInfo*) + Core->>Backend: qcperf_backend_info(struct QcPerfBackendInfo*) + Backend-->>Core: Response with capability data + Core-->>CoreTest: Return capability data + + %% Step 4: Create deep copy of backend info (if verbose mode enabled) + alt Verbose Mode Enabled + CoreTest->>CoreTest: create_backend_info_copy(backend_info) + Note over CoreTest: Deep copy capability and metric information for verbose printing + end + + %% Step 5: Set data callback + CoreTest->>Core: qcperf_set_data_callback(enum QcPerfBackendId, QcPerfDataCallback) + Core->>Backend: set_data_callback(QcPerfDataCallback) + Backend-->>Core: Return response code + Core-->>CoreTest: Return response code + + %% Step 6: Test capability + %% Step 6.1: Start profiling + CoreTest->>Core: qcperf_start(enum QcPerfBackendId, struct QcPerfRequest*) + Core->>Backend: qcperf_backend_start(struct QcPerfRequest*) + Backend->>BackendThread: Create thread for receiving data from driver + Backend->>Driver: Send start command to driver + + %% Step 6.2: Data collection + loop Thread Execution + Note over Backend,BackendThread: Background thread created by the backend + BackendThread->>Driver: Request data as per request parameters + Driver-->>BackendThread: Send data back to consumer thread + BackendThread->>CoreTest: Send data to result callback function + CoreTest->>CoreTest: Process and display metric data + end + + Driver-->>Backend: Start response + Backend-->>Core: Return response code + Core-->>CoreTest: Return response code + + %% Step 6.3: Wait for data collection + CoreTest->>CoreTest: Wait for data collection (sleep) + + %% Step 6.4: Stop profiling + CoreTest->>Core: qcperf_stop(enum QcPerfBackendId, struct QcPerfRequest*) + Core->>Backend: qcperf_backend_stop(struct QcPerfRequest*) + Backend->>Driver: Send stop command to driver + Backend->>BackendThread: Signal thread to terminate + Driver-->>Backend: Stop response + Backend-->>Core: Return response code + Core-->>CoreTest: Return response code + + %% Step 7: Disconnect backend + CoreTest->>Core: qcperf_disconnect_backend(enum QcPerfBackendId) + Core->>Backend: qcperf_backend_deinit() + Backend->>Driver: Send deinit command to driver + Driver-->>Backend: Deinit response + Backend->>Backend: Free all allocated memory + Backend-->>Core: Return response code + Core->>Core: Cleanup backend registered data + Core-->>CoreTest: Return response code + + %% Step 8: Deinitialize QCPerf + CoreTest->>Core: qcperf_deinit() + Core->>Core: Cleanup core data structures + Core-->>CoreTest: Return response code + + %% Step 9: Clean up resources + CoreTest->>CoreTest: Free request memory + CoreTest->>CoreTest: Free backend info memory + CoreTest->>CoreTest: Call cleanup_backend_info() diff --git a/qcperf/CMakeLists.txt b/qcperf/CMakeLists.txt index 0d2627c..0c2fedf 100644 --- a/qcperf/CMakeLists.txt +++ b/qcperf/CMakeLists.txt @@ -1,64 +1,115 @@ -# ============================================================================ -# QcPerf - Qualcomm Performance Profiler Library -# Main CMakeLists.txt file -# ============================================================================ - -# Minimum CMake version required for modern CMake features -# Version 3.15+ provides improved target property handling and generator expressions -cmake_minimum_required(VERSION 3.15) - -# ============================================================================ -# Version information -# ============================================================================ -# Enable version information generation -# This creates a header with version details, build timestamp, etc. -add_subdirectory(version_info) - -# ============================================================================ -# Project declaration -# ============================================================================ -# - VERSION: Semantic versioning (major.minor.patch) -# - DESCRIPTION: Brief description of the project -# - LANGUAGES: Programming languages used (C only for this project) -project(QcPerf - VERSION "${QCPERF_VERSION}" - DESCRIPTION "Qualcomm Performance Profiler Library v${QCPERF_VERSION}" - LANGUAGES C CXX -) - - -# ============================================================================ -# Build configuration -# ============================================================================ -# Include the combined build configuration from cmake/BuildConfig.cmake -# This centralizes platform detection, compiler flags, and other build settings -include(cmake/BuildConfig.cmake) - - -# ============================================================================ -# Component subdirectories -# ============================================================================ -# Add each component in dependency order: -# - core: Main library functionality -# - backends: Performance monitoring backend implementations -# - utils: Utility libraries used by core and backends -# - core-test: Test application for the core library -add_subdirectory(core) -add_subdirectory(backends) -add_subdirectory(utils) -add_subdirectory(test_app) - -# ============================================================================ -# Configuration summary -# ============================================================================ -# Print a summary of the build configuration for user verification -message(STATUS "") -message(STATUS "QcPerf Configuration Summary:") -message(STATUS " Version: ${QCPERF_VERSION}") -message(STATUS " Build type: ${CMAKE_BUILD_TYPE}") -message(STATUS " C Compiler: ${CMAKE_C_COMPILER}") -message(STATUS " CXX Compiler: ${CMAKE_CXX_COMPILER}") -message(STATUS " System: ${CMAKE_SYSTEM_NAME}") -message(STATUS " Processor: ${CMAKE_SYSTEM_PROCESSOR}") -message(STATUS " Install prefix: ${CMAKE_INSTALL_PREFIX}") -message(STATUS "") +# ============================================================================ +# QcPerf - Qualcomm Performance Profiler Library +# Main CMakeLists.txt file +# ============================================================================ + +# Minimum CMake version required for modern CMake features +# Version 3.15+ provides improved target property handling and generator expressions +cmake_minimum_required(VERSION 3.15) + +# ============================================================================ +# Select Toolchain based on TARGET_ARCH +# ============================================================================ + +# ============================================================================ +# Library type option +# ============================================================================ +# Build QcPerfCore as STATIC by default. +# Pass -DBUILD_SHARED=ON to build a shared library (.so / .dll) instead. +option(BUILD_SHARED "Build QcPerfCore as a shared library (.so/.dll)" OFF) + +if(NOT CMAKE_TOOLCHAIN_FILE AND DEFINED TARGET_ARCH) + if(TARGET_ARCH STREQUAL "linux-aarch64") + # Linux AArch64 cross-compilation — set the GNU cross-toolchain file. + set(CMAKE_TOOLCHAIN_FILE + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/toolchains/aarch64-linux-gnu.cmake" + CACHE FILEPATH "Toolchain file (auto-selected for TARGET_ARCH=${TARGET_ARCH})") + message(STATUS "Selected toolchain for TARGET_ARCH=${TARGET_ARCH}: ${CMAKE_TOOLCHAIN_FILE}") + endif() +endif() + +# ============================================================================ +# Version information +# ============================================================================ +# Enable version information generation +# This creates a header with version details, build timestamp, etc. +add_subdirectory(version_info) + +# ============================================================================ +# Project declaration +# ============================================================================ +# - VERSION: Semantic versioning (major.minor.patch) +# - DESCRIPTION: Brief description of the project +# - LANGUAGES: Programming languages used (C only for this project) +project(QcPerf + VERSION "${QCPERF_VERSION}" + DESCRIPTION "Qualcomm Performance Profiler Library v${QCPERF_VERSION}" + LANGUAGES C CXX +) + +# Set Binary root directory for all output +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + +# ============================================================================ +# Build configuration +# ============================================================================ +# Include the combined build configuration from cmake/BuildConfig.cmake +# This centralizes platform detection, compiler flags, and other build settings +include(cmake/BuildConfig.cmake) + +if(BUILD_SHARED) + set(BUILD_SHARED_TYPE "SHARED") + add_compile_definitions(QCPERF_SHARED_LIBRARY) +else() + add_compile_definitions(QCPERF_STATIC_LIBRARY) + set(BUILD_SHARED_TYPE "STATIC") +endif() + + +# ============================================================================ +# Component subdirectories +# ============================================================================ +# Add each component in dependency order: +# - core: Main library functionality +# - backends: Performance monitoring backend implementations +# - utils: Utility libraries used by core and backends +# - core-test: Test application for the core library +add_subdirectory(core) +add_subdirectory(backends) +add_subdirectory(utils) +add_subdirectory(test_app) + +# ============================================================================ +# Configuration summary +# ============================================================================ +# Print a summary of the build configuration for user verification + +# Build the list of enabled backends for display +set(_ENABLED_BACKENDS_LIST "") +foreach(_BACKEND ${QCPERF_PLATFORM_SUPPORTED_BACKENDS}) + if(DEFINED QCPERF_BACKEND_OS_PREFIX_${_BACKEND}) + set(_OS_PREFIX ${QCPERF_BACKEND_OS_PREFIX_${_BACKEND}}) + set(_COMPILE_FLAG QCPERF_ENABLED_${_OS_PREFIX}_${_BACKEND}) + else() + set(_COMPILE_FLAG QCPERF_ENABLED_${_BACKEND}) + endif() + if(${_COMPILE_FLAG}) + list(APPEND _ENABLED_BACKENDS_LIST ${_COMPILE_FLAG}) + endif() +endforeach() +string(REPLACE ";" ", " _ENABLED_BACKENDS_STR "${_ENABLED_BACKENDS_LIST}") + +message(STATUS "") +message(STATUS "QcPerf Configuration Summary:") +message(STATUS " Version: ${QCPERF_VERSION}") +message(STATUS " Build type: ${CMAKE_BUILD_TYPE}") +message(STATUS " C Compiler: ${CMAKE_C_COMPILER}") +message(STATUS " CXX Compiler: ${CMAKE_CXX_COMPILER}") +message(STATUS " System: ${CMAKE_SYSTEM_NAME}") +message(STATUS " Processor: ${CMAKE_SYSTEM_PROCESSOR}") +message(STATUS " Install prefix: ${CMAKE_INSTALL_PREFIX}") +message(STATUS " Library type: ${BUILD_SHARED_TYPE}") +message(STATUS " Enabled backends: ${_ENABLED_BACKENDS_STR}") +message(STATUS "") diff --git a/qcperf/CMakePresets.json b/qcperf/CMakePresets.json new file mode 100644 index 0000000..c1a909c --- /dev/null +++ b/qcperf/CMakePresets.json @@ -0,0 +1,60 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 19, + "patch": 0 + }, + "configurePresets": [ + { + "name": "linux-aarch64-debug-base", + "hidden": true, + "displayName": "Linux AArch64 Debug Base (hidden)", + "description": "Base preset for Linux AArch64 cross-compilation (Debug). Not used directly — inherit from this in CMakeUserPresets.json.", + "generator": "Unix Makefiles", + "binaryDir": "${sourceDir}/../build-linux-aarch64-debug", + "cacheVariables": { + "TARGET_ARCH": "linux-aarch64", + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "linux-aarch64-release-base", + "hidden": true, + "displayName": "Linux AArch64 Release Base (hidden)", + "description": "Base preset for Linux AArch64 cross-compilation (Release). Not used directly — inherit from this in CMakeUserPresets.json.", + "generator": "Unix Makefiles", + "binaryDir": "${sourceDir}/../build-linux-aarch64-release", + "cacheVariables": { + "TARGET_ARCH": "linux-aarch64", + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "linux-aarch64-debug-shared-base", + "hidden": true, + "displayName": "Linux AArch64 Debug Shared Base (hidden)", + "description": "Base preset for Linux AArch64 cross-compilation (Debug, Shared library). Not used directly — inherit from this in CMakeUserPresets.json.", + "generator": "Unix Makefiles", + "binaryDir": "${sourceDir}/../build-linux-aarch64-debug-shared", + "cacheVariables": { + "TARGET_ARCH": "linux-aarch64", + "CMAKE_BUILD_TYPE": "Debug", + "BUILD_SHARED": "ON" + } + }, + { + "name": "linux-aarch64-release-shared-base", + "hidden": true, + "displayName": "Linux AArch64 Release Shared Base (hidden)", + "description": "Base preset for Linux AArch64 cross-compilation (Release, Shared library). Not used directly — inherit from this in CMakeUserPresets.json.", + "generator": "Unix Makefiles", + "binaryDir": "${sourceDir}/../build-linux-aarch64-release-shared", + "cacheVariables": { + "TARGET_ARCH": "linux-aarch64", + "CMAKE_BUILD_TYPE": "Release", + "BUILD_SHARED": "ON" + } + } + ] +} diff --git a/qcperf/CMakeUserPresets.json b/qcperf/CMakeUserPresets.json new file mode 100644 index 0000000..aa5e841 --- /dev/null +++ b/qcperf/CMakeUserPresets.json @@ -0,0 +1,65 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "linux-aarch64-user-base", + "hidden": true, + "displayName": "Linux AArch64 User Base (hidden)", + "description": "User-specific base preset. Set AARCH64_TOOLCHAIN_PATH and ProjectVersion here once — all Linux AArch64 presets inherit from this.", + "cacheVariables": { + "ProjectVersion": "0.1.0.0", + "AARCH64_TOOLCHAIN_PATH": "/path/to/arm-gnu-toolchain" + } + }, + { + "name": "linux-aarch64-debug", + "displayName": "Linux AArch64 Debug", + "description": "Cross-compile for Linux AArch64 (Debug) using ARM GNU Toolchain. AARCH64_TOOLCHAIN_PATH is read from the environment variable if set, otherwise falls back to the value defined in linux-aarch64-user-base.", + "inherits": ["linux-aarch64-debug-base", "linux-aarch64-user-base"] + }, + { + "name": "linux-aarch64-release", + "displayName": "Linux AArch64 Release", + "description": "Cross-compile for Linux AArch64 (Release) using ARM GNU Toolchain. AARCH64_TOOLCHAIN_PATH is read from the environment variable if set, otherwise falls back to the value defined in linux-aarch64-user-base.", + "inherits": ["linux-aarch64-release-base", "linux-aarch64-user-base"] + }, + { + "name": "linux-aarch64-debug-shared", + "displayName": "Linux AArch64 Debug Shared", + "description": "Cross-compile for Linux AArch64 (Debug, Shared library). QcPerfCore is built as a shared object (.so).", + "inherits": ["linux-aarch64-debug-shared-base", "linux-aarch64-user-base"] + }, + { + "name": "linux-aarch64-release-shared", + "displayName": "Linux AArch64 Release Shared", + "description": "Cross-compile for Linux AArch64 (Release, Shared library). QcPerfCore is built as a shared object (.so).", + "inherits": ["linux-aarch64-release-shared-base", "linux-aarch64-user-base"] + } + ], + "buildPresets": [ + { + "name": "linux-aarch64-debug", + "displayName": "Build Linux AArch64 Debug", + "description": "Build the linux-aarch64-debug configure preset", + "configurePreset": "linux-aarch64-debug" + }, + { + "name": "linux-aarch64-release", + "displayName": "Build Linux AArch64 Release", + "description": "Build the linux-aarch64-release configure preset", + "configurePreset": "linux-aarch64-release" + }, + { + "name": "linux-aarch64-debug-shared", + "displayName": "Build Linux AArch64 Debug Shared", + "description": "Build QcPerfCore as a shared library (Debug)", + "configurePreset": "linux-aarch64-debug-shared" + }, + { + "name": "linux-aarch64-release-shared", + "displayName": "Build Linux AArch64 Release Shared", + "description": "Build QcPerfCore as a shared library (Release)", + "configurePreset": "linux-aarch64-release-shared" + } + ] +} diff --git a/qcperf/backends/CMakeLists.txt b/qcperf/backends/CMakeLists.txt index 8653d45..a0bb5ed 100644 --- a/qcperf/backends/CMakeLists.txt +++ b/qcperf/backends/CMakeLists.txt @@ -14,22 +14,41 @@ # # Each backend implements a common interface defined in the inc/ directory, # allowing the core library to interact with any backend in a uniform way. -# Platform-specific backends are conditionally included based on the target platform. +# Backend inclusion is controlled by QCPERF_ENABLED_* variables set in +# cmake/BuildConfig.cmake based on the BACKENDS CMake option and the +# detected platform. # ============================================================================ # Backend Subdirectories # ============================================================================ -# Add subdirectories for individual backends -# The dummy backend is always included as a fallback implementation -add_subdirectory(dummy) +# Add subdirectories for individual backends, guarded by QCPERF_ENABLED_* flags. +# To add a new backend: +# 1. Add its name to QCPERF_PLATFORM_SUPPORTED_BACKENDS in cmake/BuildConfig.cmake +# 2. Add the corresponding add_subdirectory call below + +if(QCPERF_ENABLED_DUMMY) + add_subdirectory(dummy) +endif() # Add utility libraries used by backends add_subdirectory(utils) -# Add platform-specific backends -# Windows ARM64 platforms include additional backends for hardware monitoring -if(QCPERF_PLATFORM_WINDOWS_ARM64) +# Linux ARM64 backends +if(QCPERF_ENABLED_QCOM_LINUX_CPU) + add_subdirectory(qcom-linux-cpu) +endif() + +if(QCPERF_ENABLED_QCOM_LINUX_NPU) + add_subdirectory(qcom-dsp) + add_subdirectory(qcom-dsp-npu) +endif() + +# Windows ARM64 backends +if(QCPERF_ENABLED_WOS_THERMAL) add_subdirectory(wos-thermal) +endif() + +if(QCPERF_ENABLED_WOS_POWER) add_subdirectory(wos-power-backend) endif() diff --git a/qcperf/backends/dummy/CMakeLists.txt b/qcperf/backends/dummy/CMakeLists.txt index f6398d4..0d62b4a 100644 --- a/qcperf/backends/dummy/CMakeLists.txt +++ b/qcperf/backends/dummy/CMakeLists.txt @@ -10,6 +10,8 @@ # qcperf/backends/inc, allowing it to be used interchangeably with other # backends through the unified backend interface. +message("Added dummy backend") + # Create the dummy backend library add_library(QcPerfDummyBackend STATIC src/dummy.c @@ -25,7 +27,7 @@ target_include_directories(QcPerfDummyBackend PUBLIC ${CMAKE_SOURCE_DIR}/utils/qtime/inc ) -target_link_libraries(QcPerfDummyBackend +target_link_libraries(QcPerfDummyBackend PUBLIC QcPerfQThread QcPerfQTime ${_OS_M} diff --git a/qcperf/backends/dummy/src/dummy.c b/qcperf/backends/dummy/src/dummy.c index a6e54f2..46f59de 100644 --- a/qcperf/backends/dummy/src/dummy.c +++ b/qcperf/backends/dummy/src/dummy.c @@ -47,7 +47,7 @@ #include "dummy.h" #include "qcperf_backend_interface.h" -#include "qthread.h" +#include "QThread.h" #include "qtime.h" static QcPerfMessageCallback g_message_callback = NULL; @@ -508,9 +508,8 @@ static void* get_dummy_data(void* param) { uint64_t current_time = 0; uint64_t last_stream_time = 0; uint64_t elapsed_ns = 0; - char dummy_string[64]; - uint32_t sample_count = 0; - enum QTimeReturnCode time_return_code = RETURN_CODE_TIME_FAILED; + char dummy_string[64] = {0}; + uint32_t sample_count = 0; if (NULL != request) { g_is_thread_running = true; @@ -525,9 +524,8 @@ static void* get_dummy_data(void* param) { if (NULL != capability_info) { // Calculate how many samples to collect before streaming // Convert ms to ns for consistent calculations - uint64_t sampling_rate_ns = (uint64_t)request->sampling_rate * 1000000ULL; uint64_t streaming_rate_ns = (uint64_t)request->streaming_rate * 1000000ULL; - samples_per_stream = (uint32_t)((request->streaming_rate + request->sampling_rate - 1) / request->sampling_rate); + samples_per_stream = (uint32_t)((request->streaming_rate + request->sampling_rate - 1) / request->sampling_rate); total_metrics = samples_per_stream * capability_info->metric_ids_list_len; @@ -550,11 +548,11 @@ static void* get_dummy_data(void* param) { } } - time_return_code = get_time_ns(¤t_time); + get_time_ns(¤t_time); last_stream_time = current_time; while (g_is_thread_running) { - time_return_code = get_time_ns(¤t_time); + get_time_ns(¤t_time); for (uint32_t i = 0; i < capability_info->metric_ids_list_len; i++) { uint32_t metric_index = data->metric_response_len; @@ -562,7 +560,7 @@ static void* get_dummy_data(void* param) { SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Metric index exceeds allocated size"); break; } - + data->metric_response[metric_index].metric_id = capability_info->metric_ids_list[i].metric_id; data->metric_response[metric_index].timestamp = current_time; diff --git a/qcperf/backends/inc/CMakeLists.txt b/qcperf/backends/inc/CMakeLists.txt index afb0629..02efeff 100644 --- a/qcperf/backends/inc/CMakeLists.txt +++ b/qcperf/backends/inc/CMakeLists.txt @@ -5,6 +5,10 @@ # aggregates all backend implementations and provides a single point of # dependency for the core library. It centralizes backend-specific includes # and dependencies, allowing the core to remain decoupled from specific backends. +# +# Backend inclusion is controlled by QCPERF_ENABLED_* variables set in +# cmake/BuildConfig.cmake based on the BACKENDS CMake option and the +# detected platform. # ============================================================================ # Interface Library Target @@ -21,33 +25,58 @@ add_library(QcPerfBackends INTERFACE) # These are the common headers that all backends need to implement target_include_directories(QcPerfBackends INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/backends/dummy/inc ) # ============================================================================ -# Dependencies +# Per-Backend Includes and Link Libraries # ============================================================================ -# Link against all backend libraries -# The dummy backend is always included as a fallback -target_link_libraries(QcPerfBackends INTERFACE - QcPerfDummyBackend -) +# Each backend is conditionally included based on its QCPERF_ENABLED_* flag. +# To add a new backend, add a corresponding block below following the same pattern. -# ============================================================================ -# Platform-Specific Configuration -# ============================================================================ -# Add platform-specific backends -# Windows ARM64 platforms include additional backends for hardware monitoring -if(QCPERF_PLATFORM_WINDOWS_ARM64) +# Dummy backend +if(QCPERF_ENABLED_DUMMY) target_include_directories(QcPerfBackends INTERFACE - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/backends/wos-thermal/inc - ${CMAKE_SOURCE_DIR}/backends/wos-power-backend/inc + ${CMAKE_SOURCE_DIR}/backends/dummy/inc + ) + target_link_libraries(QcPerfBackends INTERFACE + QcPerfDummyBackend + ) +endif() + +# Linux ARM64 backends +if(QCPERF_ENABLED_QCOM_LINUX_CPU) + target_include_directories(QcPerfBackends INTERFACE + ${CMAKE_SOURCE_DIR}/backends/qcom-linux-cpu/inc + ) + target_link_libraries(QcPerfBackends INTERFACE + QcPerfQcomLinuxCpuBackend ) +endif() +if(QCPERF_ENABLED_QCOM_LINUX_NPU) + target_include_directories(QcPerfBackends INTERFACE + ${CMAKE_SOURCE_DIR}/backends/qcom-dsp-npu/inc + ) + target_link_libraries(QcPerfBackends INTERFACE + QcPerfDspNpuBackend + ) +endif() + +# Windows ARM64 backends +if(QCPERF_ENABLED_WOS_THERMAL) + target_include_directories(QcPerfBackends INTERFACE + ${CMAKE_SOURCE_DIR}/backends/wos-thermal/inc + ) target_link_libraries(QcPerfBackends INTERFACE QcPerfWosThermalBackend - QcPerfWosPowerBackend ) +endif() +if(QCPERF_ENABLED_WOS_POWER) + target_include_directories(QcPerfBackends INTERFACE + ${CMAKE_SOURCE_DIR}/backends/wos-power-backend/inc + ) + target_link_libraries(QcPerfBackends INTERFACE + QcPerfWosPowerBackend + ) endif() diff --git a/qcperf/backends/inc/qcperf_backend_enum.h b/qcperf/backends/inc/qcperf_backend_enum.h index 71972fd..29702ad 100644 --- a/qcperf/backends/inc/qcperf_backend_enum.h +++ b/qcperf/backends/inc/qcperf_backend_enum.h @@ -55,12 +55,20 @@ * * Enumeration of backend implementations available in the QcPerf library. * Each backend provides specific performance monitoring capabilities. + * + * @note All enum values are always defined regardless of which backends are + * compiled. Whether a backend is actually available at runtime is + * controlled by the QCPERF_ENABLED_* compile definitions set via the + * BACKENDS CMake option. Attempting to connect to a backend that was + * not compiled in will return QC_PERF_RETURN_CODE_INVALID_BACKEND_ID. */ enum QcPerfBackendId { - QC_PERF_BACKEND_DUMMY = 0, /**< Dummy backend for testing purposes */ - QC_PERF_BACKEND_POWER, /**< Power monitoring backend */ - QC_PERF_BACKEND_THERMAL, /**< Thermal monitoring backend */ - QC_PERF_BACKEND_MAX, /**< Maximum number of backends (sentinel value) */ + QC_PERF_BACKEND_DUMMY = 0, /**< Dummy backend for testing purposes */ + QC_PERF_BACKEND_QCOM_LINUX_CPU, /**< Qualcomm Linux CPU monitoring backend (Linux ARM64) */ + QC_PERF_BACKEND_DSP_NPU, /**< Qualcomm DSP NPU monitoring backend (Linux ARM64) */ + QC_PERF_BACKEND_POWER, /**< Power monitoring backend (Windows ARM64) */ + QC_PERF_BACKEND_THERMAL, /**< Thermal monitoring backend (Windows ARM64) */ + QC_PERF_BACKEND_MAX, /**< Sentinel value — total number of backend slots */ }; #endif /* QCPERF_BACKEND_ENUM_H */ diff --git a/qcperf/backends/inc/qcperf_backends.h b/qcperf/backends/inc/qcperf_backends.h index 2888228..0c6a359 100644 --- a/qcperf/backends/inc/qcperf_backends.h +++ b/qcperf/backends/inc/qcperf_backends.h @@ -36,14 +36,40 @@ * maintains a registry of all available backend initialization functions. * It serves as a unified interface between the core library and all backend * implementations, allowing the core to remain decoupled from specific backends. + * + * Each entry in backend_init_fns[] corresponds to a QcPerfBackendId enum value. + * Backends that are not compiled in (i.e. their QCPERF_ENABLED_* definition is + * absent) have a NULL entry. The core checks for NULL before invoking an entry + * and returns QC_PERF_RETURN_CODE_INVALID_BACKEND_ID for disabled backends. + * + * To add a new backend: + * 1. Add its QCPERF_ENABLED_ guard and #include below. + * 2. Add a corresponding NULL / &init_fn entry in backend_init_fns[]. + * 3. Add its name to QCPERF_PLATFORM_SUPPORTED_BACKENDS in cmake/BuildConfig.cmake. */ -#ifndef QC_PERF_BACKENDS_H // QC_PERF_BACKENDS_H +#ifndef QC_PERF_BACKENDS_H #define QC_PERF_BACKENDS_H +#if defined(QCPERF_ENABLED_DUMMY) #include "dummy.h" +#endif + +#if defined(QCPERF_ENABLED_QCOM_LINUX_CPU) +#include "qcom_linux_cpu.h" +#endif + +#if defined(QCPERF_ENABLED_QCOM_LINUX_NPU) +#include "qcom_dsp_npu.h" +#endif + +#if defined(QCPERF_ENABLED_WOS_POWER) #include "wos_power_backend.h" +#endif + +#if defined(QCPERF_ENABLED_WOS_THERMAL) #include "wos_thermal.h" +#endif /** * @typedef backend_init_t @@ -60,12 +86,37 @@ typedef enum QcPerfReturnCode (*backend_init_t)(struct QcPerfBackendPrivate*); /** * @brief Array of backend initialization function pointers * - * This static array contains pointers to all available backend initialization - * functions. The array is NULL-terminated to allow iteration without knowing - * the size at compile time. New backends should be added to this array. + * This static array contains pointers to all backend initialization functions, + * indexed by QcPerfBackendId. Entries for backends that are not compiled in + * are set to NULL. The core checks for NULL before invoking an entry. * - * @note The array must always be NULL-terminated */ -static backend_init_t backend_init_fns[] = {&qcperf_dummy_create, &wos_power_backend_create, &qcperf_wos_thermal_backend_create}; +static backend_init_t backend_init_fns[] = { +#if defined(QCPERF_ENABLED_DUMMY) + &qcperf_dummy_create, /* QC_PERF_BACKEND_DUMMY */ +#else + NULL, /* QC_PERF_BACKEND_DUMMY (disabled) */ +#endif +#if defined(QCPERF_ENABLED_QCOM_LINUX_CPU) + &qcperf_qcom_linux_cpu_create, /* QC_PERF_BACKEND_QCOM_LINUX_CPU */ +#else + NULL, /* QC_PERF_BACKEND_QCOM_LINUX_CPU (disabled) */ +#endif +#if defined(QCPERF_ENABLED_QCOM_LINUX_NPU) + &qcperf_dsp_npu_create, /* QC_PERF_BACKEND_DSP_NPU */ +#else + NULL, /* QC_PERF_BACKEND_DSP_NPU (disabled) */ +#endif +#if defined(QCPERF_ENABLED_WOS_POWER) + &wos_power_backend_create, /* QC_PERF_BACKEND_POWER */ +#else + NULL, /* QC_PERF_BACKEND_POWER (disabled) */ +#endif +#if defined(QCPERF_ENABLED_WOS_THERMAL) + &qcperf_wos_thermal_backend_create, /* QC_PERF_BACKEND_THERMAL */ +#else + NULL, /* QC_PERF_BACKEND_THERMAL (disabled) */ +#endif +}; #endif // QC_PERF_BACKENDS_H diff --git a/qcperf/backends/qcom-dsp-npu/CMakeLists.txt b/qcperf/backends/qcom-dsp-npu/CMakeLists.txt new file mode 100644 index 0000000..b9a5dbd --- /dev/null +++ b/qcperf/backends/qcom-dsp-npu/CMakeLists.txt @@ -0,0 +1,37 @@ +# ============================================================================ +# QcPerf DSP NPU Backend +# ============================================================================ +# This CMakeLists.txt builds the DSP NPU backend, which collects real +# performance metrics from Qualcomm NPU/CDSP hardware using the DSP library. +# The DSP NPU backend implements the standard backend interface defined in +# qcperf/backends/inc, allowing it to be used interchangeably with other +# backends through the unified backend interface. + +message("Added DSP NPU backend") + +# Create the DSP NPU backend library +add_library(QcPerfDspNpuBackend STATIC + src/qcom_dsp_npu.c + src/qcom_dsp_npu_info.c +) + +target_include_directories(QcPerfDspNpuBackend PUBLIC + inc + ${CMAKE_SOURCE_DIR}/core/inc + ${CMAKE_SOURCE_DIR}/core/inc/internal + ${CMAKE_SOURCE_DIR}/backends/inc + ${CMAKE_SOURCE_DIR}/backends/qcom-dsp/inc + ${CMAKE_SOURCE_DIR}/utils/qthread/inc + ${CMAKE_SOURCE_DIR}/utils/qtime/inc +) + +target_link_libraries(QcPerfDspNpuBackend PUBLIC + QcPerfQThread + QcPerfQTime + ${_OS_M} +) + +# Link the DSP library for NPU access +target_link_libraries(QcPerfDspNpuBackend PRIVATE + QcPerfQcomDsp +) \ No newline at end of file diff --git a/qcperf/backends/qcom-dsp-npu/inc/qcom_dsp_npu.h b/qcperf/backends/qcom-dsp-npu/inc/qcom_dsp_npu.h new file mode 100644 index 0000000..972d00b --- /dev/null +++ b/qcperf/backends/qcom-dsp-npu/inc/qcom_dsp_npu.h @@ -0,0 +1,61 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file qcom_dsp_npu.h + * @brief DSP NPU backend interface for libqcperf + * @author Snehal Lalage (slalage@qti.qualcomm.com) + * This header provides the public interface for the DSP NPU backend, which + * collects performance metrics from Qualcomm NPU/CDSP hardware using the + * DSP library for real hardware monitoring capabilities. + */ + +#ifndef QCOM_DSP_NPU_H +#define QCOM_DSP_NPU_H + +#include "qcom_dsp_npu_info.h" + +struct QcPerfBackendPrivate; + +/** + * @brief Create and initialize the DSP NPU backend + * + * This function configures the DSP NPU backend by populating the backend + * private structure with function pointers for all required backend + * operations including initialization, start, stop, deinitialization, + * and callback registration. + * + * @param[in,out] backend Pointer to backend private structure to be configured + * + * @return QC_PERF_RETURN_CODE_SUCCESS on successful creation + * @return QC_PERF_RETURN_CODE_NULL_POINTER if backend pointer is NULL + */ +enum QcPerfReturnCode qcperf_dsp_npu_create(struct QcPerfBackendPrivate* backend); + +#endif /* QCOM_DSP_NPU_H */ \ No newline at end of file diff --git a/qcperf/backends/qcom-dsp-npu/inc/qcom_dsp_npu_info.h b/qcperf/backends/qcom-dsp-npu/inc/qcom_dsp_npu_info.h new file mode 100644 index 0000000..f403d0f --- /dev/null +++ b/qcperf/backends/qcom-dsp-npu/inc/qcom_dsp_npu_info.h @@ -0,0 +1,102 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file qcom_dsp_npu_info.h + * @brief Static metric definitions and initialization functions for DSP NPU backend + * @author Snehal Lalage (slalage@qti.qualcomm.com) + * This header defines all metric IDs, names, descriptions, and units for the + * DSP NPU backend's capabilities. It also provides initialization functions to + * populate metric information structures with these static definitions. + */ + +#ifndef QCOM_DSP_NPU_INFO_H +#define QCOM_DSP_NPU_INFO_H + +#include "qcperf_common.h" + +#define DSP_NPU_CAPABILITY_0_ID 0 +#define DSP_NPU_CAPABILITIES_LEN 1 + +#define DSP_NPU_STREAMING_RATES_LEN 10 +#define DSP_NPU_STREAMING_RATES 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 + +#define DSP_NPU_SAMPLING_RATES_LEN 6 +#define DSP_NPU_SAMPLING_RATES 1, 5, 10, 50, 100, 200 + +#define DSP_NPU_CAPABILITY_0 "npu" +#define DSP_NPU_CAPABILITY_0_METRIC_COUNT 4 + +/** + * @enum DspNpuCapability0MetricIndex + * @brief Array indices for NPU Capability 0 metrics + * + * This enum defines the array indices for accessing metrics in the + * metrics_data array for NPU Capability 0, providing better code readability. + */ +enum DspNpuCapability0MetricIndex { + DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_UTILIZATION = 0, + DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_CLOCK, + DSP_NPU_CAPABILITY_0_METRIC_INDEX_HVX_UTILIZATION, + DSP_NPU_CAPABILITY_0_METRIC_INDEX_HMX_UTILIZATION, +}; + +// NPU Metric Definitions +#define DSP_NPU_METRIC_Q6_UTILIZATION_ID 0 +#define DSP_NPU_METRIC_Q6_UTILIZATION_NAME "Q6 Utilization" +#define DSP_NPU_METRIC_Q6_UTILIZATION_DESCRIPTION "Average effective Q6 clock utilization with respect to max Q6 clock" +#define DSP_NPU_METRIC_Q6_UTILIZATION_UNIT "%" + +#define DSP_NPU_METRIC_Q6_CLOCK_ID 1 +#define DSP_NPU_METRIC_Q6_CLOCK_NAME "Q6 Clock" +#define DSP_NPU_METRIC_Q6_CLOCK_DESCRIPTION "Average Q6 clock frequency" +#define DSP_NPU_METRIC_Q6_CLOCK_UNIT "KHz" + +#define DSP_NPU_METRIC_HVX_UTILIZATION_ID 2 +#define DSP_NPU_METRIC_HVX_UTILIZATION_NAME "HVX Utilization" +#define DSP_NPU_METRIC_HVX_UTILIZATION_DESCRIPTION "Average HVX utilization with respect to max Q6 clock" +#define DSP_NPU_METRIC_HVX_UTILIZATION_UNIT "%" + +#define DSP_NPU_METRIC_HMX_UTILIZATION_ID 3 +#define DSP_NPU_METRIC_HMX_UTILIZATION_NAME "HMX Utilization" +#define DSP_NPU_METRIC_HMX_UTILIZATION_DESCRIPTION "Average HMX utilization with respect to max Q6 clock" +#define DSP_NPU_METRIC_HMX_UTILIZATION_UNIT "%" + +/** + * @brief Initialize NPU Capability 0 metrics data + * + * Populates the provided metrics_data array with metric information for + * NPU Capability 0, including metric IDs, names, descriptions, and units. + * + * @param[out] metrics_data Array to be populated with NPU Capability 0 metric information + * (must have space for DSP_NPU_CAPABILITY_0_METRIC_COUNT entries) + */ +void dsp_npu_capability_0_init_metrics(struct QcPerfMetricInfo *metrics_data); + +#endif /* QCOM_DSP_NPU_INFO_H */ \ No newline at end of file diff --git a/qcperf/backends/qcom-dsp-npu/src/qcom_dsp_npu.c b/qcperf/backends/qcom-dsp-npu/src/qcom_dsp_npu.c new file mode 100644 index 0000000..457b6c9 --- /dev/null +++ b/qcperf/backends/qcom-dsp-npu/src/qcom_dsp_npu.c @@ -0,0 +1,533 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file qcom_dsp_npu.c + * @brief DSP NPU backend implementation for libqcperf + * @author Snehal Lalage (slalage@qti.qualcomm.com) + */ + +#include +#include +#include +#include +#ifdef __linux__ +#include +#else +#include +#endif + +#include "qcom_dsp_npu.h" +#include "qcperf_backend_interface.h" +#include "qcom_dsp.h" +#include "QThread.h" +#include "qtime.h" + +static QcPerfMessageCallback g_message_callback = NULL; +static QcPerfDataCallback g_data_callback = NULL; + +static struct QcPerfBackendInfo g_backend_info = {0}; + +// metric data array +struct QcPerfMetricInfo g_capability_0_metrics_data[DSP_NPU_CAPABILITY_0_METRIC_COUNT] = {0}; + +static volatile bool g_is_thread_running = false; +static struct QThreadInfo g_thread_info = {0}; +static bool g_is_dsp_initialized = false; + +static inline void send_message(enum QcPerfMessageLevel level, const char* fmt, ...); +static enum QcPerfReturnCode dsp_npu_alloc(void); +static void dsp_npu_free(void); +static void* get_dsp_npu_data(void* param); +static enum QcPerfReturnCode validate_request(struct QcPerfRequest* request); + +#define MESSAGE_MAX_LEN 256 + +/** + * @brief Macro to conditionally log messages if message callback is set + */ +#define SEND_MESSAGE(level, ...) \ + if (g_message_callback != NULL) { \ + send_message(level, __VA_ARGS__); \ + } + +static const uint16_t streaming_rates[DSP_NPU_STREAMING_RATES_LEN] = {DSP_NPU_STREAMING_RATES}; +static const uint16_t sampling_rates[DSP_NPU_SAMPLING_RATES_LEN] = {DSP_NPU_SAMPLING_RATES}; + +/** + * @brief Set the message callback function + */ +static enum QcPerfReturnCode dsp_npu_set_message_callback(QcPerfMessageCallback message_callback) { + g_message_callback = message_callback; + return QC_PERF_RETURN_CODE_SUCCESS; +} + +/** + * @brief Initialize the DSP NPU backend + */ +static enum QcPerfReturnCode dsp_npu_init(void) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_SUCCESS; + + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Initializing DSP NPU backend"); + + g_backend_info.backend_id = QC_PERF_BACKEND_DSP_NPU; + + // Initialize DSP library + enum DspReturnCode dsp_ret = qcom_dsp_init(DSP_NPU0); + if (dsp_ret != RETURN_CODE_DSP_LIB_SUCCESS) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to initialize DSP library: error code %d", dsp_ret); + ret = QC_PERF_RETURN_CODE_FAILED; + } else { + g_is_dsp_initialized = true; + + ret = dsp_npu_alloc(); + + if (QC_PERF_RETURN_CODE_SUCCESS == ret) { + dsp_npu_capability_0_init_metrics(g_capability_0_metrics_data); + + // capability_0 + g_backend_info.capabilities_list[0].capability_id = DSP_NPU_CAPABILITY_0_ID; + snprintf(g_backend_info.capabilities_list[0].capability_name, CAPABILITY_NAME_MAX_LEN, "%s", DSP_NPU_CAPABILITY_0); + g_backend_info.capabilities_list[0].capability_name_len = strlen(g_backend_info.capabilities_list[0].capability_name); + g_backend_info.capabilities_list[0].metric_ids_list_len = DSP_NPU_CAPABILITY_0_METRIC_COUNT; + + for (uint8_t strate_idx = 0; strate_idx < DSP_NPU_STREAMING_RATES_LEN && strate_idx < MAX_SAMPLING_STREAMING_RATES_LEN; strate_idx++) { + g_backend_info.capabilities_list[0].streaming_rate[strate_idx] = streaming_rates[strate_idx]; + g_backend_info.capabilities_list[0].streaming_rate_len++; + } + + for (uint8_t sprate_idx = 0; sprate_idx < DSP_NPU_SAMPLING_RATES_LEN && sprate_idx < MAX_SAMPLING_STREAMING_RATES_LEN; sprate_idx++) { + g_backend_info.capabilities_list[0].sampling_rate[sprate_idx] = sampling_rates[sprate_idx]; + g_backend_info.capabilities_list[0].sampling_rate_len++; + } + + g_backend_info.capabilities_list[0].metric_ids_list = (struct QcPerfMetricInfo*)&g_capability_0_metrics_data; + + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "DSP NPU backend initialized successfully"); + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to initialize DSP NPU backend: memory allocation failed"); + dsp_npu_free(); + if (g_is_dsp_initialized) { + qcom_dsp_deinit(DSP_NPU0); + g_is_dsp_initialized = false; + } + } + } + + return ret; +} + +/** + * @brief Get backend information including capabilities and metrics + */ +static enum QcPerfReturnCode dsp_npu_backend_info(struct QcPerfBackendInfo* backend_info) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_SUCCESS; + + if (NULL == backend_info) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Backend info is NULL"); + ret = QC_PERF_RETURN_CODE_NULL_POINTER; + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Retrieving DSP NPU backend capabilities information"); + *backend_info = g_backend_info; + } + + return ret; +} + +/** + * @brief Set the result callback function + */ +static enum QcPerfReturnCode dsp_npu_set_data_callback(QcPerfDataCallback data_callback) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; + if (NULL == data_callback) { + return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; + } else if (NULL != g_data_callback) { + return_code = QC_PERF_RETURN_CODE_CALLBACK_ALREADY_SET; + } else { + g_data_callback = data_callback; + return_code = QC_PERF_RETURN_CODE_SUCCESS; + } + return return_code; +} + +/** + * @brief Validate the performance monitoring request + */ +static enum QcPerfReturnCode validate_request(struct QcPerfRequest* request) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_CAPABILITY_NOT_FOUND; + struct QcPerfCapabilityInfo* capability_info = NULL; + bool sampling_rate_valid = false; + bool streaming_rate_valid = false; + + // Find the capability + for (uint8_t cap_idx = 0; cap_idx < g_backend_info.capabilities_list_length; cap_idx++) { + if (g_backend_info.capabilities_list[cap_idx].capability_id == request->capability_id) { + capability_info = &g_backend_info.capabilities_list[cap_idx]; + ret = QC_PERF_RETURN_CODE_SUCCESS; + break; + } + } + + if (QC_PERF_RETURN_CODE_SUCCESS != ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Capability ID %u not found", request->capability_id); + } else { + for (uint8_t sprate_idx = 0; sprate_idx < capability_info->sampling_rate_len; sprate_idx++) { + if (capability_info->sampling_rate[sprate_idx] == request->sampling_rate) { + sampling_rate_valid = true; + break; + } + } + + if (false == sampling_rate_valid) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Invalid sampling rate %u for capability ID %u", request->sampling_rate, request->capability_id); + ret = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; + } else { + for (uint8_t strate_idx = 0; strate_idx < capability_info->streaming_rate_len; strate_idx++) { + if (capability_info->streaming_rate[strate_idx] == request->streaming_rate) { + streaming_rate_valid = true; + break; + } + } + + if (false == streaming_rate_valid) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Invalid streaming rate %u for capability ID %u", request->streaming_rate, request->capability_id); + ret = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Request validation successful for capability ID %u", request->capability_id); + ret = QC_PERF_RETURN_CODE_SUCCESS; + } + } + } + + return ret; +} + +/** + * @brief Start performance data collection + */ +static enum QcPerfReturnCode dsp_npu_start(struct QcPerfRequest* request) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Starting profiling"); + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_SUCCESS; + + if (NULL == request) { + ret = QC_PERF_RETURN_CODE_NULL_POINTER; + } else { + ret = validate_request(request); + if (QC_PERF_RETURN_CODE_SUCCESS != ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Request validation failed"); + } else if (NULL == g_data_callback) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Data Callback is not set"); + ret = QC_PERF_RETURN_CODE_FAILED; + } else if (g_is_thread_running) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "Performance monitoring thread is already running"); + ret = QC_PERF_RETURN_CODE_ALREADY_INITIALIZED; + } else { + struct QThreadAttributes thread_attrs = {0}; + enum QThreadReturnCode thread_ret = RET_QTHREAD_CREATE_FAILED; + + thread_attrs.stack_size = 0; + thread_attrs.thread_params = request; + thread_attrs.thread_fn = get_dsp_npu_data; + snprintf((char*)thread_attrs.thread_name, THREAD_NAME_SIZE, "qcperf_dsp_npu_thread"); + thread_attrs.thread_name_len = (uint8_t)strlen((char*)thread_attrs.thread_name); + + thread_ret = thread_create(&thread_attrs, &g_thread_info); + + if (RET_QTHREAD_CREATE_SUCCESS != thread_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to create performance monitoring thread"); + ret = QC_PERF_RETURN_CODE_FAILED; + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Performance monitoring thread started successfully"); + ret = QC_PERF_RETURN_CODE_SUCCESS; + } + } + } + + return ret; +} + +/** + * @brief Stop performance data collection + */ +static enum QcPerfReturnCode dsp_npu_stop(struct QcPerfRequest* request) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Stopping profiling"); + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_SUCCESS; + + if (NULL == request) { + ret = QC_PERF_RETURN_CODE_NULL_POINTER; + } else { + if (g_is_thread_running) { + enum QThreadReturnCode thread_ret = RET_QTHREAD_JOIN_FAILED; + + g_is_thread_running = false; + + thread_ret = thread_join(&g_thread_info); + + if (RET_QTHREAD_JOIN_SUCCESS == thread_ret) { + thread_ret = thread_destroy(&g_thread_info); + + if (RET_QTHREAD_DESTROY_SUCCESS == thread_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Performance monitoring thread stopped successfully"); + ret = QC_PERF_RETURN_CODE_SUCCESS; + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to destroy thread handle"); + ret = QC_PERF_RETURN_CODE_FAILED; + } + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to join thread"); + ret = QC_PERF_RETURN_CODE_FAILED; + } + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Performance monitoring thread is not running"); + ret = QC_PERF_RETURN_CODE_SUCCESS; + } + } + + return ret; +} + +/** + * @brief Deinitialize the DSP NPU backend + */ +static enum QcPerfReturnCode dsp_npu_deinit(void) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Deinitializing DSP NPU backend"); + + dsp_npu_free(); + + if (g_is_dsp_initialized) { + enum DspReturnCode dsp_ret = qcom_dsp_deinit(DSP_NPU0); + if (dsp_ret != RETURN_CODE_DSP_LIB_SUCCESS) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to deinitialize DSP library: error code %d", dsp_ret); + } + g_is_dsp_initialized = false; + } + + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "DSP NPU backend deinitialized successfully"); + + return QC_PERF_RETURN_CODE_SUCCESS; +} + +static inline void send_message(enum QcPerfMessageLevel level, const char* fmt, ...) { + char msg[MESSAGE_MAX_LEN]; + va_list args; + va_start(args, fmt); + int len = vsnprintf(msg, sizeof(msg), fmt, args); + va_end(args); + + if (len > 0) { + if (len >= MESSAGE_MAX_LEN) { + len = MESSAGE_MAX_LEN - 1; + } + struct QcPerfMessage msgStruct = {.message = msg, .message_length = (size_t)len, .message_level = level}; + + g_message_callback(&msgStruct); + } +} + +/** + * @brief Allocate memory for backend information + */ +static enum QcPerfReturnCode dsp_npu_alloc(void) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_SUCCESS; + + g_backend_info.capabilities_list = (struct QcPerfCapabilityInfo*)calloc(DSP_NPU_CAPABILITIES_LEN, sizeof(struct QcPerfCapabilityInfo)); + + if (NULL == g_backend_info.capabilities_list) { + ret = QC_PERF_RETURN_CODE_CALLOC_FAILED; + } else { + g_backend_info.capabilities_list_length = DSP_NPU_CAPABILITIES_LEN; + } + + return ret; +} + +/** + * @brief Free all allocated memory for backend information + */ +static void dsp_npu_free(void) { + if (NULL != g_backend_info.capabilities_list) { + for (int cap_idx = 0; cap_idx < g_backend_info.capabilities_list_length; cap_idx++) { + g_backend_info.capabilities_list[cap_idx].metric_ids_list = NULL; + g_backend_info.capabilities_list[cap_idx].metric_ids_list_len = 0; + } + + free(g_backend_info.capabilities_list); + g_backend_info.capabilities_list = NULL; + } + + g_backend_info.capabilities_list_length = 0; +} + +/** + * @brief Thread function for collecting DSP NPU metric data + */ +static void* get_dsp_npu_data(void* param) { + struct QcPerfRequest* request = (struct QcPerfRequest*)param; + struct QcPerfCapabilityInfo* capability_info = NULL; + uint32_t samples_per_stream = 0; + uint32_t total_metrics = 0; + struct QcPerfData* data = NULL; + uint64_t current_time = 0; + uint64_t last_stream_time = 0; + uint64_t elapsed_ns = 0; + uint32_t sample_count = 0; + int no_metrics = 0; + + if (NULL != request) { + g_is_thread_running = true; + + for (int cap_idx = 0; cap_idx < g_backend_info.capabilities_list_length; cap_idx++) { + if (g_backend_info.capabilities_list[cap_idx].capability_id == request->capability_id) { + capability_info = &g_backend_info.capabilities_list[cap_idx]; + break; + } + } + + if (NULL != capability_info) { + // Calculate how many samples to collect before streaming + uint64_t streaming_rate_ns = (uint64_t)request->streaming_rate * 1000000ULL; + samples_per_stream = (uint32_t)((request->streaming_rate + request->sampling_rate - 1) / request->sampling_rate); + + total_metrics = samples_per_stream * capability_info->metric_ids_list_len; + + data = (struct QcPerfData*)calloc(1, sizeof(struct QcPerfData)); + if (NULL != data) { + data->metric_response = (struct QcPerfMetricResponse*)calloc(total_metrics, sizeof(struct QcPerfMetricResponse)); + if (NULL != data->metric_response) { + data->capabilityId = request->capability_id; + data->backend_id = QC_PERF_BACKEND_DSP_NPU; + data->metric_response_len = 0; + + get_time_ns(¤t_time); + last_stream_time = current_time; + + while (g_is_thread_running) { + get_time_ns(¤t_time); + + // Get data from DSP library + struct sysmon_query_prof_data* prof_data = qcom_dsp_get_prof_data(DSP_NPU0, &no_metrics); + + if (prof_data != NULL && no_metrics> 0) { + // Populate metrics from DSP data + for (uint32_t metric_idx = 0; metric_idx < capability_info->metric_ids_list_len; metric_idx++) { + uint32_t metric_index = data->metric_response_len; + if (metric_index >= total_metrics) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Metric index exceeds allocated size"); + break; + } + + data->metric_response[metric_index].metric_id = capability_info->metric_ids_list[metric_idx].metric_id; + data->metric_response[metric_index].timestamp = current_time; + data->metric_response[metric_index].metric_value.data_type = QC_PERF_DATA_TYPE_DOUBLE; + + switch (metric_idx) { + case DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_UTILIZATION: + data->metric_response[metric_index].metric_value.double_value = (double)prof_data->q6_utilization; + break; + case DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_CLOCK: + data->metric_response[metric_index].metric_value.double_value = (double)prof_data->q6_clock; + break; + case DSP_NPU_CAPABILITY_0_METRIC_INDEX_HVX_UTILIZATION: + data->metric_response[metric_index].metric_value.double_value = (double)prof_data->hvx_utilization; + break; + case DSP_NPU_CAPABILITY_0_METRIC_INDEX_HMX_UTILIZATION: + data->metric_response[metric_index].metric_value.double_value = (double)prof_data->hmx_utilization; + break; + default: + break; + } + data->metric_response_len++; + } + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "Failed to get profiling data from DSP"); + } + + // Increment sample count + sample_count = sample_count + 1; + + // Check if it's time to stream data + elapsed_ns = current_time - last_stream_time; + if (sample_count >= samples_per_stream || elapsed_ns >= streaming_rate_ns) { + // Call the callback with the data + if (NULL != g_data_callback && data->metric_response_len > 0) { + g_data_callback(data); + data->metric_response_len = 0; + } else if (NULL == g_data_callback) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Result callback is NULL, cannot send metric data"); + } + + // Reset counters + sample_count = 0; + last_stream_time = current_time; + } + + // Sleep for the sampling rate + if (g_is_thread_running) { + usleep((useconds_t)(request->sampling_rate * 1000)); + } + } + + free(data->metric_response); + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to allocate memory for metric responses"); + } + free(data); + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to allocate memory for performance data"); + } + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Capability info not found for requested capability ID"); + g_is_thread_running = false; + } + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Request parameter is NULL in thread function"); + } + return NULL; +} + +/** + * @brief Create and configure the DSP NPU backend + */ +enum QcPerfReturnCode qcperf_dsp_npu_create(struct QcPerfBackendPrivate* backend) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_SUCCESS; + + if (NULL == backend) { + ret = QC_PERF_RETURN_CODE_NULL_POINTER; + } else { + backend->qcperf_backend_init = dsp_npu_init; + backend->qcperf_backend_start = dsp_npu_start; + backend->qcperf_backend_stop = dsp_npu_stop; + backend->qcperf_backend_deinit = dsp_npu_deinit; + backend->qcperf_backend_info = dsp_npu_backend_info; + backend->set_message_callback = dsp_npu_set_message_callback; + backend->set_data_callback = dsp_npu_set_data_callback; + } + + return ret; +} \ No newline at end of file diff --git a/qcperf/backends/qcom-dsp-npu/src/qcom_dsp_npu_info.c b/qcperf/backends/qcom-dsp-npu/src/qcom_dsp_npu_info.c new file mode 100644 index 0000000..eee48e9 --- /dev/null +++ b/qcperf/backends/qcom-dsp-npu/src/qcom_dsp_npu_info.c @@ -0,0 +1,86 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file qcom_dsp_npu_info.c + * @brief Metric initialization implementation for DSP NPU backend + * @author Snehal Lalage (slalage@qti.qualcomm.com) + * This file implements the initialization functions that populate metric + * information structures with static definitions for the DSP NPU backend's + * capability. + */ + +#include +#include +#include "qcom_dsp_npu_info.h" + +/** + * @brief Initialize NPU Capability 0 metrics data + * + * This function populates the metric information for NPU Capability 0 + * using the macro definitions from qcom_dsp_npu_info.h + */ +void dsp_npu_capability_0_init_metrics(struct QcPerfMetricInfo *metrics_data) { + // Q6 Utilization + metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_UTILIZATION].metric_id = DSP_NPU_METRIC_Q6_UTILIZATION_ID; + snprintf(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_UTILIZATION].metric_name, METRIC_NAME_MAX_LEN, "%s", DSP_NPU_METRIC_Q6_UTILIZATION_NAME); + metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_UTILIZATION].metric_name_len = strlen(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_UTILIZATION].metric_name); + snprintf(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_UTILIZATION].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", DSP_NPU_METRIC_Q6_UTILIZATION_DESCRIPTION); + metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_UTILIZATION].metric_description_len = strlen(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_UTILIZATION].metric_description); + snprintf(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_UTILIZATION].metric_unit, MAX_METRIC_UNIT_LEN, "%s", DSP_NPU_METRIC_Q6_UTILIZATION_UNIT); + metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_UTILIZATION].metric_unit_len = strlen(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_UTILIZATION].metric_unit); + + // Q6 Clock + metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_CLOCK].metric_id = DSP_NPU_METRIC_Q6_CLOCK_ID; + snprintf(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_CLOCK].metric_name, METRIC_NAME_MAX_LEN, "%s", DSP_NPU_METRIC_Q6_CLOCK_NAME); + metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_CLOCK].metric_name_len = strlen(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_CLOCK].metric_name); + snprintf(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_CLOCK].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", DSP_NPU_METRIC_Q6_CLOCK_DESCRIPTION); + metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_CLOCK].metric_description_len = strlen(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_CLOCK].metric_description); + snprintf(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_CLOCK].metric_unit, MAX_METRIC_UNIT_LEN, "%s", DSP_NPU_METRIC_Q6_CLOCK_UNIT); + metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_CLOCK].metric_unit_len = strlen(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_Q6_CLOCK].metric_unit); + + // HVX Utilization + metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HVX_UTILIZATION].metric_id = DSP_NPU_METRIC_HVX_UTILIZATION_ID; + snprintf(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HVX_UTILIZATION].metric_name, METRIC_NAME_MAX_LEN, "%s", DSP_NPU_METRIC_HVX_UTILIZATION_NAME); + metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HVX_UTILIZATION].metric_name_len = strlen(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HVX_UTILIZATION].metric_name); + snprintf(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HVX_UTILIZATION].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", DSP_NPU_METRIC_HVX_UTILIZATION_DESCRIPTION); + metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HVX_UTILIZATION].metric_description_len = strlen(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HVX_UTILIZATION].metric_description); + snprintf(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HVX_UTILIZATION].metric_unit, MAX_METRIC_UNIT_LEN, "%s", DSP_NPU_METRIC_HVX_UTILIZATION_UNIT); + metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HVX_UTILIZATION].metric_unit_len = strlen(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HVX_UTILIZATION].metric_unit); + + // HMX Utilization + metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HMX_UTILIZATION].metric_id = DSP_NPU_METRIC_HMX_UTILIZATION_ID; + snprintf(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HMX_UTILIZATION].metric_name, METRIC_NAME_MAX_LEN, "%s", DSP_NPU_METRIC_HMX_UTILIZATION_NAME); + metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HMX_UTILIZATION].metric_name_len = strlen(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HMX_UTILIZATION].metric_name); + snprintf(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HMX_UTILIZATION].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", DSP_NPU_METRIC_HMX_UTILIZATION_DESCRIPTION); + metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HMX_UTILIZATION].metric_description_len = strlen(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HMX_UTILIZATION].metric_description); + snprintf(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HMX_UTILIZATION].metric_unit, MAX_METRIC_UNIT_LEN, "%s", DSP_NPU_METRIC_HMX_UTILIZATION_UNIT); + metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HMX_UTILIZATION].metric_unit_len = strlen(metrics_data[DSP_NPU_CAPABILITY_0_METRIC_INDEX_HMX_UTILIZATION].metric_unit); + +} \ No newline at end of file diff --git a/qcperf/backends/qcom-dsp/CMakeLists.txt b/qcperf/backends/qcom-dsp/CMakeLists.txt new file mode 100644 index 0000000..d8f0860 --- /dev/null +++ b/qcperf/backends/qcom-dsp/CMakeLists.txt @@ -0,0 +1,22 @@ +add_library(QcPerfQcomDsp STATIC + src/qcom_dsp.c + src/dspquery_stub.c + +) + +add_library(cdsprpc SHARED + src/cdsprpc_stub.c + +) + +target_include_directories(QcPerfQcomDsp PUBLIC + inc +) + +target_include_directories(cdsprpc PUBLIC + inc +) + +target_link_libraries(QcPerfQcomDsp PUBLIC + cdsprpc +) \ No newline at end of file diff --git a/qcperf/backends/qcom-dsp/inc/AEEStdDef.h b/qcperf/backends/qcom-dsp/inc/AEEStdDef.h new file mode 100644 index 0000000..971c2fd --- /dev/null +++ b/qcperf/backends/qcom-dsp/inc/AEEStdDef.h @@ -0,0 +1,738 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef AEESTDDEF_H +#define AEESTDDEF_H + +#if defined(COMDEF_H) /* guards against a known re-definer */ +#define _BOOLEAN_DEFINED +#define _UINT32_DEFINED +#define _UINT16_DEFINED +#define _UINT8_DEFINED +#define _INT32_DEFINED +#define _INT16_DEFINED +#define _INT8_DEFINED +#define _UINT64_DEFINED +#define _INT64_DEFINED +#define _BYTE_DEFINED +#endif /* #if !defined(COMDEF_H) */ + +/* ----------------------------------------------------------------------- +** Standard Types +** ----------------------------------------------------------------------- */ + +/* The following definitions are the same accross platforms. This first +** group are the sanctioned types. +*/ +#include +#include + +#ifndef _BOOLEAN_DEFINED +typedef uint8_t boolean; /* Boolean value type. */ +#define _BOOLEAN_DEFINED +#endif + +#ifndef _UINT32_DEFINED +typedef uint32_t uint32; /* Unsigned 32 bit value */ +#define _UINT32_DEFINED +#endif + +#ifndef _UINT16_DEFINED +typedef uint16_t uint16; /* Unsigned 16 bit value */ +#define _UINT16_DEFINED +#endif + +#ifndef _UINT8_DEFINED +typedef uint8_t uint8; /* Unsigned 8 bit value */ +#define _UINT8_DEFINED +#endif + +#ifndef _INT32_DEFINED +typedef int32_t int32; /* Signed 32 bit value */ +#define _INT32_DEFINED +#endif + +#ifndef _INT16_DEFINED +typedef int16_t int16; /* Signed 16 bit value */ +#define _INT16_DEFINED +#endif + +#ifndef _INT8_DEFINED +typedef int8_t int8; /* Signed 8 bit value */ +#define _INT8_DEFINED +#endif + +#ifndef _UINT64_DEFINED +typedef uint64_t uint64; /* Unsigned 64 bit value */ +#define _UINT64_DEFINED +#endif + +#ifndef _INT64_DEFINED +typedef int64_t int64; /* Signed 64 bit value */ +#define _INT64_DEFINED +#endif + +#ifndef _BYTE_DEFINED +typedef uint8_t byte; /* byte type */ +#define _BYTE_DEFINED +#endif + + +#ifndef _AEEUID_DEFINED +typedef uint32 AEEUID; +#define _AEEUID_DEFINED +#endif + +#ifndef _AEEIID_DEFINED +typedef uint32 AEEIID; +#define _AEEIID_DEFINED +#endif + +#ifndef _AEECLSID_DEFINED +typedef uint32 AEECLSID; +#define _AEECLSID_DEFINED +#endif + +#ifndef _AEEPRIVID_DEFINED +typedef uint32 AEEPRIVID; +#define _AEEPRIVID_DEFINED +#endif + +#ifndef _AECHAR_DEFINED +typedef uint16 AECHAR; +#define _AECHAR_DEFINED +#endif + +#ifndef _AEERESULT_DEFINED +typedef int AEEResult; +#define _AEERESULT_DEFINED +#endif + +/* ----------------------------------------------------------------------- +** Function Calling Conventions +** ----------------------------------------------------------------------- */ + +#ifndef CDECL +#ifdef _MSC_VER +#define CDECL __cdecl +#else +#define CDECL +#endif /* _MSC_VER */ +#endif /* CDECL */ + +/* ----------------------------------------------------------------------- +** Constants +** ----------------------------------------------------------------------- */ + +#ifndef TRUE +#define TRUE 1 /* Boolean true value. */ +#endif + +#ifndef FALSE +#define FALSE 0 /* Boolean false value. */ +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef MIN_INT8 +#define MIN_INT8 -128 +#endif +#ifndef MIN_INT16 +#define MIN_INT16 -32768 +#endif +#ifndef MIN_INT32 +#define MIN_INT32 (~0x7fffffff) /* -2147483648 is unsigned */ +#endif +#ifndef MIN_INT64 +#define MIN_INT64 (~0x7fffffffffffffffLL) /* -9223372036854775808 is unsigned */ +#endif + +#ifndef MAX_INT8 +#define MAX_INT8 127 +#endif +#ifndef MAX_INT16 +#define MAX_INT16 32767 +#endif +#ifndef MAX_INT32 +#define MAX_INT32 2147483647 +#endif +#ifndef MAX_INT64 +#define MAX_INT64 9223372036854775807LL +#endif + +#ifndef MAX_UINT8 +#define MAX_UINT8 255 +#endif +#ifndef MAX_UINT16 +#define MAX_UINT16 65535 +#endif +#ifndef MAX_UINT32 +#define MAX_UINT32 4294967295u +#endif +#ifndef MAX_UINT64 +#define MAX_UINT64 18446744073709551615uLL +#endif + +#ifndef MIN_AECHAR +#define MIN_AECHAR 0 +#endif +#ifndef MAX_AECHAR +#define MAX_AECHAR 65535 +#endif + + +/* ----------------------------------------------------------------------- +** Preprocessor helpers +** ----------------------------------------------------------------------- */ +#define __STR__(x) #x +#define __TOSTR__(x) __STR__(x) +#define __FILE_LINE__ __FILE__ ":" __TOSTR__(__LINE__) + +/* ----------------------------------------------------------------------- +** Types for code generated from IDL +** ----------------------------------------------------------------------- */ + +#ifndef __QIDL_WCHAR_T_DEFINED__ +#define __QIDL_WCHAR_T_DEFINED__ +typedef uint16 _wchar_t; +#endif + +/* __STRING_OBJECT__ will be deprecated in the future */ +#if !defined(__QIDL_STRING_OBJECT_DEFINED__) && !defined(__STRING_OBJECT__) +#define __QIDL_STRING_OBJECT_DEFINED__ +#define __STRING_OBJECT__ +typedef struct _cstring_s { + char* data; + int dataLen; + int dataLenReq; +} _cstring_t; + +typedef struct _wstring_s { + _wchar_t* data; + int dataLen; + int dataLenReq; +} _wstring_t; +#endif /* __QIDL_STRING_OBJECT_DEFINED__ */ + +/* +======================================================================= + DATA STRUCTURES DOCUMENTATION +======================================================================= + +boolean + +Description: + This type is used to express boolean values (TRUE or FALSE). + +Definition: + typedef unsigned char boolean + +======================================================================= + +uint32 + +Description: + This is a 32-bit unsigned integer. + +Definition: + typedef unsigned long int uint32 + +======================================================================= + +uint16 + +Description: + This is a 16-bit unsigned integer. + +Definition: + typedef unsigned short uint16 + +======================================================================= + +uint8 + +Description: + This is an 8-bit unsigned integer. + +Definition: + typedef unsigned char uint8 + +======================================================================= + +int32 + +Description: + This is a 32-bit signed integer. + +Definition: + typedef signed long int int32 + +======================================================================= + +int16 + +Description: + This is a 16-bit signed integer. + +Definition: + typedef signed short int16 + +======================================================================= + +int8 + +Description: + This is an 8-bit signed integer. + +Definition: + typedef signed char int8 + +======================================================================= + +uint64 + +Description: + This is a 64-bit unsigned integer. + +Definition: + typedef unsigned __int64 uint64 + +======================================================================= + +int64 + +Description: + This is a 64-bit signed integer. + +Definition: + typedef __int64 int64 + +======================================================================= + +byte + +Description: + This is a byte. + +Definition: + typedef unsigned char byte + +======================================================================= + +AEEUID + +Description: + This is a BREW unique ID. Used to express unique types, interfaces, classes + groups and privileges. The BREW ClassID Generator generates + unique IDs that can be used anywhere you need a new AEEIID, AEECLSID, + or AEEPRIVID. + +Definition: + typedef uint32 AEEUID + +======================================================================= + +AEEIID + +Description: + This is an interface ID type, used to denote a BREW interface. It is a special case + of AEEUID. + +Definition: + typedef uint32 AEEIID + +======================================================================= + +AEECLSID + +Description: + This is a classe ID type, used to denote a BREW class. It is a special case + of AEEUID. + +Definition: + typedef uint32 AEECLSID + +======================================================================= + +AEEPRIVID + +Description: + This is a privilege ID type, used to express a privilege. It is a special case + of AEEUID. + +Definition: + typedef uint32 AEEPRIVID + +======================================================================= + +AECHAR + +Description: + This is a 16-bit character type. + +Definition: + typedef uint16 AECHAR + +======================================================================= + +AEEResult + +Description: + This is the standard result type. + +Definition: + typedef int AEEResult + +======================================================================= + +_wchar_t + +Description: + This is a 16-bit character type corresponding to the IDL 'wchar' + type. + +Definition: + typedef uint16 _wchar_t + +======================================================================= + +_cstring_t + +Description: + This structure is used to represent an IDL string when used inside a + sequence or union. + +Definition: + typedef struct _cstring_s { + char* data; + int dataLen; + int dataLenReq; + } _cstring_t; + +Members: + data : A pointer to the NULL-terminated string. + dataLen : The size, in chars, of the buffer pointed to by 'data', + including the NULL terminator. This member is only used + when the structure is part of an rout or inrout + parameter, but must be supplied by the caller as an + input in these cases. + dataLenReq : The size that would have been required to store the + entire result string. This member is only used when the + structure is part of an rout or inrout parameter, when + it is an output value set by the callee. The length of + the returned string (including the NULL terminator) + after a call is the minimum of dataLen and dataLenReq. + +======================================================================= + +_wstring_t + +Description: + This structure is used to represent an IDL wstring when used inside a + sequence or union. + +Definition: + typedef struct _wstring_s { + _wchar_t* data; + int dataLen; + int dataLenReq; + } _wstring_t; + +Members: + data : A pointer to the NULL-terminated wide string. + dataLen : The size, in 16-bit characters, of the buffer pointed to + by 'data', including the NULL terminator. This member + is only used when the structure is part of an rout or + inrout parameter, but must be supplied by the caller as + an input in these cases. + dataLenReq : The number of 16-bit characters that would have been + required to store the entire result string. This member + is only used when the structure is part of an rout or + inrout parameter, when it is an output value set by the + callee. The length of the returned wstring (including + the NULL terminator) after a call is the minimum of + dataLen and dataLenReq. + +======================================================================= +CONSTANTS DOCUMENTATION +======================================================================= + +TRUE + +Description: + TRUE is the boolean "true." + +Definition: + + #define TRUE 1 + +======================================================================= + +FALSE + +Description: + FALSE is the boolean "false." + +Definition: + + #define FALSE 0 + +======================================================================= + +NULL + +Description: + NULL is the null value, usually used to test a pointer. + +Definition: + + #define NULL 0 + + +======================================================================= + +MIN_INT8 + +Description: + MIN_INT8 is the minimum signed 8-bit integer value. + +Definition: + + #define MIN_INT8 -128 + +======================================================================= + +MIN_INT16 + +Description: + MIN_INT16 is the minimum signed 16-bit integer value + +Definition: + + #define MIN_INT16 -32768 + + +======================================================================= + +MIN_INT32 + +Description: + MIN_INT32 is the minimum signed 32-bit integer value. + +Definition: + + #define MIN_INT32 (~0x7fffffff) + +Comments: + We use (~0x7fffffff), because -2147483648 is treated as unsigned by + compilers + +======================================================================= + +MIN_INT64 + +Description: + MIN_INT64 is the minimum signed 64-bit integer value. + +Definition: + + #define MIN_INT64 (~0x7fffffffffffffffll) + +Comments: + We use (~0x7fffffffffffffffll), because -9223372036854775808 is + treated as unsigned by compilers + +======================================================================= + +MAX_INT8 + +Description: + MAX_INT8 is the maximum signed 8-bit integer value + +Definition: + + #define MAX_INT8 127 + +======================================================================= + +MAX_INT16 + +Description: + MAX_INT16 is the maximum signed 16-bit integer value. + +Definition: + + #define MAX_INT16 32767 + +======================================================================= + +MAX_INT32 + +Description: + MAX_INT32 is the maximum signed 32-bit integer value. + +Definition: + + #define MAX_INT32 2147483647 + +======================================================================= + +MAX_INT64 + +Description: + MAX_INT64 is the maximum signed 64-bit integer value. + +Definition: + + #define MAX_INT64 9223372036854775807ll + +======================================================================= + +MAX_UINT8 + +Description: + MAX_UINT8 is the maximum unsigned 8-bit integer value. + +Definition: + + #define MAX_UINT8 255 + +======================================================================= + +MAX_UINT16 + +Description: + MAX_UINT16 is the maximum unsigned 16-bit integer value. + +Definition: + + #define MAX_UINT16 65535 + +======================================================================= + +MAX_UINT32 + +Description: + MAX_UINT32 is the maximum unsigned 32-bit integer value. + +Definition: + + #define MAX_UINT32 4294967295u + + +======================================================================= + +MAX_UINT64 + +Description: + MAX_UINT64 is the maximum unsigned 64-bit integer value. + +Definition: + + #define MAX_UINT64 18446744073709551615ull + +======================================================================= + +MIN_AECHAR + +Description: + MIN_AECHAR is the minimum AECHAR value. + +Definition: + + #define MIN_AECHAR 0 + +======================================================================= + +MAX_AECHAR + +Description: + MAX_AECHAR is the maximum AECHAR value. + +Definition: + + #define MAX_AECHAR 65535 + +======================================================================= +MACROS DOCUMENTATION +======================================================================= + +__STR__() + +Description: + The __STR__() makes a token into a string, used to string-ize things already + defined. + +Definition: + + #define __STR__(x) #x + +Parameters: + x: token to make into a string + +======================================================================= + +__TOSTR__() + +Description: + The __TOSTR__() makes a token's value into a string, used to string-ize things + already defined, used with __STR__. + +Definition: + + #define __TOSTR__(x) __STR__(x) + +Parameters: + x: token to evaluate and string-ize + +Evaluation Value: + the token's replacement as a string + +======================================================================= + +__FILE_LINE__ + +Description: + The compiler's __FILE__ (a string) and __LINE__ (an integer) are pasted + together as a single string with a ":" between. + +Definition: + + #define __FILE_LINE__ __FILE__ ":" __TOSTR__(__LINE__) + +Evaluation Value: + __FILE__":""__LINE__" + +======================================================================= +*/ + +#endif /* #ifndef AEESTDDEF_H */ + diff --git a/qcperf/backends/qcom-dsp/inc/AEEStdErr.h b/qcperf/backends/qcom-dsp/inc/AEEStdErr.h new file mode 100644 index 0000000..1e1192a --- /dev/null +++ b/qcperf/backends/qcom-dsp/inc/AEEStdErr.h @@ -0,0 +1,352 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef AEESTDERR_H +#define AEESTDERR_H + +// +// Basic Error Codes +// +// + +#define AEE_SUCCESS 0 ///< No error +#define AEE_EUNKNOWN -1 /// Unknown error (should not use this) +#define AEE_EOFFSET 0x00000000 +#define AEE_EFAILED (AEE_EOFFSET + 0x001) ///< General failure +#define AEE_ENOMEMORY (AEE_EOFFSET + 0x002) ///< Insufficient RAM +#define AEE_ECLASSNOTSUPPORT (AEE_EOFFSET + 0x003) ///< Specified class unsupported +#define AEE_EVERSIONNOTSUPPORT (AEE_EOFFSET + 0x004) ///< Version not supported +#define AEE_EALREADYLOADED (AEE_EOFFSET + 0x005) ///< Object already loaded +#define AEE_EUNABLETOLOAD (AEE_EOFFSET + 0x006) ///< Unable to load object/applet +#define AEE_EUNABLETOUNLOAD (AEE_EOFFSET + 0x007) ///< Unable to unload + ///< object/applet +#define AEE_EALARMPENDING (AEE_EOFFSET + 0x008) ///< Alarm is pending +#define AEE_EINVALIDTIME (AEE_EOFFSET + 0x009) ///< Invalid time +#define AEE_EBADCLASS (AEE_EOFFSET + 0x00A) ///< NULL class object +#define AEE_EBADMETRIC (AEE_EOFFSET + 0x00B) ///< Invalid metric specified +#define AEE_EEXPIRED (AEE_EOFFSET + 0x00C) ///< App/Component Expired +#define AEE_EBADSTATE (AEE_EOFFSET + 0x00D) ///< Invalid state +#define AEE_EBADPARM (AEE_EOFFSET + 0x00E) ///< Invalid parameter +#define AEE_ESCHEMENOTSUPPORTED (AEE_EOFFSET + 0x00F) ///< Invalid URL scheme +#define AEE_EBADITEM (AEE_EOFFSET + 0x010) ///< Invalid item +#define AEE_EINVALIDFORMAT (AEE_EOFFSET + 0x011) ///< Invalid format +#define AEE_EINCOMPLETEITEM (AEE_EOFFSET + 0x012) ///< Incomplete item +#define AEE_ENOPERSISTMEMORY (AEE_EOFFSET + 0x013) ///< Insufficient flash +#define AEE_EUNSUPPORTED (AEE_EOFFSET + 0x014) ///< API is not supported +#define AEE_EPRIVLEVEL (AEE_EOFFSET + 0x015) ///< Privileges are insufficient + ///< for this operation +#define AEE_ERESOURCENOTFOUND (AEE_EOFFSET + 0x016) ///< Unable to find specified + ///< resource +#define AEE_EREENTERED (AEE_EOFFSET + 0x017) ///< Non re-entrant API + ///< re-entered +#define AEE_EBADTASK (AEE_EOFFSET + 0x018) ///< API called in wrong task + ///< context +#define AEE_EALLOCATED (AEE_EOFFSET + 0x019) ///< App/Module left memory + ///< allocated when released. +#define AEE_EALREADY (AEE_EOFFSET + 0x01A) ///< Operation is already in + ///< progress +#define AEE_EADSAUTHBAD (AEE_EOFFSET + 0x01B) ///< ADS mutual authorization + ///< failed +#define AEE_ENEEDSERVICEPROG (AEE_EOFFSET + 0x01C) ///< Need service programming +#define AEE_EMEMPTR (AEE_EOFFSET + 0x01D) ///< bad memory pointer +#define AEE_EHEAP (AEE_EOFFSET + 0x01E) ///< heap corruption +#define AEE_EIDLE (AEE_EOFFSET + 0x01F) ///< Context (system, interface, + ///< etc.) is idle +#define AEE_EITEMBUSY (AEE_EOFFSET + 0x020) ///< Context (system, interface, + ///< etc.) is busy +#define AEE_EBADSID (AEE_EOFFSET + 0x021) ///< Invalid subscriber ID +#define AEE_ENOTYPE (AEE_EOFFSET + 0x022) ///< No type detected/found +#define AEE_ENEEDMORE (AEE_EOFFSET + 0x023) ///< Need more data/info +#define AEE_EADSCAPS (AEE_EOFFSET + 0x024) ///< ADS Capabilities do not + ///< match those required for + ///< phone +#define AEE_EBADSHUTDOWN (AEE_EOFFSET + 0x025) ///< App failed to close properly +#define AEE_EBUFFERTOOSMALL (AEE_EOFFSET + 0x026) ///< Destination buffer given is + ///< too small +#define AEE_ENOSUCH (AEE_EOFFSET + 0x027) ///< No such name, port, socket + ///< or service exists or is + ///< valid +#define AEE_EACKPENDING (AEE_EOFFSET + 0x028) ///< ACK pending on application +#define AEE_ENOTOWNER (AEE_EOFFSET + 0x029) ///< Not an owner authorized to + ///< perform the operation +#define AEE_EINVALIDITEM (AEE_EOFFSET + 0x02A) ///< Current item is invalid +#define AEE_ENOTALLOWED (AEE_EOFFSET + 0x02B) ///< Not allowed to perform the + ///< operation +#define AEE_EBADHANDLE (AEE_EOFFSET + 0x02C) ///< Invalid handle +#define AEE_EOUTOFHANDLES (AEE_EOFFSET + 0x02D) ///< Out of handles +#define AEE_EINTERRUPTED (AEE_EOFFSET + 0x02E) ///< Waitable call is interrupted +#define AEE_ENOMORE (AEE_EOFFSET + 0x02F) ///< No more items available -- + ///< reached end +#define AEE_ECPUEXCEPTION (AEE_EOFFSET + 0x030) ///< A CPU exception occurred +#define AEE_EREADONLY (AEE_EOFFSET + 0x031) ///< Cannot change read-only + ///< object or parameter + +#define AEE_ECONNRESET 104 ///< Connection reset by peer +#define AEE_EWOULDBLOCK 516 ///< Operation would block if not + ///< non-blocking; wait and try + ///< again + +//Error code for sigverify +#define AEE_EUNSIGNEDMOD 4096 /// 0x1000 test-sig not found, Unsigned shared object +#define AEE_EINVALIDHASH 8192 /// 0x2000 test-sig not found, Invalid hash object + +#define AEE_EINVALIDMSG (AEE_EOFFSET + 0x032) /// Invalid SMD message from APPS +#define AEE_EINVALIDTHREAD (AEE_EOFFSET + 0x033) /// Invalid thread +#define AEE_EINVALIDPROCESS (AEE_EOFFSET + 0x034) /// Invalid Process +#define AEE_EINVALIDFILENAME (AEE_EOFFSET + 0x035) /// Invalid filename +#define AEE_EINVALIDDIGESTSIZE (AEE_EOFFSET + 0x036) /// Invalid digest size +#define AEE_EINVALIDSEGS (AEE_EOFFSET + 0x037) /// Invalid segments +#define AEE_EINVALIDSIGNATURE (AEE_EOFFSET + 0x038) /// Invalid signature +#define AEE_EINVALIDDOMAIN (AEE_EOFFSET + 0x039) /// Invalid domain +#define AEE_EINVALIDFD (AEE_EOFFSET + 0x03A) /// Invalid file descriptor +#define AEE_EINVALIDDEVICE (AEE_EOFFSET + 0x03B) /// Invalid Device +#define AEE_EINVALIDMODE (AEE_EOFFSET + 0x03C) /// Invalid Mode +#define AEE_EINVALIDPROCNAME (AEE_EOFFSET + 0x03D) /// Invalid Process name +#define AEE_ENOSUCHMOD (AEE_EOFFSET + 0x03E) /// No such module +#define AEE_ENOSUCHINSTANCE (AEE_EOFFSET + 0x03F) /// No instance in the list lookup +#define AEE_ENOSUCHTHREAD (AEE_EOFFSET + 0x040) /// No such thread +#define AEE_ENOSUCHPROCESS (AEE_EOFFSET + 0x041) /// No such process +#define AEE_ENOSUCHSYMBOL (AEE_EOFFSET + 0x042) /// No such symbol +#define AEE_ENOSUCHDEVICE (AEE_EOFFSET + 0x043) /// No such device +#define AEE_ENOSUCHPROP (AEE_EOFFSET + 0x044) /// No such dal property +#define AEE_ENOSUCHFILE (AEE_EOFFSET + 0x045) /// No such file +#define AEE_ENOSUCHHANDLE (AEE_EOFFSET + 0x046) /// No such handle +#define AEE_ENOSUCHSTREAM (AEE_EOFFSET + 0x047) /// No such stream +#define AEE_ENOSUCHMAP (AEE_EOFFSET + 0x048) /// No such Map +#define AEE_ENOSUCHREGISTER (AEE_EOFFSET + 0x049) /// No such register +#define AEE_ENOSUCHCLIENT (AEE_EOFFSET + 0x04A) /// No such QDI client +#define AEE_EBADDOMAIN (AEE_EOFFSET + 0x04B) /// Bad domain (not initialized) +#define AEE_EBADOFFSET (AEE_EOFFSET + 0x04C) /// Bad buffer/page/heap offset +#define AEE_EBADSIZE (AEE_EOFFSET + 0x04D) /// Bad buffer/page/heap size +#define AEE_EBADPERMS (AEE_EOFFSET + 0x04E) /// Bad FILE/MAP/MEM permissions +#define AEE_EBADFD (AEE_EOFFSET + 0x04F) /// Bad file descriptor +#define AEE_EBADPID (AEE_EOFFSET + 0x050) /// Bad PID from HLOS +#define AEE_EBADTID (AEE_EOFFSET + 0x051) /// Bad TID +#define AEE_EBADELF (AEE_EOFFSET + 0x052) /// Bad elf file +#define AEE_EBADASID (AEE_EOFFSET + 0x053) /// Bad asid +#define AEE_EBADCONTEXT (AEE_EOFFSET + 0x054) /// Bad context +#define AEE_EBADMEMALIGN (AEE_EOFFSET + 0x055) /// Bad memory alignment +#define AEE_EIOCTL (AEE_EOFFSET + 0x056) /// ioctl error +#define AEE_EFOPEN (AEE_EOFFSET + 0x057) /// file open error +#define AEE_EFGETS (AEE_EOFFSET + 0x058) /// file get string error +#define AEE_EFFLUSH (AEE_EOFFSET + 0x059) /// file flush error +#define AEE_EFCLOSE (AEE_EOFFSET + 0x05A) /// file close error +#define AEE_EEOF (AEE_EOFFSET + 0x05B) /// File EOF reached +#define AEE_EFREAD (AEE_EOFFSET + 0x05C) /// file read failed +#define AEE_EFWRITE (AEE_EOFFSET + 0x05D) /// file write failed +#define AEE_EFGETPOS (AEE_EOFFSET + 0x05E) /// file get position failed +#define AEE_EFSETPOS (AEE_EOFFSET + 0x05F) /// file set position failed +#define AEE_EFTELL (AEE_EOFFSET + 0x060) /// file tell position failed +#define AEE_EFSEEK (AEE_EOFFSET + 0x061) /// file seek failed +#define AEE_EFLEN (AEE_EOFFSET + 0x062) /// file len failed +#define AEE_EGETENV (AEE_EOFFSET + 0x063) /// get enviroment failed +#define AEE_ESETENV (AEE_EOFFSET + 0x064) /// set enviroment failed +#define AEE_EMMAP (AEE_EOFFSET + 0x065) /// mmap failed +#define AEE_EIONMAP (AEE_EOFFSET + 0x066) /// ion map failed +#define AEE_EIONALLOC (AEE_EOFFSET + 0x067) /// ion alloc failed +#define AEE_ENORPCMEMORY (AEE_EOFFSET + 0x068) /// ION memory allocation failed +#define AEE_ENOROOTOFTRUST (AEE_EOFFSET + 0x069) /// No root of trust for sigverify +#define AEE_ENOTLOCKED (AEE_EOFFSET + 0x06A) /// Unlock failed, not locked before +#define AEE_ENOTINITIALIZED (AEE_EOFFSET + 0x06B) /// Not initialized +#define AEE_EUNSUPPORTEDAPI (AEE_EOFFSET + 0x06C) /// unsupported API +#define AEE_EUNPACK (AEE_EOFFSET + 0x06D) /// unpacking command failed +#define AEE_EPOLL (AEE_EOFFSET + 0x06E) /// error while polling for event +#define AEE_EEVENTREAD (AEE_EOFFSET + 0x06F) /// event read failed +#define AEE_EMAXBUFS (AEE_EOFFSET + 0x070) /// Maximum buffers +#define AEE_EINVARGS (AEE_EOFFSET + 0x071) /// Invalid Arguments + +#define AEE_ESMD_OFFSET (AEE_EOFFSET + 0x100) /// SMD errors offset +#define AEE_ESMDBADPACKET (AEE_EOFFSET + 0x101) /// SMD invalid packet size +#define AEE_ESMDALREADYOPEN (AEE_EOFFSET + 0x102) /// SMD port is already open +#define AEE_ESMDOPENFAILED (AEE_EOFFSET + 0x103) /// SMD port open failed + +#define AEE_EDAL_OFFSET (AEE_EOFFSET + 0x120) /// Dal error offset +#define AEE_EDALDEVATTACH (AEE_EOFFSET + 0x121) /// DAL attach error +#define AEE_EDALINTREGISTER (AEE_EOFFSET + 0x122) /// DAL interrupt register error +#define AEE_EDALINTUNREGISTER (AEE_EOFFSET + 0x123) /// Dal interrupt unregister error +#define AEE_EDALGETPROP (AEE_EOFFSET + 0x124) /// Dal get property +#define AEE_EDALGETVAL (AEE_EOFFSET + 0x125) /// Dal get property value + +#define AEE_EQURT_OFFSET (AEE_EOFFSET + 0x140) /// QURT error offset +#define AEE_EQURTREGIONCREATE (AEE_EOFFSET + 0x141) /// QURT region create failed +#define AEE_EQURTCACHECLEAN (AEE_EOFFSET + 0x142) /// QURT cache clean failed +#define AEE_EQURTREGIONGETATTR (AEE_EOFFSET + 0x143) /// QURT region get attribute failed +#define AEE_EQURTBADREGIONPERMS (AEE_EOFFSET + 0x144) /// QURT bad permissions for region +#define AEE_EQURTMEMPOOLADD (AEE_EOFFSET + 0x145) /// QURT Add to memory pool failed +#define AEE_EQURTREGISTERDEV (AEE_EOFFSET + 0x146) /// QURT register device failed +#define AEE_EQURTMEMPOOLCREATE (AEE_EOFFSET + 0x147) /// QURT create memory pool failed +#define AEE_EQURTGETVA (AEE_EOFFSET + 0x148) /// QURT get VA failed +#define AEE_EQURTREGIONDELETE (AEE_EOFFSET + 0x149) /// QURT region delete failed +#define AEE_EQURTMEMPOOLATTACH (AEE_EOFFSET + 0x14A) /// QURT memory pool attach failed +#define AEE_EQURTTHREADCREATE (AEE_EOFFSET + 0x14B) /// QURT thread create failed +#define AEE_EQURTCOPYTOUSER (AEE_EOFFSET + 0x14C) /// QURT copy to user memory failed +#define AEE_EQURTMEMMAPCREATE (AEE_EOFFSET + 0x14D) /// QURT map create failed +#define AEE_EQURTINVHANDLE (AEE_EOFFSET + 0x14E) /// QURT Invalid client handle +#define AEE_EQURTBADASID (AEE_EOFFSET + 0x14F) /// QURT Bad ASIC from QURT +#define AEE_EQURTOPENFAILED (AEE_EOFFSET + 0x150) /// QURT QDI open failed +#define AEE_EQURTCOPYFROMUSER (AEE_EOFFSET + 0x151) /// QURT Copy from user failed +#define AEE_EQURTLINELOCK (AEE_EOFFSET + 0x152) /// QURT Line lock failed +#define AEE_EQURTQDIDEFMETHOD (AEE_EOFFSET + 0x153) /// QURT QDI default method failed + +#define AEE_EMMPM_OFFSET (AEE_EOFFSET + 0x170) /// MMPM errors offset +#define AEE_EMMPMREQUEST (AEE_EOFFSET + 0x171) /// MMPM Power request to failed +#define AEE_EMMPMRELEASE (AEE_EOFFSET + 0x172) /// MMPM Release request failed +#define AEE_EMMPMSETPARAM (AEE_EOFFSET + 0x173) /// MMPM set param request failed +#define AEE_EMMPMREGISTER (AEE_EOFFSET + 0x174) /// MMPM Register request failed +#define AEE_EMMPMGETINFO (AEE_EOFFSET + 0x175) /// MMPM Get info failed + + +/* +#define AEE_SUCCESS 0 // no error +#define AEE_EFAILED 1 // general failure +#define AEE_ENOMEMORY 2 // insufficient RAM +#define AEE_ECLASSNOTSUPPORT 3 // specified class unsupported +#define AEE_EVERSIONNOTSUPPORT 4 // version not supported +#define AEE_EALREADYLOADED 5 // object already loaded +#define AEE_EUNABLETOLOAD 6 // unable to load object/applet +#define AEE_EUNABLETOUNLOAD 7 // unable to unload object/applet +#define AEE_EALARMPENDING 8 // alarm is pending +#define AEE_EINVALIDTIME 9 // invalid time +#define AEE_EBADCLASS 10 // NULL class object +#define AEE_EBADMETRIC 11 // invalid metric specified +#define AEE_EEXPIRED 12 // App/Component Expired +#define AEE_EBADSTATE 13 // invalid state +#define AEE_EBADPARM 14 // invalid parameter +#define AEE_ESCHEMENOTSUPPORTED 15 // invalid URL scheme +#define AEE_EBADITEM 16 // invalid item +#define AEE_EINVALIDFORMAT 17 // invalid format +#define AEE_EINCOMPLETEITEM 18 // incomplete item +#define AEE_ENOPERSISTMEMORY 19 // insufficient flash +#define AEE_EUNSUPPORTED 20 // API is not supported +#define AEE_EPRIVLEVEL 21 // privileges are insufficient for this operation +#define AEE_ERESOURCENOTFOUND 22 +#define AEE_EREENTERED 23 +#define AEE_EBADTASK 24 +#define AEE_EALLOCATED 25 // App/Module left memory allocated when released +#define AEE_EALREADY 26 // operation is already in progress +#define AEE_EADSAUTHBAD 27 // ADS mutual authorization failed +#define AEE_ENEEDSERVICEPROG 28 // need service programming +#define AEE_EMEMPTR 29 // bad memory pointer +#define AEE_EHEAP 30 // heap corruption +#define AEE_EIDLE 31 // context (system, interface, etc.) is idle +#define AEE_EITEMBUSY 32 // context (system, interface, etc.) is busy +#define AEE_EBADSID 33 // invalid subscriber ID +#define AEE_ENOTYPE 34 // no type detected/found +#define AEE_ENEEDMORE 35 // need more data/info +#define AEE_EADSCAPS 36 // ADS Capabilities do not match those required for phone +#define AEE_EBADSHUTDOWN 37 // App failed to close properly +#define AEE_EBUFFERTOOSMALL 38 // destination buffer given is too small +#define AEE_ENOSUCH 39 // no such name/port/socket/service exists or valid +#define AEE_EACKPENDING 40 // ACK pending on application +#define AEE_ENOTOWNER 41 // not an owner authorized to perform the operation +#define AEE_EINVALIDITEM 42 // current item is invalid +#define AEE_ENOTALLOWED 43 // not allowed to perform the operation +#define AEE_EBADHANDLE 44 // invalid handle +#define AEE_EOUTOFHANDLES 45 // out of handles +#define AEE_EINTERRUPTED 46 // waitable call is interrupted +#define AEE_ENOMORE 47 // no more items available -- reached end +#define AEE_ECPUEXCEPTION 48 // a CPU exception occurred +#define AEE_EREADONLY 49 // Cannot change read-only object or parameter +// a moratorium on adding to AEEStdErr.h is in effect, 50 and later are +// already spoken for + +#define AEE_EWOULDBLOCK 516 // Operation would block if not non-blocking; wait and try again +*/ +/* +============================================================================ + ERRORS DOCUMENTATION +============================================================================== +Basic AEE Error Codes + +This section lists the set of basic errors returned, the codes associated +with the errors, and descriptions of the errors. + + +Basic error codes + +Definition: + +Error Code Description + +AEE_SUCCESS 0 operation Successful +AEE_EFAILED 1 general failure +AEE_ENOMEMORY 2 insufficient RAM +AEE_ECLASSNOTSUPPORT 3 specified class unsupported +AEE_EVERSIONNOTSUPPORT 4 version not supported +AEE_EALREADYLOADED 5 object already loaded +AEE_EUNABLETOLOAD 6 unable to load object/applet +AEE_EUNABLETOUNLOAD 7 unable to unload object/applet +AEE_EALARMPENDING 8 alarm is pending +AEE_EINVALIDTIME 9 invalid time +AEE_EBADCLASS 10 NULL class object +AEE_EBADMETRIC 11 invalid metric specified +AEE_EEXPIRED 12 Application/Component Expired +AEE_EBADSTATE 13 invalid state +AEE_EBADPARM 14 invalid parameter +AEE_ESCHEMENOTSUPPORTED 15 invalid URL scheme +AEE_EBADITEM 16 invalid item +AEE_EINVALIDFORMAT 17 invalid format +AEE_EINCOMPLETEITEM 18 incomplete item +AEE_ENOPERSISTMEMORY 19 insufficient flash +AEE_EUNSUPPORTED 20 API is not supported +AEE_EPRIVLEVEL 21 application privileges are insufficient for this operation +AEE_ERESOURCENOTFOUND 22 unable to find specified resource +AEE_EREENTERED 23 non re-entrant API re-entered +AEE_EBADTASK 24 API called in wrong task context +AEE_EALLOCATED 25 Application/Module left memory allocated when released +AEE_EALREADY 26 operation is already in progress +AEE_EADSAUTHBAD 27 ADS mutual authorization failed +AEE_ENEEDSERVICEPROG 28 need service programming +AEE_EMEMPTR 29 bad memory pointer +AEE_EHEAP 30 heap corruption +AEE_EIDLE 31 context (system, interface, etc.) is idle +AEE_EITEMBUSY 32 context (system, interface, etc.) is busy +AEE_EBADSID 33 invalid subscriber ID +AEE_ENOTYPE 34 no type detected/found +AEE_ENEEDMORE 35 need more data/info +AEE_EADSCAPS 36 capabilities do not match those required +AEE_EBADSHUTDOWN 37 application failed to close properly +AEE_EBUFFERTOOSMALL 38 destination buffer given is too small +AEE_ENOSUCH 39 no such name/port/socket/service exists or valid +AEE_EACKPENDING 40 ACK pending on application +AEE_ENOTOWNER 41 not an owner authorized to perform the operation +AEE_EINVALIDITEM 42 current item is invalid +AEE_ENOTALLOWED 43 not allowed to perform the operation +AEE_EBADHANDLE 44 invalid handle +AEE_EOUTOFHANDLES 45 out of handles +AEE_EINTERRUPTED 46 waitable call is interrupted +AEE_ENOMORE 47 no more items available -- reached end +AEE_ECPUEXCEPTION 48 a CPU exception occurred +AEE_EREADONLY 49 cannot change read-only object or parameter +AEE_EWOULDBLOCK 516 operation would block if not non-blocking; wait and try again + +================================================================== +*/ +#endif /* #ifndef AEESTDERR_H */ + diff --git a/qcperf/backends/qcom-dsp/inc/dspquery_stub.h b/qcperf/backends/qcom-dsp/inc/dspquery_stub.h new file mode 100644 index 0000000..a57f63e --- /dev/null +++ b/qcperf/backends/qcom-dsp/inc/dspquery_stub.h @@ -0,0 +1,105 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _SYSMONQUERY_H +#define _SYSMONQUERY_H + +#include "remote.h" +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifdef __cplusplus +extern "C" { +#endif +/** + * Opens the handle in the specified domain. If this is the first + * handle, this creates the session. Typically this means opening + * the device, aka open("/dev/adsprpc-smd"), then calling ioctl + * device APIs to create a PD on the DSP to execute our code in, + * then asking that PD to dlopen the .so and dlsym the skel function. + * + * @param uri, _URI"&_dom=aDSP" + * _URI is a QAIC generated uri, or + * "file:///?_skel_handle_invoke&_modver=1.0" + * If the _dom parameter is not present, _dom=DEFAULT is assumed + * but not forwarded. + * Reserved uri keys: + * [0]: first unamed argument is the skel invoke function + * _dom: execution domain name, _dom=mDSP/aDSP/DEFAULT + * _modver: module version, _modver=1.0 + * _*: any other key name starting with an _ is reserved + * Unknown uri keys/values are forwarded as is. + * @param h, resulting handle + * @retval, 0 on success + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(sysmonquery_open)(const char* uri, remote_handle64* h) __QAIC_HEADER_ATTRIBUTE; +/** + * Closes a handle. If this is the last handle to close, the session + * is closed as well, releasing all the allocated resources. + + * @param h, the handle to close + * @retval, 0 on success, should always succeed + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(sysmonquery_close)(remote_handle64 h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(sysmonquery_init)(remote_handle64 _h, unsigned int npu_flag) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(sysmonquery_get_profdata)(remote_handle64 _h, unsigned char* profdata_ptr, int profdata_ptrLen, int* no_metrics, unsigned int npu_flag) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(sysmonquery_deinit)(remote_handle64 _h, unsigned int npu_flag) __QAIC_HEADER_ATTRIBUTE; +#ifndef sysmonquery_URI +#define sysmonquery_URI "file:///libsysmonquery_skel.so?sysmonquery_skel_handle_invoke&_modver=1.0" +#endif /*sysmonquery_URI*/ +#ifdef __cplusplus +} +#endif +extern int (*local_remote_handle64_open)(const char*, remote_handle64*); +extern int (*local_remote_handle64_invoke)(remote_handle64, uint32_t, remote_arg*); +extern int (*local_remote_handle64_close)(remote_handle64); +extern void* (*local_rpcmem_alloc)(int, uint32_t, int); +extern void (*local_rpcmem_free)(void*); + +#endif //_SYSMONQUERY_H diff --git a/qcperf/backends/qcom-dsp/inc/qcom_dsp.h b/qcperf/backends/qcom-dsp/inc/qcom_dsp.h new file mode 100644 index 0000000..0367bd1 --- /dev/null +++ b/qcperf/backends/qcom-dsp/inc/qcom_dsp.h @@ -0,0 +1,87 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file dsp_lib.h + * @brief DSP library public API — types, return codes, and function declarations + * @author Himanshu Keshri (hkeshri@qti.qualcomm.com) + */ + +#ifndef QCOM_DSP_H_ +#define QCOM_DSP_H_ + +#include "dspquery_stub.h" +#include "remote.h" +#include "rpcmem.h" + +#include +#include +#include +#include + +struct sysmon_query_prof_data { + float q6_utilization; // avg effective q6 clock with respect to max q6 clock. (%) + unsigned int q6_clock; // avg q6 clock. (KHz) + float reserved0; // Reserved field + float hvx_utilization; // avg HVX utilization with respect to max q6 clock. (%) + float hmx_utilization; // avg HMX utilization with respect to max q6 clock. (%) + float reserved1; // Reserved field + float reserved2; // Reserved field + float reserved3; // Reserved field + float reserved4; // Reserved field + float reserved5; // Reserved field + float reserved6; // Reserved field + float reserved7; // Reserved field + float reserved8; // Reserved field + float reserved9; // Reserved field +}; + +enum DspDomainId { + DSP_ADSP = ADSP_DOMAIN_ID, + DSP_NPU0 = CDSP_DOMAIN_ID, + DSP_MAX = CDSP_DOMAIN_ID, +}; + +enum DspReturnCode { + RETURN_CODE_DSP_LIB_SUCCESS = 0, + RETURN_CODE_DSP_LIB_FAIL = 1, + RETURN_CODE_DSP_SYSMON_QUERY_OPEN_FAILED, + RETURN_CODE_DSP_SYSMON_QUERY_INIT_FAILED, + RETURN_CODE_DSP_SYSMON_QUERY_RPC_MEM_ALLOC_FAILED, + RETURN_CODE_DSP_SYSMON_QUERY_GET_PROF_DATA_FAILED, + RETURN_CODE_DSP_SYSMON_QUERY_DEINIT_FAILED, +}; + +enum DspReturnCode qcom_dsp_init(enum DspDomainId); + +struct sysmon_query_prof_data* qcom_dsp_get_prof_data(enum DspDomainId domain_id, int* no_metrics); + +enum DspReturnCode qcom_dsp_deinit(enum DspDomainId); + +#endif /* QCOM_DSP_H_ */ diff --git a/qcperf/backends/qcom-dsp/inc/remote.h b/qcperf/backends/qcom-dsp/inc/remote.h new file mode 100644 index 0000000..78b23c5 --- /dev/null +++ b/qcperf/backends/qcom-dsp/inc/remote.h @@ -0,0 +1,282 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef REMOTE_H +#define REMOTE_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint32_t remote_handle; +typedef uint64_t remote_handle64; //! used by multi domain modules + //! 64 bit handles are translated to 32 bit values + //! by the transport layer + +typedef struct { + void *pv; + size_t nLen; +} remote_buf; + +typedef struct { + int32_t fd; + uint32_t offset; +} remote_dma_handle; + +typedef union { + remote_buf buf; + remote_handle h; + remote_handle64 h64; //! used by multi domain modules + remote_dma_handle dma; +} remote_arg; + +/*Retrives method attribute from the scalars parameter*/ +#define REMOTE_SCALARS_METHOD_ATTR(dwScalars) (((dwScalars) >> 29) & 0x7) + +/*Retrives method index from the scalars parameter*/ +#define REMOTE_SCALARS_METHOD(dwScalars) (((dwScalars) >> 24) & 0x1f) + +/*Retrives number of input buffers from the scalars parameter*/ +#define REMOTE_SCALARS_INBUFS(dwScalars) (((dwScalars) >> 16) & 0x0ff) + +/*Retrives number of output buffers from the scalars parameter*/ +#define REMOTE_SCALARS_OUTBUFS(dwScalars) (((dwScalars) >> 8) & 0x0ff) + +/*Retrives number of input handles from the scalars parameter*/ +#define REMOTE_SCALARS_INHANDLES(dwScalars) (((dwScalars) >> 4) & 0x0f) + +/*Retrives number of output handles from the scalars parameter*/ +#define REMOTE_SCALARS_OUTHANDLES(dwScalars) ((dwScalars) & 0x0f) + +#define REMOTE_SCALARS_MAKEX(nAttr,nMethod,nIn,nOut,noIn,noOut) \ + ((((uint32_t) (nAttr) & 0x7) << 29) | \ + (((uint32_t) (nMethod) & 0x1f) << 24) | \ + (((uint32_t) (nIn) & 0xff) << 16) | \ + (((uint32_t) (nOut) & 0xff) << 8) | \ + (((uint32_t) (noIn) & 0x0f) << 4) | \ + ((uint32_t) (noOut) & 0x0f)) + +#define REMOTE_SCALARS_MAKE(nMethod,nIn,nOut) REMOTE_SCALARS_MAKEX(0,nMethod,nIn,nOut,0,0) + +#define REMOTE_SCALARS_LENGTH(sc) (REMOTE_SCALARS_INBUFS(sc) +\ + REMOTE_SCALARS_OUTBUFS(sc) +\ + REMOTE_SCALARS_INHANDLES(sc) +\ + REMOTE_SCALARS_OUTHANDLES(sc)) + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_REMOTE_EXPORT +#ifdef _WIN32 +#define __QAIC_REMOTE_EXPORT __declspec(dllexport) +#else //_WIN32 +#define __QAIC_REMOTE_EXPORT +#endif //_WIN32 +#endif //__QAIC_REMOTE_EXPORT + +#ifndef __QAIC_REMOTE_ATTRIBUTE +#define __QAIC_REMOTE_ATTRIBUTE +#endif + +#define NUM_DOMAINS 4 +#define NUM_SESSIONS 2 +#define DOMAIN_ID_MASK 3 + +#ifndef DEFAULT_DOMAIN_ID +#define DEFAULT_DOMAIN_ID 0 +#endif + +#define ADSP_DOMAIN_ID 0 +#define MDSP_DOMAIN_ID 1 +#define SDSP_DOMAIN_ID 2 +#define CDSP_DOMAIN_ID 3 +#define CDSP1_DOMAIN_ID 4 +#define GPDSP0_DOMAIN_ID 5 +#define GPDSP1_DOMAIN_ID 6 + + +#define ADSP_DOMAIN "&_dom=adsp" +#define MDSP_DOMAIN "&_dom=mdsp" +#define SDSP_DOMAIN "&_dom=sdsp" +#define CDSP_DOMAIN "&_dom=cdsp" +#define CDSP1_DOMAIN "&_dom=cdsp1" +#define GPDSP0_DOMAIN "&_dom=gpdsp0" +#define GPDSP1_DOMAIN "&_dom=gpdsp1" + +#define SESSION_1 "&_session=1" +#define SESSION_2 "&_session=2" +#define SESSION_3 "&_session=3" +#define SESSION_4 "&_session=4" +#define SESSION_5 "&_session=5" + +/* All other values are reserved */ + +/* opens a remote_handle "name" + * returns 0 on success + */ +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_handle_open)(const char* name, remote_handle *ph) __QAIC_REMOTE_ATTRIBUTE; +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_handle64_open)(const char* name, remote_handle64 *ph) __QAIC_REMOTE_ATTRIBUTE; + +/* invokes the remote handle + * see retrive macro's on dwScalars format + * pra, contains the arguments in the following order, inbufs, outbufs, inhandles, outhandles. + * implementors should ignore and pass values asis that the transport doesn't understand. + */ +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_handle_invoke)(remote_handle h, uint32_t dwScalars, remote_arg *pra) __QAIC_REMOTE_ATTRIBUTE; +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_handle64_invoke)(remote_handle64 h, uint32_t dwScalars, remote_arg *pra) __QAIC_REMOTE_ATTRIBUTE; + +/* closes the remote handle + */ +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_handle_close)(remote_handle h) __QAIC_REMOTE_ATTRIBUTE; +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_handle64_close)(remote_handle64 h) __QAIC_REMOTE_ATTRIBUTE; + +/* remote handle control interface + */ +/* request ID for fastrpc latency control */ +#define DSPRPC_CONTROL_LATENCY (1) +struct remote_rpc_control_latency { + uint32_t enable; // enable auto control of rpc latency + uint32_t latency; // latency: reserved +}; + +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_handle_control)(uint32_t req, void* data, uint32_t datalen) __QAIC_REMOTE_ATTRIBUTE; +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_handle64_control)(remote_handle64 h, uint32_t req, void* data, uint32_t datalen) __QAIC_REMOTE_ATTRIBUTE; + +/* map memory to the remote domain + * + * @param fd, fd assosciated with this memory + * @param flags, flags to be used for the mapping + * @param vaddrin, input address + * @param size, size of buffer + * @param vaddrout, output address + * @retval, 0 on success + */ +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_mmap)(int fd, uint32_t flags, uint32_t vaddrin, int size, uint32_t* vaddrout) __QAIC_REMOTE_ATTRIBUTE; + +/* unmap memory from the remote domain + * + * @param vaddrout, remote address mapped + * @param size, size to unmap. Unmapping a range partially may not be supported. + * @retval, 0 on success, may fail if memory is still mapped + */ +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_munmap)(uint32_t vaddrout, int size) __QAIC_REMOTE_ATTRIBUTE; + +/* + * Attribute to map a buffer as dma non-coherent + * Driver perform cache maintenance. + */ +#define FASTRPC_ATTR_NON_COHERENT (2) + +/* + * Attribute to map a buffer as dma coherent + * Driver skips cache maintenenace + * It will be ignored if a device is marked as dma-coherent in device tree. + */ +#define FASTRPC_ATTR_COHERENT (4) + +/* Attribute to keep the buffer persistant + * until unmap is called explicitly + */ +#define FASTRPC_ATTR_KEEP_MAP (8) + +/* Register a file descriptor for a buffer. This is only valid on + * android with ION allocated memory. Users of fastrpc should register + * a buffer allocated with ION to enable sharing that buffer to the + * dsp via the smmu. Some versions of libadsprpc.so lack this + * function, so users should set this symbol as weak. + * + * #pragma weak remote_register_buf + * + * @param buf, virtual address of the buffer + * @param size, size to of the buffer + * @fd, the file descriptor, callers can use -1 to deregister. + * $attr, map buffer as coherent or non-coherent + */ +__QAIC_REMOTE_EXPORT void __QAIC_REMOTE(remote_register_buf)(void* buf, int size, int fd) __QAIC_REMOTE_ATTRIBUTE; +__QAIC_REMOTE_EXPORT void __QAIC_REMOTE(remote_register_buf_attr)(void* buf, int size, int fd, int attr) __QAIC_REMOTE_ATTRIBUTE; + +/* + * This is the default mode for the driver. While the driver is in parallel + * mode it will try to invalidate output buffers after it transfers control + * to the dsp. This allows the invalidate operations to overlap with the + * dsp processing the call. This mode should be used when output buffers + * are only read on the application processor and only written on the aDSP. + */ +#define REMOTE_MODE_PARALLEL 0 + +/* + * When operating in SERIAL mode the driver will invalidate output buffers + * before calling into the dsp. This mode should be used when output + * buffers have been written to somewhere besides the aDSP. + */ +#define REMOTE_MODE_SERIAL 1 + +/* + * Internal transport prefix + */ +#define ITRANSPORT_PREFIX "'\":;./\\" + +/* + * Set the mode of operation. + * + * Some versions of libadsprpc.so lack this function, so users should set + * this symbol as weak. + * + * #pragma weak remote_set_mode + * + * @param mode, the mode + * @retval, 0 on success + */ +__QAIC_REMOTE_EXPORT int __QAIC_REMOTE(remote_set_mode)(uint32_t mode) __QAIC_REMOTE_ATTRIBUTE; + +/* Register a file descriptor. This can be used when users do not have + * a mapping to pass to the RPC layer. The generated address is a mapping + * with PROT_NONE, any access to this memory will fail, so it should only + * be used as an ID to identify this file descriptor to the RPC layer. + * + * To deregister use remote_register_buf(addr, size, -1). + * + * #pragma weak remote_register_fd + * + * @param fd, the file descriptor. + * @param size, size to of the buffer + * @retval, (void*)-1 on failure, address on success. + * + */ +__QAIC_REMOTE_EXPORT void *__QAIC_REMOTE(remote_register_fd)(int fd, int size) __QAIC_REMOTE_ATTRIBUTE; + +#ifdef __cplusplus +} +#endif + +#endif // REMOTE_H diff --git a/qcperf/backends/qcom-dsp/inc/rpcmem.h b/qcperf/backends/qcom-dsp/inc/rpcmem.h new file mode 100644 index 0000000..2279b64 --- /dev/null +++ b/qcperf/backends/qcom-dsp/inc/rpcmem.h @@ -0,0 +1,157 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef RPCMEM_H +#define RPCMEM_H + +#include "AEEStdDef.h" + +/** + * RPCMEM_DEFAULT_HEAP + * Dynamicaly select the heap to use. This should be ok for most usecases. + */ +#define RPCMEM_DEFAULT_HEAP -1 + + +/** + * RPCMEM_DEFAULT_FLAGS should allocate memory with the same properties + * as the ION_FLAG_CACHED flag + */ +#ifdef ION_FLAG_CACHED +#define RPCMEM_DEFAULT_FLAGS ION_FLAG_CACHED +#else +#define RPCMEM_DEFAULT_FLAGS 1 +#endif + +/** + * RPCMEM HEAP IDs + * SYSTEM HEAP: + * - non-contiguous physical memory + * - for sub-systems with SMMU + * - recommended for HVX/CDSPs + * CONTIG HEAP: + * - Contiguous physical memory + * - limited memory + * - for sub-systems without SMMU (ex. sDSP and mDSP) + */ +#define RPCMEM_HEAP_ID_SYSTEM (25) +#define RPCMEM_HEAP_ID_CONTIG (22) +#define RPCMEM_HEAP_ID_SECURE (9) +#define RPCMEM_HEAP_ID_SYSTEM_CONTIG (21) + +/** + * RPCMEM_FLAG_UNCACHED + * ION_FLAG_CACHED should be defined as 1 + */ +#define RPCMEM_FLAG_UNCACHED 0 +#define RPCMEM_FLAG_CACHED RPCMEM_DEFAULT_FLAGS + +/** + * examples: + * + * heap 22, uncached, 1kb + * rpcmem_alloc(22, 0, 1024); + * rpcmem_alloc(22, RPCMEM_FLAG_UNCACHED, 1024); + * + * heap 21, cached, 2kb + * rpcmem_alloc(21, RPCMEM_FLAG_CACHED, 2048); + * #include + * rpcmem_alloc(21, ION_FLAG_CACHED, 2048); + * + * just give me the defaults, 2kb + * rpcmem_alloc(RPCMEM_DEFAULT_HEAP, RPCMEM_DEFAULT_FLAGS, 2048); + * rpcmem_alloc_def(2048); + * + * give me the default flags, but from heap 18, 4kb + * rpcmem_alloc(18, RPCMEM_DEFAULT_FLAGS, 4096); + * + */ +#define ION_SECURE_FLAGS ((1 << 31) | (1 << 19)) +#ifdef __cplusplus +extern "C" { +#endif + +/** + * call once to initialize the library + * Note: should not call this if rpcmem is linked from libadsprpc.so + * /libcdsprpc.so/libmdsprpc.so/libsdsprpc.so + */ +extern void rpcmem_init(void); + +/** + * call once for cleanup + * Note: should not call this if rpcmem is linked from libadsprpc.so + * /libcdsprpc.so/libmdsprpc.so/libsdsprpc.so + */ +extern void rpcmem_deinit(void); + +/** + * Allocate via ION a buffer of size + * @heapid, the heap id to use + * @flags, ion flags to use to when allocating + * @size, the buffer size to allocate + * @retval, 0 on failure, pointer to buffer on success + * + * For example: + * buf = rpcmem_alloc(RPCMEM_DEFAULT_HEAP, RPCMEM_DEFAULT_FLAGS, size); + */ + +extern void* rpcmem_alloc(int heapid, uint32 flags, int size); + +/** + * allocate with default settings + */ + #if !defined(WINNT) && !defined (_WIN32_WINNT) +__attribute__((unused)) +#endif +static __inline void* rpcmem_alloc_def(int size) { + return rpcmem_alloc(RPCMEM_DEFAULT_HEAP, RPCMEM_DEFAULT_FLAGS, size); +} + +/** + * free buffer, ignores invalid buffers + */ +extern void rpcmem_free(void* po); + +/** + * returns associated fd + */ +extern int rpcmem_to_fd(void* po); + +#ifdef __cplusplus +} +#endif + +#define RPCMEM_HEAP_DEFAULT 0x80000000 +#define RPCMEM_HEAP_NOREG 0x40000000 +#define RPCMEM_HEAP_UNCACHED 0x20000000 +#define RPCMEM_HEAP_NOVA 0x10000000 +#define RPCMEM_HEAP_NONCOHERENT 0x08000000 + +#endif //RPCMEM_H diff --git a/qcperf/backends/qcom-dsp/src/cdsprpc_stub.c b/qcperf/backends/qcom-dsp/src/cdsprpc_stub.c new file mode 100644 index 0000000..6a35859 --- /dev/null +++ b/qcperf/backends/qcom-dsp/src/cdsprpc_stub.c @@ -0,0 +1,70 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file cdsprpc_stub.c + * @brief Build-time stub for libcdsprpc.so — satisfies the linker; real library loaded at runtime + * @author Himanshu Keshri (hkeshri@qti.qualcomm.com) + */ +#include +#include "remote.h" +#include "rpcmem.h" + +/* remote_handle64 API ---------------------------------------------------- */ + +int remote_handle64_open(const char *name, remote_handle64 *ph) +{ + (void)name; (void)ph; + return -1; +} + +int remote_handle64_invoke(remote_handle64 h, uint32_t dwScalars, remote_arg *pra) +{ + (void)h; (void)dwScalars; (void)pra; + return -1; +} + +int remote_handle64_close(remote_handle64 h) +{ + (void)h; + return -1; +} + +// /* rpcmem API ------------------------------------------------------------- */ + +void *rpcmem_alloc(int heapid, uint32 flags, int size) +{ + (void)heapid; (void)flags; (void)size; + return NULL; +} + +void rpcmem_free(void *po) +{ + (void)po; +} diff --git a/qcperf/backends/qcom-dsp/src/dspquery_stub.c b/qcperf/backends/qcom-dsp/src/dspquery_stub.c new file mode 100644 index 0000000..5ddd397 --- /dev/null +++ b/qcperf/backends/qcom-dsp/src/dspquery_stub.c @@ -0,0 +1,526 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _DSPQUERYSTUB_H +#define _DSPQUERYSTUB_H + +#include "dspquery_stub.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv)) +#endif + + +#endif // _QAIC_ENV_H + +#include "remote.h" +#include +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc(size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size) < (uintptr_t)me->stack + me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _SYSMONQUERY_SLIM_H +#define _SYSMONQUERY_SLIM_H +#include "remote.h" +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[1]; +static const Type types[1] = {{0x1,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x1}}; +static const Parameter parameters[6] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8),0,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)0}}, 2,0x4,0,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[0]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0}}; +static const Parameter* const parameterArrays[6] = {(&(parameters[4])),(&(parameters[5])),(&(parameters[3])),(&(parameters[0])),(&(parameters[1])),(&(parameters[2]))}; +static const Method methods[4] = {{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x1),0x4,0x0,2,2,(&(parameterArrays[3])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x1,0x0),0x0,0x0,1,1,(&(parameterArrays[5])),0x1,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x4,0x0,1,1,(&(parameterArrays[2])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x2,0x0,0x0),0x8,0x4,5,3,(&(parameterArrays[0])),0x4,0x4}}; +static const Method* const methodArrays[5] = {&(methods[0]),&(methods[1]),&(methods[2]),&(methods[3]),&(methods[2])}; +static const char strings[70] = "profdata_ptr\0get_profdata\0no_metrics\0npu_flag\0deinit\0close\0open\0uri\0h\0"; +static const uint16_t methodStrings[13] = {13,0,26,37,59,64,68,46,37,48,37,53,68}; +static const uint16_t methodStringsArrays[5] = {4,11,9,0,7}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(sysmonquery_slim) = {5,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_SYSMONQUERY_SLIM_H +__QAIC_STUB_EXPORT int __QAIC_STUB(sysmonquery_skel_handle_invoke)(remote_handle64 _h, uint32_t _sc, remote_arg* _pra) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(local_remote_handle64_invoke)(_h, _sc, _pra); +} +#ifdef __cplusplus +extern "C" { +#endif +extern int remote_register_dma_handle(int, uint32_t); +__QAIC_STUB_EXPORT int __QAIC_STUB(sysmonquery_open)(const char* uri, remote_handle64* h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(local_remote_handle64_open)(uri, h); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(sysmonquery_close)(remote_handle64 h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(local_remote_handle64_close)(h); +} +static __inline int _stub_method(remote_handle64 _handle, uint32_t _mid, uint32_t _in0[1]) { + remote_arg _pra[1]; + uint32_t _primIn[1]; + int _nErr = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 4); + _TRY(_nErr, __QAIC_REMOTE(local_remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(sysmonquery_init)(remote_handle64 _handle, unsigned int npu_flag) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + return _stub_method(_handle, _mid, (uint32_t*)&npu_flag); +} +static __inline int _stub_method_1(remote_handle64 _handle, uint32_t _mid, char* _rout0[1], uint32_t _rout0Len[1], uint32_t _rout1[1], uint32_t _in2[1]) { + int _numIn[1]; + remote_arg _pra[3]; + uint32_t _primIn[2]; + uint32_t _primROut[1]; + remote_arg* _praIn; + remote_arg* _praROut; + int _nErr = 0; + _numIn[0] = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _COPY(_primIn, 0, _rout0Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _praROut[0].buf.pv = _rout0[0]; + _praROut[0].buf.nLen = (1 * _rout0Len[0]); + _COPY(_primIn, 4, _in2, 0, 4); + _TRY(_nErr, __QAIC_REMOTE(local_remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 2, 0, 0), _pra)); + _COPY(_rout1, 0, _primROut, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(sysmonquery_get_profdata)(remote_handle64 _handle, unsigned char* profdata_ptr, int profdata_ptrLen, int* no_metrics, unsigned int npu_flag) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 3; + return _stub_method_1(_handle, _mid, (char**)&profdata_ptr, (uint32_t*)&profdata_ptrLen, (uint32_t*)no_metrics, (uint32_t*)&npu_flag); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(sysmonquery_deinit)(remote_handle64 _handle, unsigned int npu_flag) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 4; + return _stub_method(_handle, _mid, (uint32_t*)&npu_flag); +} +#ifdef __cplusplus +} +#endif +#endif //_DSPQUERYSTUB_H diff --git a/qcperf/backends/qcom-dsp/src/qcom_dsp.c b/qcperf/backends/qcom-dsp/src/qcom_dsp.c new file mode 100644 index 0000000..688602a --- /dev/null +++ b/qcperf/backends/qcom-dsp/src/qcom_dsp.c @@ -0,0 +1,136 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file dsp_lib.c + * @brief DSP library implementation + * @author Himanshu Keshri (hkeshri@qti.qualcomm.com) + */ + +#include "qcom_dsp.h" + +void get_full_uri_info(const char* uri, char* full_uri, int size, enum DspDomainId domain_id); + +static remote_handle64 h[DSP_MAX] = {0}; +static struct sysmon_query_prof_data* sysmon_query_prof_data_ptr[DSP_MAX] = {0}; + +void get_full_uri_info(const char* uri, char* full_uri, int size, enum DspDomainId domain_id) { + memset(full_uri, 0, (size_t)size); + strlcpy(full_uri, uri, (size_t)size); + remote_handle64 fd; + + if (domain_id == DSP_ADSP) { + strlcat(full_uri, ADSP_DOMAIN, (size_t)size); + remote_handle64_open(ITRANSPORT_PREFIX "attachuserpd&_dom=adsp", &fd); + } else if (domain_id == DSP_NPU0) { + strlcat(full_uri, CDSP_DOMAIN, (size_t)size); + remote_handle64_open(ITRANSPORT_PREFIX "attachuserpd&_dom=cdsp", &fd); + } else { + memset(full_uri, 0, (size_t)size); + } +} + +enum DspReturnCode qcom_dsp_init(enum DspDomainId domain_id) { + enum DspReturnCode return_code = RETURN_CODE_DSP_LIB_FAIL; + int sysmon_query_return_code = -1; + unsigned int npu_id = 0; + char full_uri[256] = {0}; + + if (domain_id == CDSP_DOMAIN_ID) { + npu_id = 0; + } + + get_full_uri_info(sysmonquery_URI, full_uri, sizeof(full_uri), domain_id); + sysmon_query_return_code = sysmonquery_open(full_uri, &h[domain_id]); + if (sysmon_query_return_code != 0) { + return_code = RETURN_CODE_DSP_SYSMON_QUERY_OPEN_FAILED; + } else { + sysmon_query_return_code = sysmonquery_init(h[domain_id], npu_id); + if (sysmon_query_return_code != 0) { + return_code = RETURN_CODE_DSP_SYSMON_QUERY_INIT_FAILED; + } else { + sysmon_query_prof_data_ptr[domain_id] = + (struct sysmon_query_prof_data*)rpcmem_alloc(RPCMEM_DEFAULT_HEAP, (RPCMEM_DEFAULT_FLAGS | RPCMEM_HEAP_NONCOHERENT), sizeof(struct sysmon_query_prof_data)); + if (sysmon_query_prof_data_ptr[domain_id] == NULL) { + return_code = RETURN_CODE_DSP_SYSMON_QUERY_RPC_MEM_ALLOC_FAILED; + } else { + memset(sysmon_query_prof_data_ptr[domain_id], 0, sizeof(struct sysmon_query_prof_data)); + return_code = RETURN_CODE_DSP_LIB_SUCCESS; + } + } + } + + if (return_code != RETURN_CODE_DSP_LIB_SUCCESS) { + qcom_dsp_deinit(domain_id); + } + return return_code; +} + +struct sysmon_query_prof_data* qcom_dsp_get_prof_data(enum DspDomainId domain_id, int* no_metrics) { + unsigned int npu_id = 0; + struct sysmon_query_prof_data* result_ptr = NULL; + if (no_metrics == NULL) { + result_ptr = NULL; + } else { + if (domain_id == CDSP_DOMAIN_ID) { + npu_id = 0; + } + int result = sysmonquery_get_profdata(h[domain_id], (unsigned char*)sysmon_query_prof_data_ptr[domain_id], sizeof(struct sysmon_query_prof_data), no_metrics, npu_id); + if (result == 0) { + result_ptr = sysmon_query_prof_data_ptr[domain_id]; + } else { + result_ptr = NULL; + } + } + return result_ptr; +} + +enum DspReturnCode qcom_dsp_deinit(enum DspDomainId domain_id) { + enum DspReturnCode return_code = RETURN_CODE_DSP_LIB_FAIL; + unsigned int npu_id = 0; + int sysmon_query_return_code = -1; + if (domain_id == CDSP_DOMAIN_ID) { + npu_id = 0; + } + + sysmon_query_return_code = sysmonquery_deinit(h[domain_id], npu_id); + if (sysmon_query_return_code != 0) { + return_code = RETURN_CODE_DSP_SYSMON_QUERY_DEINIT_FAILED; + } else { + return_code = RETURN_CODE_DSP_LIB_SUCCESS; + } + if (sysmon_query_prof_data_ptr[domain_id] != NULL) { + rpcmem_free(sysmon_query_prof_data_ptr[domain_id]); + } + + if (h[domain_id] != 0) { + sysmonquery_close(h[domain_id]); + } + return return_code; +} diff --git a/qcperf/backends/qcom-linux-cpu/CMakeLists.txt b/qcperf/backends/qcom-linux-cpu/CMakeLists.txt new file mode 100644 index 0000000..6ebdf85 --- /dev/null +++ b/qcperf/backends/qcom-linux-cpu/CMakeLists.txt @@ -0,0 +1,28 @@ +# ============================================================================ +# QcPerf Qualcomm Linux CPU Backend +# ============================================================================ +# This CMakeLists.txt builds the qcom-linux-cpu backend, which monitors CPU +# performance metrics on Qualcomm Linux platforms + +message("Added qcom-linux-cpu backend") + +add_library(QcPerfQcomLinuxCpuBackend STATIC + src/qcom_linux_cpu.c + src/qcom_linux_cpu_info.c + src/qcom_linux_cpu_utils.c +) + +target_include_directories(QcPerfQcomLinuxCpuBackend PUBLIC + inc + ${CMAKE_SOURCE_DIR}/core/inc + ${CMAKE_SOURCE_DIR}/core/inc/internal + ${CMAKE_SOURCE_DIR}/backends/inc + ${CMAKE_SOURCE_DIR}/utils/qthread/inc + ${CMAKE_SOURCE_DIR}/utils/qtime/inc +) + +target_link_libraries(QcPerfQcomLinuxCpuBackend + QcPerfQThread + QcPerfQTime + ${_OS_M} +) diff --git a/qcperf/backends/qcom-linux-cpu/inc/qcom_linux_cpu.h b/qcperf/backends/qcom-linux-cpu/inc/qcom_linux_cpu.h new file mode 100644 index 0000000..1a60072 --- /dev/null +++ b/qcperf/backends/qcom-linux-cpu/inc/qcom_linux_cpu.h @@ -0,0 +1,62 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file qcom_linux_cpu.h + * @brief Qualcomm Linux CPU backend interface for libqcperf + * @author Himanshu Keshri (hkeshri@qti.qualcomm.com) + * + * This header provides the public interface for the qcom-linux-cpu backend, + * which monitors CPU performance metrics on Qualcomm Linux platforms. + * It also defines capability configuration and streaming/sampling rates. + */ + +#ifndef QCOM_LINUX_CPU_H +#define QCOM_LINUX_CPU_H + +#include "qcom_linux_cpu_info.h" + +struct QcPerfBackendPrivate; + +/** + * @brief Create and initialize the qcom-linux-cpu backend + * + * This function configures the qcom-linux-cpu backend by populating the backend + * private structure with function pointers for all required backend + * operations including initialization, start, stop, deinitialization, + * and callback registration. + * + * @param[in,out] backend Pointer to backend private structure to be configured + * + * @return QC_PERF_RETURN_CODE_SUCCESS on successful creation + * @return QC_PERF_RETURN_CODE_NULL_POINTER if backend pointer is NULL + */ +enum QcPerfReturnCode qcperf_qcom_linux_cpu_create(struct QcPerfBackendPrivate* backend); + +#endif /* QCOM_LINUX_CPU_H */ diff --git a/qcperf/backends/qcom-linux-cpu/inc/qcom_linux_cpu_info.h b/qcperf/backends/qcom-linux-cpu/inc/qcom_linux_cpu_info.h new file mode 100644 index 0000000..6f9d2a0 --- /dev/null +++ b/qcperf/backends/qcom-linux-cpu/inc/qcom_linux_cpu_info.h @@ -0,0 +1,214 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file qcom_linux_cpu_info.h + * @brief Metric definitions and initialization functions for qcom-linux-cpu backend + * @author Himanshu Keshri (hkeshri@qti.qualcomm.com) + * + * This header contains all metric IDs, names, descriptions, and units for the + * qcom-linux-cpu backend. Metric IDs are static compile-time constants. + */ + +#ifndef QCOM_LINUX_CPU_INFO_H +#define QCOM_LINUX_CPU_INFO_H + +#include + +#include "qcperf_common.h" + +#define QCOM_LINUX_CPU_MAX_CORES 18 +#define QCOM_LINUX_CPU_METRICS_PER_CORE 5 +#define QCOM_LINUX_CPU_TOTAL_METRICS 2 + +#define QCOM_LINUX_CPU_CAPABILITY_ID 0 +#define QCOM_LINUX_CPU_CAPABILITIES_LEN 1 +#define QCOM_LINUX_CPU_CAPABILITY "cpu" + +#define QCOM_LINUX_CPU_STREAMING_RATES_LEN 3 +#define QCOM_LINUX_CPU_STREAMING_RATES 200, 500, 1000 + +#define QCOM_LINUX_CPU_SAMPLING_RATES_LEN 3 +#define QCOM_LINUX_CPU_SAMPLING_RATES 50, 100, 200 + +/* ============================================================================ + * Metrics + * ============================================================================ */ + +#define QCOM_LINUX_CPU_TOTAL_LOAD_ID 0 /**< Total CPU load */ +#define QCOM_LINUX_CPU_TOTAL_EFF_UTIL_ID 1 /**< Total CPU effective utilization */ + +/* Core 0: IDs 2-6 */ +#define QCOM_LINUX_CPU_CORE_0_LOAD 2 +#define QCOM_LINUX_CPU_CORE_0_FREQ 3 +#define QCOM_LINUX_CPU_CORE_0_STEAL_TIME 4 +#define QCOM_LINUX_CPU_CORE_0_EFF_UTIL 5 +#define QCOM_LINUX_CPU_CORE_0_DCVS_LIMIT 6 + +/* Core 1: IDs 7-11 */ +#define QCOM_LINUX_CPU_CORE_1_LOAD 7 +#define QCOM_LINUX_CPU_CORE_1_FREQ 8 +#define QCOM_LINUX_CPU_CORE_1_STEAL_TIME 9 +#define QCOM_LINUX_CPU_CORE_1_EFF_UTIL 10 +#define QCOM_LINUX_CPU_CORE_1_DCVS_LIMIT 11 + +/* Core 2: IDs 12-16 */ +#define QCOM_LINUX_CPU_CORE_2_LOAD 12 +#define QCOM_LINUX_CPU_CORE_2_FREQ 13 +#define QCOM_LINUX_CPU_CORE_2_STEAL_TIME 14 +#define QCOM_LINUX_CPU_CORE_2_EFF_UTIL 15 +#define QCOM_LINUX_CPU_CORE_2_DCVS_LIMIT 16 + +/* Core 3: IDs 17-21 */ +#define QCOM_LINUX_CPU_CORE_3_LOAD 17 +#define QCOM_LINUX_CPU_CORE_3_FREQ 18 +#define QCOM_LINUX_CPU_CORE_3_STEAL_TIME 19 +#define QCOM_LINUX_CPU_CORE_3_EFF_UTIL 20 +#define QCOM_LINUX_CPU_CORE_3_DCVS_LIMIT 21 + +/* Core 4: IDs 22-26 */ +#define QCOM_LINUX_CPU_CORE_4_LOAD 22 +#define QCOM_LINUX_CPU_CORE_4_FREQ 23 +#define QCOM_LINUX_CPU_CORE_4_STEAL_TIME 24 +#define QCOM_LINUX_CPU_CORE_4_EFF_UTIL 25 +#define QCOM_LINUX_CPU_CORE_4_DCVS_LIMIT 26 + +/* Core 5: IDs 27-31 */ +#define QCOM_LINUX_CPU_CORE_5_LOAD 27 +#define QCOM_LINUX_CPU_CORE_5_FREQ 28 +#define QCOM_LINUX_CPU_CORE_5_STEAL_TIME 29 +#define QCOM_LINUX_CPU_CORE_5_EFF_UTIL 30 +#define QCOM_LINUX_CPU_CORE_5_DCVS_LIMIT 31 + +/* Core 6: IDs 32-36 */ +#define QCOM_LINUX_CPU_CORE_6_LOAD 32 +#define QCOM_LINUX_CPU_CORE_6_FREQ 33 +#define QCOM_LINUX_CPU_CORE_6_STEAL_TIME 34 +#define QCOM_LINUX_CPU_CORE_6_EFF_UTIL 35 +#define QCOM_LINUX_CPU_CORE_6_DCVS_LIMIT 36 + +/* Core 7: IDs 37-41 */ +#define QCOM_LINUX_CPU_CORE_7_LOAD 37 +#define QCOM_LINUX_CPU_CORE_7_FREQ 38 +#define QCOM_LINUX_CPU_CORE_7_STEAL_TIME 39 +#define QCOM_LINUX_CPU_CORE_7_EFF_UTIL 40 +#define QCOM_LINUX_CPU_CORE_7_DCVS_LIMIT 41 + +/* Core 8: IDs 42-46 */ +#define QCOM_LINUX_CPU_CORE_8_LOAD 42 +#define QCOM_LINUX_CPU_CORE_8_FREQ 43 +#define QCOM_LINUX_CPU_CORE_8_STEAL_TIME 44 +#define QCOM_LINUX_CPU_CORE_8_EFF_UTIL 45 +#define QCOM_LINUX_CPU_CORE_8_DCVS_LIMIT 46 + +/* Core 9: IDs 47-51 */ +#define QCOM_LINUX_CPU_CORE_9_LOAD 47 +#define QCOM_LINUX_CPU_CORE_9_FREQ 48 +#define QCOM_LINUX_CPU_CORE_9_STEAL_TIME 49 +#define QCOM_LINUX_CPU_CORE_9_EFF_UTIL 50 +#define QCOM_LINUX_CPU_CORE_9_DCVS_LIMIT 51 + +/* Core 10: IDs 52-56 */ +#define QCOM_LINUX_CPU_CORE_10_LOAD 52 +#define QCOM_LINUX_CPU_CORE_10_FREQ 53 +#define QCOM_LINUX_CPU_CORE_10_STEAL_TIME 54 +#define QCOM_LINUX_CPU_CORE_10_EFF_UTIL 55 +#define QCOM_LINUX_CPU_CORE_10_DCVS_LIMIT 56 + +/* Core 11: IDs 57-61 */ +#define QCOM_LINUX_CPU_CORE_11_LOAD 57 +#define QCOM_LINUX_CPU_CORE_11_FREQ 58 +#define QCOM_LINUX_CPU_CORE_11_STEAL_TIME 59 +#define QCOM_LINUX_CPU_CORE_11_EFF_UTIL 60 +#define QCOM_LINUX_CPU_CORE_11_DCVS_LIMIT 61 + +/* Core 12: IDs 62-66 */ +#define QCOM_LINUX_CPU_CORE_12_LOAD 62 +#define QCOM_LINUX_CPU_CORE_12_FREQ 63 +#define QCOM_LINUX_CPU_CORE_12_STEAL_TIME 64 +#define QCOM_LINUX_CPU_CORE_12_EFF_UTIL 65 +#define QCOM_LINUX_CPU_CORE_12_DCVS_LIMIT 66 + +/* Core 13: IDs 67-71 */ +#define QCOM_LINUX_CPU_CORE_13_LOAD 67 +#define QCOM_LINUX_CPU_CORE_13_FREQ 68 +#define QCOM_LINUX_CPU_CORE_13_STEAL_TIME 69 +#define QCOM_LINUX_CPU_CORE_13_EFF_UTIL 70 +#define QCOM_LINUX_CPU_CORE_13_DCVS_LIMIT 71 + +/* Core 14: IDs 72-76 */ +#define QCOM_LINUX_CPU_CORE_14_LOAD 72 +#define QCOM_LINUX_CPU_CORE_14_FREQ 73 +#define QCOM_LINUX_CPU_CORE_14_STEAL_TIME 74 +#define QCOM_LINUX_CPU_CORE_14_EFF_UTIL 75 +#define QCOM_LINUX_CPU_CORE_14_DCVS_LIMIT 76 + +/* Core 15: IDs 77-81 */ +#define QCOM_LINUX_CPU_CORE_15_LOAD 77 +#define QCOM_LINUX_CPU_CORE_15_FREQ 78 +#define QCOM_LINUX_CPU_CORE_15_STEAL_TIME 79 +#define QCOM_LINUX_CPU_CORE_15_EFF_UTIL 80 +#define QCOM_LINUX_CPU_CORE_15_DCVS_LIMIT 81 + +/* Core 16: IDs 82-86 */ +#define QCOM_LINUX_CPU_CORE_16_LOAD 82 +#define QCOM_LINUX_CPU_CORE_16_FREQ 83 +#define QCOM_LINUX_CPU_CORE_16_STEAL_TIME 84 +#define QCOM_LINUX_CPU_CORE_16_EFF_UTIL 85 +#define QCOM_LINUX_CPU_CORE_16_DCVS_LIMIT 86 + +/* Core 17: IDs 87-91 */ +#define QCOM_LINUX_CPU_CORE_17_LOAD 87 +#define QCOM_LINUX_CPU_CORE_17_FREQ 88 +#define QCOM_LINUX_CPU_CORE_17_STEAL_TIME 89 +#define QCOM_LINUX_CPU_CORE_17_EFF_UTIL 90 +#define QCOM_LINUX_CPU_CORE_17_DCVS_LIMIT 91 + +/* ============================================================================ + * Per-core metric offsets + * ============================================================================ */ + +#define QCOM_LINUX_CPU_LOAD_OFFSET 0 /**< CPU load */ +#define QCOM_LINUX_CPU_FREQ_OFFSET 1 /**< CPU frequency */ +#define QCOM_LINUX_CPU_STEAL_TIME_OFFSET 2 /**< CPU steal time */ +#define QCOM_LINUX_CPU_EFF_UTIL_OFFSET 3 /**< CPU effective utilization */ +#define QCOM_LINUX_CPU_DCVS_LIMIT_OFFSET 4 /**< CPU DCVS frequency limit */ + +/* ============================================================================ + * Per-core metric ID lookup macro + * QCOM_LINUX_CPU_CORE_BASE_ID(core_id) -> LOAD ID + * QCOM_LINUX_CPU_CORE_BASE_ID(core_id) + QCOM_LINUX_CPU_FREQ_OFFSET -> FREQ ID + * etc. + * ============================================================================ */ + +#define QCOM_LINUX_CPU_CORE_BASE_ID(core_id) ((uint16_t)(QCOM_LINUX_CPU_CORE_0_LOAD + (core_id)*QCOM_LINUX_CPU_METRICS_PER_CORE)) + +enum QcPerfReturnCode qcom_linux_cpu_init_metrics(struct QcPerfMetricInfo *metrics_data, uint8_t *metric_data_len); + +#endif /* QCOM_LINUX_CPU_INFO_H */ diff --git a/qcperf/backends/qcom-linux-cpu/inc/qcom_linux_cpu_utils.h b/qcperf/backends/qcom-linux-cpu/inc/qcom_linux_cpu_utils.h new file mode 100644 index 0000000..8455dba --- /dev/null +++ b/qcperf/backends/qcom-linux-cpu/inc/qcom_linux_cpu_utils.h @@ -0,0 +1,166 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file qcom_linux_cpu_utils.h + * @brief Sysfs/procfs utility functions for the qcom-linux-cpu backend + * @author Himanshu Keshri (hkeshri@qti.qualcomm.com) + * + * This header declares the internal utility functions used to read CPU + * topology, capacity, frequency, load, and DCVS limits from sysfs and + * procfs. These utilities are shared between qcom_linux_cpu.c and + * qcom_linux_cpu_info.c. + */ + +#ifndef QCOM_LINUX_CPU_UTILS_H +#define QCOM_LINUX_CPU_UTILS_H + +#include +#include + +#include "qcperf_common.h" + +/* ============================================================================ + * Sysfs / procfs Path Definitions + * ============================================================================ */ + +/** Path to read the number of possible CPU cores (e.g., "0-7") */ +#define QCOM_LINUX_CPU_COUNT_NODE "/sys/devices/system/cpu/possible" + +/** Path to read per-core CPU statistics */ +#define QCOM_LINUX_CPU_STAT_NODE "/proc/stat" + +/** Format string for per-core current CPU frequency node (value in kHz) */ +#define QCOM_LINUX_CPU_FREQ_NODE_FMT "/sys/devices/system/cpu/cpu%u/cpufreq/cpuinfo_cur_freq" + +/** Format string for per-core CPU capacity node */ +#define QCOM_LINUX_CPU_CAPACITY_NODE_FMT "/sys/devices/system/cpu/cpu%u/cpu_capacity" + +/** Format string for per-core DCVS frequency limit node (value in Hz) */ +#define QCOM_LINUX_CPU_DCVS_NODE_FMT "/sys/devices/system/cpu/cpu%u/dcvsh_freq_limit" + +/** Maximum length for sysfs node path strings */ +#define QCOM_LINUX_CPU_NODE_PATH_MAX_LEN 128 + +/** Maximum length for a single line read from /proc/stat */ +#define QCOM_LINUX_CPU_STAT_LINE_MAX_LEN 256 + +/** Conversion factor from kHz to MHz */ +#define QCOM_LINUX_CPU_KHZ_TO_MHZ 1000 + +/** Conversion factor from ms to us for usleep */ +#define QCOM_LINUX_CPU_MS_TO_US 1000 + +/** Number of fields expected in a /proc/stat per-core line (cpu_id + 10 values) */ +#define QCOM_LINUX_CPU_STAT_FIELD_COUNT 11 + +/** + * @struct QcomLinuxCpuLoadInfo + * @brief Stores a single /proc/stat snapshot for delta-based utilization calculation + */ +struct QcomLinuxCpuLoadInfo { + double idle; /**< Idle + iowait ticks */ + double total_time; /**< Sum of all CPU time ticks */ + double steal_time; /**< Steal time ticks */ +}; + +/** + * @brief Read the number of CPU cores from /sys/devices/system/cpu/possible + * + * Parses the "0-N" format to determine the total core count (N+1). + * + * @param[out] num_cores Populated with the number of CPU cores + * @return QC_PERF_RETURN_CODE_SUCCESS on success + * @return QC_PERF_RETURN_CODE_FAILED if the node cannot be opened or parsed + */ +enum QcPerfReturnCode qcom_linux_cpu_util_get_num_cores(uint32_t *num_cores); + +/** + * @brief Read CPU capacity for a single core from sysfs + * + * Reads the cpu_capacity (or cpuinfo_max_freq) sysfs node for the given core. + * + * @param[in] core_id CPU core index + * @param[out] capacity Populated with the capacity value for the core + * @return QC_PERF_RETURN_CODE_SUCCESS on success + * @return QC_PERF_RETURN_CODE_FAILED if the node cannot be opened or parsed + */ +enum QcPerfReturnCode qcom_linux_cpu_util_get_core_capacity(uint32_t core_id, uint32_t *capacity); + +/** + * @brief Read and sum CPU capacity across all cores + * + * Calls qcom_linux_cpu_util_get_num_cores() to determine the core count, then + * calls qcom_linux_cpu_util_get_core_capacity() for each core and accumulates + * the total. + * + * @param[out] total_capacity Sum of all per-core capacity values + * @return QC_PERF_RETURN_CODE_SUCCESS on success + * @return QC_PERF_RETURN_CODE_FAILED if the core count or any core's capacity cannot be read, or total is zero + */ +enum QcPerfReturnCode qcom_linux_cpu_util_get_total_capacity(uint32_t *total_capacity); + +/** + * @brief Read /proc/stat and populate per-core load snapshots + * + * Parses each "cpuN ..." line and stores idle, total, and steal ticks. + * + * @param[out] load_info Array of per-core load snapshots (must have num_cores entries) + * @param[in] num_cores Number of cores to read + * @return QC_PERF_RETURN_CODE_SUCCESS if at least one core was read + * @return QC_PERF_RETURN_CODE_FAILED if the file cannot be opened or no cores were parsed + */ +enum QcPerfReturnCode qcom_linux_cpu_util_get_proc_stat(struct QcomLinuxCpuLoadInfo *load_info, uint32_t num_cores); + +/** + * @brief Read the current CPU frequency for a specific core + * + * Reads the cpuinfo_cur_freq (or scaling_cur_freq) sysfs node (value in kHz) + * and converts to MHz. + * + * @param[in] core_id CPU core index + * @param[out] frequency_mhz Populated with the current frequency in MHz (0.0 on failure) + * @return QC_PERF_RETURN_CODE_SUCCESS on success + * @return QC_PERF_RETURN_CODE_FAILED if the node cannot be read + */ +enum QcPerfReturnCode qcom_linux_cpu_util_get_core_frequency(uint32_t core_id, double *frequency_mhz); + +/** + * @brief Read the DCVS frequency limit for a specific core + * + * Reads /sys/devices/system/cpu/cpu%u/dcvsh_freq_limit (value in Hz). + * + * @param[in] core_id CPU core index + * @param[out] dcvs_limit Populated with the DCVS frequency limit in Hz + * @return QC_PERF_RETURN_CODE_SUCCESS on success + * @return QC_PERF_RETURN_CODE_FAILED if the node is unavailable or cannot be parsed + */ +enum QcPerfReturnCode qcom_linux_cpu_util_get_dcvs_limit(uint32_t core_id, uint32_t *dcvs_limit); + +#endif /* QCOM_LINUX_CPU_UTILS_H */ diff --git a/qcperf/backends/qcom-linux-cpu/src/qcom_linux_cpu.c b/qcperf/backends/qcom-linux-cpu/src/qcom_linux_cpu.c new file mode 100644 index 0000000..65809bd --- /dev/null +++ b/qcperf/backends/qcom-linux-cpu/src/qcom_linux_cpu.c @@ -0,0 +1,751 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file qcom_linux_cpu.c + * @brief Qualcomm Linux CPU backend implementation for libqcperf + * @author Himanshu Keshri (hkeshri@qti.qualcomm.com) + * + * This file implements the qcom-linux-cpu backend which monitors CPU performance + * metrics on Qualcomm Linux platforms. It reads CPU statistics from /proc/stat + * and sysfs nodes to provide per-core and total CPU metrics including utilization, + * frequency, steal time, effective utilization, and DCVS frequency limits. + */ + +#include +#include +#include +#include +#include +#include + +#include "qcom_linux_cpu.h" +#include "qcom_linux_cpu_utils.h" +#include "qcperf_backend_enum.h" +#include "qcperf_backend_interface.h" +#include "QThread.h" +#include "qtime.h" + +/** Maximum length for log messages */ +#define QCOM_LINUX_CPU_MESSAGE_MAX_LEN 256 + +/** + * @struct QcomLinuxCpuSample + * @brief Stores computed per-core CPU metrics for one sampling interval + */ +struct QcomLinuxCpuSample { + double frequency; /**< Current CPU frequency in MHz */ + double utilization; /**< CPU utilization percentage */ + double steal_time; /**< CPU steal time percentage */ + double eff_utilization; /**< Effective CPU utilization percentage (excl. steal) */ + uint32_t dcvs_limit; /**< DCVS frequency limit in Hz */ +}; + +static QcPerfMessageCallback g_message_callback = NULL; +static QcPerfDataCallback g_data_callback = NULL; + +static struct QcPerfBackendInfo g_backend_info = {0}; + +static volatile bool g_is_thread_running = false; +static struct QThreadInfo g_thread_info = {0}; + +static const uint16_t g_streaming_rates[QCOM_LINUX_CPU_STREAMING_RATES_LEN] = {QCOM_LINUX_CPU_STREAMING_RATES}; +static const uint16_t g_sampling_rates[QCOM_LINUX_CPU_SAMPLING_RATES_LEN] = {QCOM_LINUX_CPU_SAMPLING_RATES}; + +/** + * @brief Conditionally send a log message if the message callback is registered + */ +#define SEND_MESSAGE(level, ...) \ + if (NULL != g_message_callback) { \ + send_message(level, __VA_ARGS__); \ + } + +/* ============================================================================ + * Forward Declarations + * ============================================================================ */ + +static inline void send_message(enum QcPerfMessageLevel level, const char *fmt, ...); +static enum QcPerfReturnCode qcom_linux_cpu_alloc(uint32_t num_cores); +static void qcom_linux_cpu_free(void); +static enum QcPerfReturnCode validate_request(struct QcPerfRequest *request); +static enum QcPerfReturnCode qcom_linux_cpu_set_message_callback(QcPerfMessageCallback message_callback); +static enum QcPerfReturnCode qcom_linux_cpu_init(void); +static enum QcPerfReturnCode qcom_linux_cpu_backend_info(struct QcPerfBackendInfo *backend_info); +static enum QcPerfReturnCode qcom_linux_cpu_set_data_callback(QcPerfDataCallback data_callback); +static enum QcPerfReturnCode qcom_linux_cpu_start(struct QcPerfRequest *request); +static enum QcPerfReturnCode qcom_linux_cpu_stop(struct QcPerfRequest *request); +static enum QcPerfReturnCode qcom_linux_cpu_deinit(void); +static void *qcom_linux_cpu_collect_data(void *param); + +/** + * @brief Format and deliver a log message via the registered message callback + */ +static inline void send_message(enum QcPerfMessageLevel level, const char *fmt, ...) { + char msg[QCOM_LINUX_CPU_MESSAGE_MAX_LEN]; + struct QcPerfMessage msg_struct = {0}; + va_list args; + int len = 0; + + va_start(args, fmt); + len = vsnprintf(msg, sizeof(msg), fmt, args); + va_end(args); + + if (len > 0) { + msg_struct.message = msg; + msg_struct.message_length = (size_t)len; + msg_struct.message_level = level; + g_message_callback(&msg_struct); + } +} + +/** + * @brief Allocate memory for backend capabilities and metrics + * + * @param[in] num_cores Number of CPU cores detected on the device + * @return QC_PERF_RETURN_CODE_SUCCESS on success + * @return QC_PERF_RETURN_CODE_CALLOC_FAILED if any allocation fails + */ +static enum QcPerfReturnCode qcom_linux_cpu_alloc(uint32_t num_cores) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_SUCCESS; + uint32_t total_metric_count = 0; + + total_metric_count = QCOM_LINUX_CPU_TOTAL_METRICS + (num_cores * QCOM_LINUX_CPU_METRICS_PER_CORE); + + g_backend_info.capabilities_list = (struct QcPerfCapabilityInfo *)calloc(QCOM_LINUX_CPU_CAPABILITIES_LEN, sizeof(struct QcPerfCapabilityInfo)); + if (NULL == g_backend_info.capabilities_list) { + ret = QC_PERF_RETURN_CODE_CALLOC_FAILED; + } else { + g_backend_info.capabilities_list_length = QCOM_LINUX_CPU_CAPABILITIES_LEN; + g_backend_info.capabilities_list[0].metric_ids_list = (struct QcPerfMetricInfo *)calloc(total_metric_count, sizeof(struct QcPerfMetricInfo)); + if (NULL == g_backend_info.capabilities_list[0].metric_ids_list) { + free(g_backend_info.capabilities_list); + g_backend_info.capabilities_list = NULL; + g_backend_info.capabilities_list_length = 0; + ret = QC_PERF_RETURN_CODE_CALLOC_FAILED; + } + } + + return ret; +} + +/** + * @brief Free all memory allocated for backend capabilities and metrics + */ +static void qcom_linux_cpu_free(void) { + if (NULL != g_backend_info.capabilities_list) { + if (NULL != g_backend_info.capabilities_list[0].metric_ids_list) { + free(g_backend_info.capabilities_list[0].metric_ids_list); + g_backend_info.capabilities_list[0].metric_ids_list = NULL; + } + g_backend_info.capabilities_list[0].metric_ids_list_len = 0; + free(g_backend_info.capabilities_list); + g_backend_info.capabilities_list = NULL; + } + g_backend_info.capabilities_list_length = 0; +} + +/** + * @brief Validate a performance monitoring request + * + * Checks that the capability ID, sampling rate, and streaming rate in the + * request are all supported by this backend. + * + * @param[in] request Pointer to the request to validate + * @return QC_PERF_RETURN_CODE_SUCCESS if all parameters are valid + * @return QC_PERF_RETURN_CODE_CAPABILITY_NOT_FOUND if capability ID is unknown + * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if rates are unsupported + */ +static enum QcPerfReturnCode validate_request(struct QcPerfRequest *request) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_CAPABILITY_NOT_FOUND; + struct QcPerfCapabilityInfo *capability_info = NULL; + bool sampling_rate_valid = false; + bool streaming_rate_valid = false; + uint8_t i = 0; + + for (i = 0; i < g_backend_info.capabilities_list_length; i++) { + if (g_backend_info.capabilities_list[i].capability_id == request->capability_id) { + capability_info = &g_backend_info.capabilities_list[i]; + ret = QC_PERF_RETURN_CODE_SUCCESS; + break; + } + } + + if (QC_PERF_RETURN_CODE_SUCCESS != ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Capability ID %u not found", request->capability_id); + } else { + for (i = 0; i < capability_info->sampling_rate_len; i++) { + if (capability_info->sampling_rate[i] == request->sampling_rate) { + sampling_rate_valid = true; + break; + } + } + + if (false == sampling_rate_valid) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Invalid sampling rate %u for capability ID %u", request->sampling_rate, request->capability_id); + ret = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; + } else { + for (i = 0; i < capability_info->streaming_rate_len; i++) { + if (capability_info->streaming_rate[i] == request->streaming_rate) { + streaming_rate_valid = true; + break; + } + } + + if (false == streaming_rate_valid) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Invalid streaming rate %u for capability ID %u", request->streaming_rate, request->capability_id); + ret = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; + } + } + } + + return ret; +} + +/* ============================================================================ + * Backend Interface Implementations + * ============================================================================ */ + +/** + * @brief Register the message callback for this backend + * + * Also forwards the callback to the utils module so utility functions + * can emit log messages through the same channel. + */ +static enum QcPerfReturnCode qcom_linux_cpu_set_message_callback(QcPerfMessageCallback message_callback) { + g_message_callback = message_callback; + return QC_PERF_RETURN_CODE_SUCCESS; +} + +/** + * @brief Initialize the qcom-linux-cpu backend + * + * Reads the CPU core count, capacity, and DCVS availability from sysfs, + * allocates metric and capability structures, and populates them with the + * backend configuration. + * + * @return QC_PERF_RETURN_CODE_SUCCESS on successful initialization + * @return QC_PERF_RETURN_CODE_FAILED if core count or capacity cannot be read + * @return QC_PERF_RETURN_CODE_CALLOC_FAILED if memory allocation fails + */ +static enum QcPerfReturnCode qcom_linux_cpu_init(void) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_SUCCESS; + uint32_t num_cores = 0; + uint32_t total_capacity = 0; + uint32_t total_metric_count = 0; + uint8_t i = 0; + + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Initializing qcom-linux-cpu backend"); + + ret = qcom_linux_cpu_util_get_num_cores(&num_cores); + if (QC_PERF_RETURN_CODE_SUCCESS != ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to read CPU core count"); + } else if (num_cores > QCOM_LINUX_CPU_MAX_CORES) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "CPU core count %u exceeds maximum supported %u", num_cores, QCOM_LINUX_CPU_MAX_CORES); + ret = QC_PERF_RETURN_CODE_FAILED; + } else { + ret = qcom_linux_cpu_util_get_total_capacity(&total_capacity); + if (QC_PERF_RETURN_CODE_SUCCESS != ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to read CPU capacity"); + } else { + ret = qcom_linux_cpu_alloc(num_cores); + if (QC_PERF_RETURN_CODE_SUCCESS != ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to allocate backend memory"); + } else { + ret = qcom_linux_cpu_init_metrics(g_backend_info.capabilities_list[0].metric_ids_list, &g_backend_info.capabilities_list[0].metric_ids_list_len); + if (QC_PERF_RETURN_CODE_SUCCESS != ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to initialize metrics"); + } else { + total_metric_count = (uint32_t)g_backend_info.capabilities_list[0].metric_ids_list_len; + g_backend_info.backend_id = QC_PERF_BACKEND_QCOM_LINUX_CPU; + + g_backend_info.capabilities_list[0].capability_id = QCOM_LINUX_CPU_CAPABILITY_ID; + snprintf(g_backend_info.capabilities_list[0].capability_name, CAPABILITY_NAME_MAX_LEN, "%s", QCOM_LINUX_CPU_CAPABILITY); + g_backend_info.capabilities_list[0].capability_name_len = strlen(g_backend_info.capabilities_list[0].capability_name); + + for (i = 0; i < QCOM_LINUX_CPU_STREAMING_RATES_LEN && i < MAX_SAMPLING_STREAMING_RATES_LEN; i++) { + g_backend_info.capabilities_list[0].streaming_rate[i] = g_streaming_rates[i]; + g_backend_info.capabilities_list[0].streaming_rate_len++; + } + + for (i = 0; i < QCOM_LINUX_CPU_SAMPLING_RATES_LEN && i < MAX_SAMPLING_STREAMING_RATES_LEN; i++) { + g_backend_info.capabilities_list[0].sampling_rate[i] = g_sampling_rates[i]; + g_backend_info.capabilities_list[0].sampling_rate_len++; + } + + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "qcom-linux-cpu backend initialized: %u cores, %u metrics", num_cores, total_metric_count); + } + } + } + } + + if (QC_PERF_RETURN_CODE_SUCCESS != ret) { + qcom_linux_cpu_free(); + } + + return ret; +} + +/** + * @brief Retrieve backend information including capabilities and metrics + * + * @param[out] backend_info Pointer to structure to be populated + * @return QC_PERF_RETURN_CODE_SUCCESS on success + * @return QC_PERF_RETURN_CODE_NULL_POINTER if backend_info is NULL + */ +static enum QcPerfReturnCode qcom_linux_cpu_backend_info(struct QcPerfBackendInfo *backend_info) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_SUCCESS; + + if (NULL == backend_info) { + ret = QC_PERF_RETURN_CODE_NULL_POINTER; + } else { + *backend_info = g_backend_info; + } + + return ret; +} + +/** + * @brief Register the data callback for delivering collected metrics + * + * @param[in] data_callback Function pointer to the data callback + * @return QC_PERF_RETURN_CODE_SUCCESS on success + * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if data_callback is NULL + * @return QC_PERF_RETURN_CODE_CALLBACK_ALREADY_SET if a callback is already registered + */ +static enum QcPerfReturnCode qcom_linux_cpu_set_data_callback(QcPerfDataCallback data_callback) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_FAILED; + + if (NULL == data_callback) { + ret = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; + } else if (NULL != g_data_callback) { + ret = QC_PERF_RETURN_CODE_CALLBACK_ALREADY_SET; + } else { + g_data_callback = data_callback; + ret = QC_PERF_RETURN_CODE_SUCCESS; + } + + return ret; +} + +/** + * @brief Start CPU performance data collection + * + * Validates the request, checks that the data callback is registered, and + * creates the data collection thread. + * + * @param[in] request Pointer to the performance request structure + * @return QC_PERF_RETURN_CODE_SUCCESS on successful start + * @return QC_PERF_RETURN_CODE_NULL_POINTER if request is NULL + * @return QC_PERF_RETURN_CODE_FAILED if callback not set or thread creation fails + * @return QC_PERF_RETURN_CODE_ALREADY_INITIALIZED if thread is already running + */ +static enum QcPerfReturnCode qcom_linux_cpu_start(struct QcPerfRequest *request) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_SUCCESS; + enum QThreadReturnCode thread_ret = RET_QTHREAD_CREATE_FAILED; + struct QThreadAttributes thread_attrs = {0}; + + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Starting qcom-linux-cpu data collection"); + + if (NULL == request) { + ret = QC_PERF_RETURN_CODE_NULL_POINTER; + } else { + ret = validate_request(request); + if (QC_PERF_RETURN_CODE_SUCCESS != ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Request validation failed"); + } else if (NULL == g_data_callback) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Data callback is not set"); + ret = QC_PERF_RETURN_CODE_FAILED; + } else if (g_is_thread_running) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "Collection thread is already running"); + ret = QC_PERF_RETURN_CODE_ALREADY_INITIALIZED; + } else { + thread_attrs.stack_size = 0; + thread_attrs.thread_params = request; + thread_attrs.thread_fn = qcom_linux_cpu_collect_data; + snprintf((char *)thread_attrs.thread_name, THREAD_NAME_SIZE, "qcperf_cpu_thread"); + thread_attrs.thread_name_len = (uint8_t)strlen((char *)thread_attrs.thread_name); + + thread_ret = thread_create(&thread_attrs, &g_thread_info); + if (RET_QTHREAD_CREATE_SUCCESS != thread_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to create CPU collection thread"); + ret = QC_PERF_RETURN_CODE_FAILED; + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "CPU collection thread started successfully"); + } + } + } + + return ret; +} + +/** + * @brief Stop CPU performance data collection + * + * Signals the collection thread to stop, waits for it to finish, and + * releases the thread handle. + * + * @param[in] request Pointer to the performance request structure + * @return QC_PERF_RETURN_CODE_SUCCESS on successful stop + * @return QC_PERF_RETURN_CODE_NULL_POINTER if request is NULL + * @return QC_PERF_RETURN_CODE_FAILED if thread join or destroy fails + */ +static enum QcPerfReturnCode qcom_linux_cpu_stop(struct QcPerfRequest *request) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_SUCCESS; + enum QThreadReturnCode thread_ret = RET_QTHREAD_JOIN_FAILED; + + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Stopping qcom-linux-cpu data collection"); + + if (NULL == request) { + ret = QC_PERF_RETURN_CODE_NULL_POINTER; + } else { + if (g_is_thread_running) { + g_is_thread_running = false; + + thread_ret = thread_join(&g_thread_info); + if (RET_QTHREAD_JOIN_SUCCESS == thread_ret) { + thread_ret = thread_destroy(&g_thread_info); + if (RET_QTHREAD_DESTROY_SUCCESS == thread_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "CPU collection thread stopped successfully"); + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to destroy CPU collection thread handle"); + ret = QC_PERF_RETURN_CODE_FAILED; + } + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to join CPU collection thread"); + ret = QC_PERF_RETURN_CODE_FAILED; + } + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "CPU collection thread is not running"); + } + } + + return ret; +} + +/** + * @brief Deinitialize the qcom-linux-cpu backend + * + * Frees all allocated memory and resets global state. + * + * @return QC_PERF_RETURN_CODE_SUCCESS always + */ +static enum QcPerfReturnCode qcom_linux_cpu_deinit(void) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Deinitializing qcom-linux-cpu backend"); + qcom_linux_cpu_free(); + g_data_callback = NULL; + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "qcom-linux-cpu backend deinitialized successfully"); + return QC_PERF_RETURN_CODE_SUCCESS; +} + +/* ============================================================================ + * Data Collection Thread + * ============================================================================ */ + +/** + * @brief Thread function for collecting CPU performance metrics + * @param[in] param Pointer to QcPerfRequest structure + * @return NULL on completion + */ +static void *qcom_linux_cpu_collect_data(void *param) { + struct QcPerfRequest *request = (struct QcPerfRequest *)param; + struct QcPerfData *data = NULL; + struct QcomLinuxCpuLoadInfo *load_prev = NULL; + struct QcomLinuxCpuLoadInfo *load_curr = NULL; + struct QcomLinuxCpuSample *samples = NULL; + + /* System topology — read once at thread start */ + uint32_t num_cores = 0; + uint32_t cpu_capacity[QCOM_LINUX_CPU_MAX_CORES] = {0}; + uint32_t total_capacity = 0; + + uint32_t total_metric_count = 0; + uint32_t samples_per_stream = 0; + uint32_t total_responses = 0; + uint32_t sample_count = 0; + uint32_t position = 0; + uint32_t core_id = 0; + uint64_t current_time = 0; + uint64_t last_stream_time = 0; + uint64_t streaming_rate_ns = 0; + uint64_t elapsed_ns = 0; + double delta_total = 0.0; + double delta_idle = 0.0; + double delta_steal = 0.0; + double total_utilization = 0.0; + double total_eff_utilization = 0.0; + double capacity_factor = 0.0; + enum QcPerfReturnCode stat_ret = QC_PERF_RETURN_CODE_FAILED; + enum QcPerfReturnCode dcvs_ret = QC_PERF_RETURN_CODE_FAILED; + + g_is_thread_running = true; + + if (NULL == request) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Request parameter is NULL in collection thread"); + g_is_thread_running = false; + } else { + /* Read stable system topology once at thread start */ + if (QC_PERF_RETURN_CODE_SUCCESS != qcom_linux_cpu_util_get_num_cores(&num_cores)) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to read CPU core count in collection thread"); + g_is_thread_running = false; + } else if (num_cores > QCOM_LINUX_CPU_MAX_CORES) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "CPU core count %u exceeds maximum in collection thread", num_cores); + g_is_thread_running = false; + } else if (QC_PERF_RETURN_CODE_SUCCESS != qcom_linux_cpu_util_get_total_capacity(&total_capacity)) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to read CPU capacity in collection thread"); + g_is_thread_running = false; + } else { + /* Populate per-core capacity array using qcom_linux_cpu_util_get_core_capacity */ + for (core_id = 0; core_id < num_cores; core_id++) { + (void)qcom_linux_cpu_util_get_core_capacity(core_id, &cpu_capacity[core_id]); + } + + total_metric_count = (uint32_t)g_backend_info.capabilities_list[0].metric_ids_list_len; + streaming_rate_ns = (uint64_t)request->streaming_rate * 1000000ULL; + samples_per_stream = (request->streaming_rate + request->sampling_rate - 1U) / request->sampling_rate; + total_responses = samples_per_stream * total_metric_count; + + load_prev = (struct QcomLinuxCpuLoadInfo *)calloc(num_cores, sizeof(struct QcomLinuxCpuLoadInfo)); + load_curr = (struct QcomLinuxCpuLoadInfo *)calloc(num_cores, sizeof(struct QcomLinuxCpuLoadInfo)); + samples = (struct QcomLinuxCpuSample *)calloc(num_cores, sizeof(struct QcomLinuxCpuSample)); + + if (NULL == load_prev || NULL == load_curr || NULL == samples) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to allocate CPU load info buffers"); + g_is_thread_running = false; + } else { + data = (struct QcPerfData *)calloc(1, sizeof(struct QcPerfData)); + if (NULL == data) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to allocate QcPerfData structure"); + g_is_thread_running = false; + } else { + data->metric_response = (struct QcPerfMetricResponse *)calloc(total_responses, sizeof(struct QcPerfMetricResponse)); + if (NULL == data->metric_response) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to allocate metric response array"); + g_is_thread_running = false; + } else { + data->backend_id = QC_PERF_BACKEND_QCOM_LINUX_CPU; + data->capabilityId = request->capability_id; + data->metric_response_len = 0; + + (void)get_time_ns(&last_stream_time); + + while (g_is_thread_running) { + /* First /proc/stat snapshot */ + stat_ret = qcom_linux_cpu_util_get_proc_stat(load_prev, num_cores); + if (QC_PERF_RETURN_CODE_SUCCESS != stat_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to read /proc/stat (first snapshot)"); + } + + /* Sleep for the sampling interval */ + usleep((unsigned int)((uint32_t)request->sampling_rate * (uint32_t)QCOM_LINUX_CPU_MS_TO_US)); + + if (!g_is_thread_running) { + break; + } + + /* Second /proc/stat snapshot */ + stat_ret = qcom_linux_cpu_util_get_proc_stat(load_curr, num_cores); + if (QC_PERF_RETURN_CODE_SUCCESS != stat_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to read /proc/stat (second snapshot)"); + } + + (void)get_time_ns(¤t_time); + + total_utilization = 0.0; + total_eff_utilization = 0.0; + + /* Compute per-core metrics and accumulate capacity-weighted totals */ + for (core_id = 0; core_id < num_cores; core_id++) { + delta_total = load_curr[core_id].total_time - load_prev[core_id].total_time; + delta_idle = load_curr[core_id].idle - load_prev[core_id].idle; + delta_steal = load_curr[core_id].steal_time - load_prev[core_id].steal_time; + + if (delta_total > 0.0) { + samples[core_id].utilization = fabs(((delta_total - delta_idle) / delta_total) * 100.0); + samples[core_id].steal_time = fabs((delta_steal / delta_total) * 100.0); + samples[core_id].eff_utilization = fabs(((delta_total - delta_idle - delta_steal) / delta_total) * 100.0); + } else { + samples[core_id].utilization = 0.0; + samples[core_id].steal_time = 0.0; + samples[core_id].eff_utilization = 0.0; + } + + (void)qcom_linux_cpu_util_get_core_frequency(core_id, &samples[core_id].frequency); + + if (0U != total_capacity) { + capacity_factor = (double)cpu_capacity[core_id] / (double)total_capacity; + total_utilization += samples[core_id].utilization * capacity_factor; + total_eff_utilization += samples[core_id].eff_utilization * capacity_factor; + } + } + + /* -------------------------------------------------- */ + /* Fill total metric responses first (IDs 0-1) */ + /* -------------------------------------------------- */ + + /* Total CPU Load */ + if (position < total_responses) { + data->metric_response[position].metric_id = QCOM_LINUX_CPU_TOTAL_LOAD_ID; + data->metric_response[position].timestamp = current_time; + data->metric_response[position].metric_value.data_type = QC_PERF_DATA_TYPE_DOUBLE; + data->metric_response[position].metric_value.double_value = total_utilization; + position++; + } + + /* Total CPU Effective Utilization */ + if (position < total_responses) { + data->metric_response[position].metric_id = QCOM_LINUX_CPU_TOTAL_EFF_UTIL_ID; + data->metric_response[position].timestamp = current_time; + data->metric_response[position].metric_value.data_type = QC_PERF_DATA_TYPE_DOUBLE; + data->metric_response[position].metric_value.double_value = total_eff_utilization; + position++; + } + + /* -------------------------------------------------- */ + /* Fill per-core metric responses */ + /* -------------------------------------------------- */ + + for (core_id = 0; (core_id < num_cores) && (position < total_responses); core_id++) { + /* CPU Core Load */ + data->metric_response[position].metric_id = QCOM_LINUX_CPU_CORE_BASE_ID(core_id); + data->metric_response[position].timestamp = current_time; + data->metric_response[position].metric_value.data_type = QC_PERF_DATA_TYPE_DOUBLE; + data->metric_response[position].metric_value.double_value = samples[core_id].utilization; + position++; + + /* CPU Core Frequency */ + if (position < total_responses) { + data->metric_response[position].metric_id = QCOM_LINUX_CPU_CORE_BASE_ID(core_id) + QCOM_LINUX_CPU_FREQ_OFFSET; + data->metric_response[position].timestamp = current_time; + data->metric_response[position].metric_value.data_type = QC_PERF_DATA_TYPE_DOUBLE; + data->metric_response[position].metric_value.double_value = samples[core_id].frequency; + position++; + } + + /* CPU Core Steal Time */ + if (position < total_responses) { + data->metric_response[position].metric_id = QCOM_LINUX_CPU_CORE_BASE_ID(core_id) + QCOM_LINUX_CPU_STEAL_TIME_OFFSET; + data->metric_response[position].timestamp = current_time; + data->metric_response[position].metric_value.data_type = QC_PERF_DATA_TYPE_DOUBLE; + data->metric_response[position].metric_value.double_value = samples[core_id].steal_time; + position++; + } + + /* CPU Core Effective Utilization */ + if (position < total_responses) { + data->metric_response[position].metric_id = QCOM_LINUX_CPU_CORE_BASE_ID(core_id) + QCOM_LINUX_CPU_EFF_UTIL_OFFSET; + data->metric_response[position].timestamp = current_time; + data->metric_response[position].metric_value.data_type = QC_PERF_DATA_TYPE_DOUBLE; + data->metric_response[position].metric_value.double_value = samples[core_id].eff_utilization; + position++; + } + + dcvs_ret = qcom_linux_cpu_util_get_dcvs_limit(core_id, &samples[core_id].dcvs_limit); + if (dcvs_ret == QC_PERF_RETURN_CODE_SUCCESS && (position < total_responses)) { + data->metric_response[position].metric_id = QCOM_LINUX_CPU_CORE_BASE_ID(core_id) + QCOM_LINUX_CPU_DCVS_LIMIT_OFFSET; + data->metric_response[position].timestamp = current_time; + data->metric_response[position].metric_value.data_type = QC_PERF_DATA_TYPE_UINT64; + data->metric_response[position].metric_value.uint64_value = (uint64_t)samples[core_id].dcvs_limit; + position++; + } + } + + sample_count++; + + /* Check if it is time to deliver data to the callback */ + elapsed_ns = current_time - last_stream_time; + if ((sample_count >= samples_per_stream) || (elapsed_ns >= streaming_rate_ns)) { + if ((NULL != g_data_callback) && (position > 0U)) { + data->metric_response_len = position; + g_data_callback(data); + } + /* Reset for next streaming window */ + position = 0; + sample_count = 0; + last_stream_time = current_time; + } + } + + free(data->metric_response); + data->metric_response = NULL; + } + free(data); + data = NULL; + } + } + + if (NULL != load_prev) { + free(load_prev); + load_prev = NULL; + } + if (NULL != load_curr) { + free(load_curr); + load_curr = NULL; + } + if (NULL != samples) { + free(samples); + samples = NULL; + } + } + } + + g_is_thread_running = false; + return NULL; +} + +/* ============================================================================ + * Backend Creation Entry Point + * ============================================================================ */ + +/** + * @brief Create and configure the qcom-linux-cpu backend + * + * Populates the backend private structure with function pointers for all + * required backend operations. + * + * @param[in,out] backend Pointer to the backend private structure to configure + * @return QC_PERF_RETURN_CODE_SUCCESS on success + * @return QC_PERF_RETURN_CODE_NULL_POINTER if backend is NULL + */ +enum QcPerfReturnCode qcperf_qcom_linux_cpu_create(struct QcPerfBackendPrivate *backend) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_SUCCESS; + + if (NULL == backend) { + ret = QC_PERF_RETURN_CODE_NULL_POINTER; + } else { + backend->set_message_callback = qcom_linux_cpu_set_message_callback; + backend->qcperf_backend_init = qcom_linux_cpu_init; + backend->qcperf_backend_info = qcom_linux_cpu_backend_info; + backend->set_data_callback = qcom_linux_cpu_set_data_callback; + backend->qcperf_backend_start = qcom_linux_cpu_start; + backend->qcperf_backend_stop = qcom_linux_cpu_stop; + backend->qcperf_backend_deinit = qcom_linux_cpu_deinit; + } + + return ret; +} diff --git a/qcperf/backends/qcom-linux-cpu/src/qcom_linux_cpu_info.c b/qcperf/backends/qcom-linux-cpu/src/qcom_linux_cpu_info.c new file mode 100644 index 0000000..a11d1ff --- /dev/null +++ b/qcperf/backends/qcom-linux-cpu/src/qcom_linux_cpu_info.c @@ -0,0 +1,172 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file qcom_linux_cpu_info.c + * @brief Metric initialization implementation for qcom-linux-cpu backend + * @author Himanshu Keshri (hkeshri@qti.qualcomm.com) + */ + +#include +#include + +#include "qcom_linux_cpu_info.h" +#include "qcom_linux_cpu_utils.h" + +/* ============================================================================ + * Metric name format strings + * ============================================================================ */ + +#define QCOM_LINUX_CPU_METRIC_LOAD_NAME_FMT "CPU Core %u Load" +#define QCOM_LINUX_CPU_METRIC_FREQ_NAME_FMT "CPU Core %u Frequency" +#define QCOM_LINUX_CPU_METRIC_STEAL_TIME_NAME_FMT "CPU Core %u Steal Time" +#define QCOM_LINUX_CPU_METRIC_EFF_UTIL_NAME_FMT "CPU Core %u Effective Utilization" +#define QCOM_LINUX_CPU_METRIC_DCVS_LIMIT_NAME_FMT "CPU Core %u DCVS Frequency Limit" +#define QCOM_LINUX_CPU_METRIC_TOTAL_LOAD_NAME "Total CPU Load" +#define QCOM_LINUX_CPU_METRIC_TOTAL_EFF_UTIL_NAME "Total CPU Effective Utilization" + +/* ============================================================================ + * Metric description format strings + * ============================================================================ */ + +#define QCOM_LINUX_CPU_METRIC_LOAD_DESC_FMT "CPU utilization percentage for core %u" +#define QCOM_LINUX_CPU_METRIC_FREQ_DESC_FMT "Current CPU frequency in MHz for core %u" +#define QCOM_LINUX_CPU_METRIC_STEAL_TIME_DESC_FMT "CPU steal time percentage for core %u" +#define QCOM_LINUX_CPU_METRIC_EFF_UTIL_DESC_FMT "Effective CPU utilization percentage for core %u" +#define QCOM_LINUX_CPU_METRIC_DCVS_LIMIT_DESC_FMT "DCVS frequency limit in Hz for core %u" +#define QCOM_LINUX_CPU_METRIC_TOTAL_LOAD_DESC "Weighted total CPU utilization percentage across all cores" +#define QCOM_LINUX_CPU_METRIC_TOTAL_EFF_UTIL_DESC "Weighted total effective CPU utilization percentage across all cores" + +/* ============================================================================ + * Metric unit strings + * ============================================================================ */ + +#define QCOM_LINUX_CPU_METRIC_LOAD_UNIT "%%" +#define QCOM_LINUX_CPU_METRIC_FREQ_UNIT "MHz" +#define QCOM_LINUX_CPU_METRIC_STEAL_TIME_UNIT "%%" +#define QCOM_LINUX_CPU_METRIC_EFF_UTIL_UNIT "%%" +#define QCOM_LINUX_CPU_METRIC_DCVS_LIMIT_UNIT "Hz" +#define QCOM_LINUX_CPU_METRIC_TOTAL_LOAD_UNIT "%%" +#define QCOM_LINUX_CPU_METRIC_TOTAL_EFF_UTIL_UNIT "%%" + +enum QcPerfReturnCode qcom_linux_cpu_init_metrics(struct QcPerfMetricInfo *metrics_data, uint8_t *metric_data_len) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_SUCCESS; + uint32_t num_cores = 0; + uint32_t core_id = 0; + uint32_t metric_idx = 0; + uint32_t dcvs_limit_probe = 0U; + + ret = qcom_linux_cpu_util_get_num_cores(&num_cores); + if (QC_PERF_RETURN_CODE_SUCCESS == ret) { + /* ------------------------------------------------------------------ */ + /* Total metrics (IDs 0-1) — placed first */ + /* ------------------------------------------------------------------ */ + + /* Total CPU Load */ + metrics_data[metric_idx].metric_id = QCOM_LINUX_CPU_TOTAL_LOAD_ID; + snprintf(metrics_data[metric_idx].metric_name, METRIC_NAME_MAX_LEN, "%s", QCOM_LINUX_CPU_METRIC_TOTAL_LOAD_NAME); + metrics_data[metric_idx].metric_name_len = strlen(metrics_data[metric_idx].metric_name); + snprintf(metrics_data[metric_idx].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", QCOM_LINUX_CPU_METRIC_TOTAL_LOAD_DESC); + metrics_data[metric_idx].metric_description_len = strlen(metrics_data[metric_idx].metric_description); + snprintf(metrics_data[metric_idx].metric_unit, MAX_METRIC_UNIT_LEN, "%s", QCOM_LINUX_CPU_METRIC_TOTAL_LOAD_UNIT); + metrics_data[metric_idx].metric_unit_len = strlen(metrics_data[metric_idx].metric_unit); + metric_idx++; + + /* Total CPU Effective Utilization */ + metrics_data[metric_idx].metric_id = QCOM_LINUX_CPU_TOTAL_EFF_UTIL_ID; + snprintf(metrics_data[metric_idx].metric_name, METRIC_NAME_MAX_LEN, "%s", QCOM_LINUX_CPU_METRIC_TOTAL_EFF_UTIL_NAME); + metrics_data[metric_idx].metric_name_len = strlen(metrics_data[metric_idx].metric_name); + snprintf(metrics_data[metric_idx].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", QCOM_LINUX_CPU_METRIC_TOTAL_EFF_UTIL_DESC); + metrics_data[metric_idx].metric_description_len = strlen(metrics_data[metric_idx].metric_description); + snprintf(metrics_data[metric_idx].metric_unit, MAX_METRIC_UNIT_LEN, "%s", QCOM_LINUX_CPU_METRIC_TOTAL_EFF_UTIL_UNIT); + metrics_data[metric_idx].metric_unit_len = strlen(metrics_data[metric_idx].metric_unit); + metric_idx++; + + /* ------------------------------------------------------------------ */ + /* Per-core metrics — IDs from static lookup table */ + /* ------------------------------------------------------------------ */ + + for (core_id = 0; core_id < num_cores && core_id < QCOM_LINUX_CPU_MAX_CORES; core_id++) { + /* CPU Core Load */ + metrics_data[metric_idx].metric_id = QCOM_LINUX_CPU_CORE_BASE_ID(core_id); + snprintf(metrics_data[metric_idx].metric_name, METRIC_NAME_MAX_LEN, QCOM_LINUX_CPU_METRIC_LOAD_NAME_FMT, core_id); + metrics_data[metric_idx].metric_name_len = strlen(metrics_data[metric_idx].metric_name); + snprintf(metrics_data[metric_idx].metric_description, MAX_METRIC_DESCRIPTION_LEN, QCOM_LINUX_CPU_METRIC_LOAD_DESC_FMT, core_id); + metrics_data[metric_idx].metric_description_len = strlen(metrics_data[metric_idx].metric_description); + snprintf(metrics_data[metric_idx].metric_unit, MAX_METRIC_UNIT_LEN, "%s", QCOM_LINUX_CPU_METRIC_LOAD_UNIT); + metrics_data[metric_idx].metric_unit_len = strlen(metrics_data[metric_idx].metric_unit); + metric_idx++; + + /* CPU Core Frequency */ + metrics_data[metric_idx].metric_id = QCOM_LINUX_CPU_CORE_BASE_ID(core_id) + QCOM_LINUX_CPU_FREQ_OFFSET; + snprintf(metrics_data[metric_idx].metric_name, METRIC_NAME_MAX_LEN, QCOM_LINUX_CPU_METRIC_FREQ_NAME_FMT, core_id); + metrics_data[metric_idx].metric_name_len = strlen(metrics_data[metric_idx].metric_name); + snprintf(metrics_data[metric_idx].metric_description, MAX_METRIC_DESCRIPTION_LEN, QCOM_LINUX_CPU_METRIC_FREQ_DESC_FMT, core_id); + metrics_data[metric_idx].metric_description_len = strlen(metrics_data[metric_idx].metric_description); + snprintf(metrics_data[metric_idx].metric_unit, MAX_METRIC_UNIT_LEN, "%s", QCOM_LINUX_CPU_METRIC_FREQ_UNIT); + metrics_data[metric_idx].metric_unit_len = strlen(metrics_data[metric_idx].metric_unit); + metric_idx++; + + /* CPU Core Steal Time */ + metrics_data[metric_idx].metric_id = QCOM_LINUX_CPU_CORE_BASE_ID(core_id) + QCOM_LINUX_CPU_STEAL_TIME_OFFSET; + snprintf(metrics_data[metric_idx].metric_name, METRIC_NAME_MAX_LEN, QCOM_LINUX_CPU_METRIC_STEAL_TIME_NAME_FMT, core_id); + metrics_data[metric_idx].metric_name_len = strlen(metrics_data[metric_idx].metric_name); + snprintf(metrics_data[metric_idx].metric_description, MAX_METRIC_DESCRIPTION_LEN, QCOM_LINUX_CPU_METRIC_STEAL_TIME_DESC_FMT, core_id); + metrics_data[metric_idx].metric_description_len = strlen(metrics_data[metric_idx].metric_description); + snprintf(metrics_data[metric_idx].metric_unit, MAX_METRIC_UNIT_LEN, "%s", QCOM_LINUX_CPU_METRIC_STEAL_TIME_UNIT); + metrics_data[metric_idx].metric_unit_len = strlen(metrics_data[metric_idx].metric_unit); + metric_idx++; + + /* CPU Core Effective Utilization */ + metrics_data[metric_idx].metric_id = QCOM_LINUX_CPU_CORE_BASE_ID(core_id) + QCOM_LINUX_CPU_EFF_UTIL_OFFSET; + snprintf(metrics_data[metric_idx].metric_name, METRIC_NAME_MAX_LEN, QCOM_LINUX_CPU_METRIC_EFF_UTIL_NAME_FMT, core_id); + metrics_data[metric_idx].metric_name_len = strlen(metrics_data[metric_idx].metric_name); + snprintf(metrics_data[metric_idx].metric_description, MAX_METRIC_DESCRIPTION_LEN, QCOM_LINUX_CPU_METRIC_EFF_UTIL_DESC_FMT, core_id); + metrics_data[metric_idx].metric_description_len = strlen(metrics_data[metric_idx].metric_description); + snprintf(metrics_data[metric_idx].metric_unit, MAX_METRIC_UNIT_LEN, "%s", QCOM_LINUX_CPU_METRIC_EFF_UTIL_UNIT); + metrics_data[metric_idx].metric_unit_len = strlen(metrics_data[metric_idx].metric_unit); + metric_idx++; + + if (QC_PERF_RETURN_CODE_SUCCESS == qcom_linux_cpu_util_get_dcvs_limit(core_id, &dcvs_limit_probe)) { + metrics_data[metric_idx].metric_id = QCOM_LINUX_CPU_CORE_BASE_ID(core_id) + QCOM_LINUX_CPU_DCVS_LIMIT_OFFSET; + snprintf(metrics_data[metric_idx].metric_name, METRIC_NAME_MAX_LEN, QCOM_LINUX_CPU_METRIC_DCVS_LIMIT_NAME_FMT, core_id); + metrics_data[metric_idx].metric_name_len = strlen(metrics_data[metric_idx].metric_name); + snprintf(metrics_data[metric_idx].metric_description, MAX_METRIC_DESCRIPTION_LEN, QCOM_LINUX_CPU_METRIC_DCVS_LIMIT_DESC_FMT, core_id); + metrics_data[metric_idx].metric_description_len = strlen(metrics_data[metric_idx].metric_description); + snprintf(metrics_data[metric_idx].metric_unit, MAX_METRIC_UNIT_LEN, "%s", QCOM_LINUX_CPU_METRIC_DCVS_LIMIT_UNIT); + metrics_data[metric_idx].metric_unit_len = strlen(metrics_data[metric_idx].metric_unit); + metric_idx++; + } + } + + *metric_data_len = (uint8_t)metric_idx; + } + + return ret; +} diff --git a/qcperf/backends/qcom-linux-cpu/src/qcom_linux_cpu_utils.c b/qcperf/backends/qcom-linux-cpu/src/qcom_linux_cpu_utils.c new file mode 100644 index 0000000..aeb695e --- /dev/null +++ b/qcperf/backends/qcom-linux-cpu/src/qcom_linux_cpu_utils.c @@ -0,0 +1,190 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file qcom_linux_cpu_utils.c + * @brief Sysfs/procfs utility function implementations for the qcom-linux-cpu backend + * @author Himanshu Keshri (hkeshri@qti.qualcomm.com) + * + * This file implements the internal utility functions used to read CPU + * topology, capacity, frequency, load, and DCVS limits from sysfs and + * procfs. These utilities are shared between qcom_linux_cpu.c and + * qcom_linux_cpu_info.c. + */ + +#include +#include +#include + +#include "qcom_linux_cpu_utils.h" + +enum QcPerfReturnCode qcom_linux_cpu_util_get_num_cores(uint32_t *num_cores) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_FAILED; + FILE *fp = NULL; + uint32_t last_core = 0; + + fp = fopen(QCOM_LINUX_CPU_COUNT_NODE, "r"); + if (NULL != fp) { + if (fscanf(fp, "%*u-%u", &last_core) == 1) { + *num_cores = last_core + 1U; + ret = QC_PERF_RETURN_CODE_SUCCESS; + } + fclose(fp); + } + + return ret; +} + +enum QcPerfReturnCode qcom_linux_cpu_util_get_core_capacity(uint32_t core_id, uint32_t *capacity) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_FAILED; + char path[QCOM_LINUX_CPU_NODE_PATH_MAX_LEN]; + FILE *fp = NULL; + + snprintf(path, sizeof(path), QCOM_LINUX_CPU_CAPACITY_NODE_FMT, core_id); + fp = fopen(path, "r"); + if (NULL != fp) { + if (fscanf(fp, "%u", capacity) == 1) { + ret = QC_PERF_RETURN_CODE_SUCCESS; + } + fclose(fp); + } + + return ret; +} + +enum QcPerfReturnCode qcom_linux_cpu_util_get_total_capacity(uint32_t *total_capacity) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_FAILED; + uint32_t num_cores = 0; + uint32_t core = 0; + uint32_t cap = 0; + + *total_capacity = 0U; + + ret = qcom_linux_cpu_util_get_num_cores(&num_cores); + if (QC_PERF_RETURN_CODE_SUCCESS == ret) { + for (core = 0; core < num_cores; core++) { + ret = qcom_linux_cpu_util_get_core_capacity(core, &cap); + if (QC_PERF_RETURN_CODE_SUCCESS != ret) { + break; + } + *total_capacity += cap; + } + } + + if ((QC_PERF_RETURN_CODE_SUCCESS == ret) && (0U == *total_capacity)) { + ret = QC_PERF_RETURN_CODE_FAILED; + } + + return ret; +} + +enum QcPerfReturnCode qcom_linux_cpu_util_get_proc_stat(struct QcomLinuxCpuLoadInfo *load_info, uint32_t num_cores) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_FAILED; + FILE *fp = NULL; + char line[QCOM_LINUX_CPU_STAT_LINE_MAX_LEN]; + uint32_t core_id = 0; + uint32_t cores_read = 0; + double user = 0.0; + double nice = 0.0; + double system = 0.0; + double idle = 0.0; + double iowait = 0.0; + double irq = 0.0; + double softirq = 0.0; + double steal = 0.0; + double guest = 0.0; + double guest_nice = 0.0; + int scan_count = 0; + + fp = fopen(QCOM_LINUX_CPU_STAT_NODE, "r"); + if (NULL != fp) { + /* Skip the aggregate "cpu" line */ + if (NULL != fgets(line, sizeof(line), fp)) { + while ((NULL != fgets(line, sizeof(line), fp)) && (cores_read < num_cores)) { + scan_count = sscanf(line, "cpu%u %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", &core_id, &user, &nice, &system, &idle, &iowait, &irq, &softirq, &steal, &guest, &guest_nice); + if ((QCOM_LINUX_CPU_STAT_FIELD_COUNT == scan_count) && (core_id < num_cores)) { + load_info[core_id].idle = idle + iowait; + load_info[core_id].total_time = user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice; + load_info[core_id].steal_time = steal; + cores_read++; + } + } + if (cores_read > 0U) { + ret = QC_PERF_RETURN_CODE_SUCCESS; + } + } + fclose(fp); + } + + return ret; +} + +enum QcPerfReturnCode qcom_linux_cpu_util_get_core_frequency(uint32_t core_id, double *frequency_mhz) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_FAILED; + char path[QCOM_LINUX_CPU_NODE_PATH_MAX_LEN]; + FILE *fp = NULL; + long freq_khz = 0; + + snprintf(path, sizeof(path), QCOM_LINUX_CPU_FREQ_NODE_FMT, core_id); + fp = fopen(path, "r"); + if (NULL == fp) { + *frequency_mhz = 0.0; + } else { + if (fscanf(fp, "%ld", &freq_khz) == 1) { + *frequency_mhz = (double)freq_khz / (double)QCOM_LINUX_CPU_KHZ_TO_MHZ; + ret = QC_PERF_RETURN_CODE_SUCCESS; + } else { + *frequency_mhz = 0.0; + } + fclose(fp); + } + + return ret; +} + +enum QcPerfReturnCode qcom_linux_cpu_util_get_dcvs_limit(uint32_t core_id, uint32_t *dcvs_limit) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_FAILED; + char path[QCOM_LINUX_CPU_NODE_PATH_MAX_LEN]; + FILE *fp = NULL; + + snprintf(path, sizeof(path), QCOM_LINUX_CPU_DCVS_NODE_FMT, core_id); + fp = fopen(path, "r"); + if (NULL != fp) { + if (fscanf(fp, "%u", dcvs_limit) == 1) { + ret = QC_PERF_RETURN_CODE_SUCCESS; + } else { + *dcvs_limit = 0U; + } + fclose(fp); + } else { + *dcvs_limit = 0U; + } + + return ret; +} diff --git a/qcperf/backends/utils/wos/cpu-thermal-etw/inc/thermal_common.h b/qcperf/backends/utils/wos/cpu-thermal-etw/inc/thermal_common.h index e7d74da..b189c9e 100644 --- a/qcperf/backends/utils/wos/cpu-thermal-etw/inc/thermal_common.h +++ b/qcperf/backends/utils/wos/cpu-thermal-etw/inc/thermal_common.h @@ -93,11 +93,11 @@ extern "C" { #endif -#include "qthread.h" -#include "qmutex.h" -#include "qsleep.h" -#include "qcv.h" -#include "qlist.h" +#include "QThread.h" +#include "QMutex.h" +#include "QSleep.h" +#include "QCv.h" +#include "QList.h" /** * @brief GUID for ACPI thermal provider diff --git a/qcperf/backends/wos-power-backend/CMakeLists.txt b/qcperf/backends/wos-power-backend/CMakeLists.txt index 501705c..b71a1e3 100644 --- a/qcperf/backends/wos-power-backend/CMakeLists.txt +++ b/qcperf/backends/wos-power-backend/CMakeLists.txt @@ -14,6 +14,8 @@ # # This backend is only built for Windows ARM64 platforms. +message("Added wos-power-backend backend") + add_library(QcPerfWosPowerBackend STATIC src/wos_power_backend.c ${CMAKE_SOURCE_DIR}/backends/utils/wos/ioctl/src/wos_ioctl.c diff --git a/qcperf/backends/wos-power-backend/power-telemetry/CMakeLists.txt b/qcperf/backends/wos-power-backend/power-telemetry/CMakeLists.txt index 3287df6..1a3fe4c 100644 --- a/qcperf/backends/wos-power-backend/power-telemetry/CMakeLists.txt +++ b/qcperf/backends/wos-power-backend/power-telemetry/CMakeLists.txt @@ -30,6 +30,4 @@ target_include_directories(QcWosPowerTelemetry PUBLIC ${CMAKE_SOURCE_DIR}/backends/wos-power-backend/power-telemetry/inc/ ${CMAKE_SOURCE_DIR}/core/inc/ ${CMAKE_SOURCE_DIR}/backends/utils/wos/ioctl/inc/ - ${CMAKE_SOURCE_DIR}/backends/utils/wos/pep/inc/ - ) diff --git a/qcperf/backends/wos-power-backend/power-telemetry/inc/power_telemetry.h b/qcperf/backends/wos-power-backend/power-telemetry/inc/power_telemetry.h index f4eaa0f..dbf71d0 100644 --- a/qcperf/backends/wos-power-backend/power-telemetry/inc/power_telemetry.h +++ b/qcperf/backends/wos-power-backend/power-telemetry/inc/power_telemetry.h @@ -142,4 +142,4 @@ enum ePowerTelemetryReturnCode powerTelemetry_railsGetInfo(struct RailsInfoRespo */ enum ePowerTelemetryReturnCode powerTelemetry_railsDestroy(); -#endif // POWER_TELEMETRY_H +#endif // POWER_TELEMETRY_H \ No newline at end of file diff --git a/qcperf/backends/wos-power-backend/power-telemetry/src/power_telemetry.c b/qcperf/backends/wos-power-backend/power-telemetry/src/power_telemetry.c index 9694e7e..30e4b55 100644 --- a/qcperf/backends/wos-power-backend/power-telemetry/src/power_telemetry.c +++ b/qcperf/backends/wos-power-backend/power-telemetry/src/power_telemetry.c @@ -322,4 +322,4 @@ enum ePowerTelemetryReturnCode powerTelemetry_railsDestroy() { g_rails_initialized = false; } return status; -} +} \ No newline at end of file diff --git a/qcperf/backends/wos-power-backend/src/wos_power_backend.c b/qcperf/backends/wos-power-backend/src/wos_power_backend.c index 91dab59..20b68a0 100644 --- a/qcperf/backends/wos-power-backend/src/wos_power_backend.c +++ b/qcperf/backends/wos-power-backend/src/wos_power_backend.c @@ -49,7 +49,7 @@ #endif #include "power_telemetry.h" -#include "qthread.h" +#include "QThread.h" #include "qtime.h" #include "wos_power_backend.h" #include "wos_power_backend_logger.h" @@ -698,4 +698,4 @@ enum QcPerfReturnCode wos_power_backend_create(struct QcPerfBackendPrivate* back } return return_code; -} +} \ No newline at end of file diff --git a/qcperf/backends/wos-thermal/CMakeLists.txt b/qcperf/backends/wos-thermal/CMakeLists.txt index c4349ed..dded4f9 100644 --- a/qcperf/backends/wos-thermal/CMakeLists.txt +++ b/qcperf/backends/wos-thermal/CMakeLists.txt @@ -1,35 +1,37 @@ -# Windows OS Thermal Backend CMake configuration -# Builds the Windows-specific thermal monitoring backend for QcPerf - -cmake_minimum_required(VERSION 3.13.5) - -# Main thermal backend library -add_library(QcPerfWosThermalBackend STATIC - src/wos_thermal.c # Main thermal backend implementation - src/wos_thermal_info.c # Thermal information provider - src/wos_thermal_lib.c # Thermal library utilities - src/wos_thermal_logger.c # Thermal logging functionality -) - -# Include directories for thermal backend -target_include_directories(QcPerfWosThermalBackend PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/inc # Local includes - ${CMAKE_SOURCE_DIR}/core/inc # Core QcPerf includes - ${CMAKE_SOURCE_DIR}/core/inc/internal # Internal QcPerf includes - ${CMAKE_SOURCE_DIR}/backends/inc # Backend common includes - ${CMAKE_SOURCE_DIR}/backends/utils/wos/ioctl/inc # Windows IOCTL utilities - ${CMAKE_SOURCE_DIR}/utils/qthread/inc # Thread utilities - ${CMAKE_SOURCE_DIR}/utils/qtime/inc # Time utilities -) - -# Link with required libraries -target_link_libraries(QcPerfWosThermalBackend PUBLIC - QcPerfQThread # Thread utilities - WosUtilIoctl # Windows IOCTL utilities - Cfgmgr32.lib # Windows Configuration Manager library - tdh.lib # Windows Trace Data Helper library - QcPerfWosCpuThermalEtw # CPU thermal ETW monitoring - QcPerfWosPassiveCooling # Passive cooling monitoring - QcPerfWosThermalEtwCommon # Common thermal ETW utilities - QcPerfQTime # Time utilities -) +# Windows OS Thermal Backend CMake configuration +# Builds the Windows-specific thermal monitoring backend for QcPerf + +cmake_minimum_required(VERSION 3.13.5) + +message("Added wos-thermal backend") + +# Main thermal backend library +add_library(QcPerfWosThermalBackend STATIC + src/wos_thermal.c # Main thermal backend implementation + src/wos_thermal_info.c # Thermal information provider + src/wos_thermal_lib.c # Thermal library utilities + src/wos_thermal_logger.c # Thermal logging functionality +) + +# Include directories for thermal backend +target_include_directories(QcPerfWosThermalBackend PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/inc # Local includes + ${CMAKE_SOURCE_DIR}/core/inc # Core QcPerf includes + ${CMAKE_SOURCE_DIR}/core/inc/internal # Internal QcPerf includes + ${CMAKE_SOURCE_DIR}/backends/inc # Backend common includes + ${CMAKE_SOURCE_DIR}/backends/utils/wos/ioctl/inc # Windows IOCTL utilities + ${CMAKE_SOURCE_DIR}/utils/qthread/inc # Thread utilities + ${CMAKE_SOURCE_DIR}/utils/qtime/inc # Time utilities +) + +# Link with required libraries +target_link_libraries(QcPerfWosThermalBackend PUBLIC + QcPerfQThread # Thread utilities + WosUtilIoctl # Windows IOCTL utilities + Cfgmgr32.lib # Windows Configuration Manager library + tdh.lib # Windows Trace Data Helper library + QcPerfWosCpuThermalEtw # CPU thermal ETW monitoring + QcPerfWosPassiveCooling # Passive cooling monitoring + QcPerfWosThermalEtwCommon # Common thermal ETW utilities + QcPerfQTime # Time utilities +) diff --git a/qcperf/backends/wos-thermal/inc/wos_thermal.h b/qcperf/backends/wos-thermal/inc/wos_thermal.h index 10de7c6..372f40d 100644 --- a/qcperf/backends/wos-thermal/inc/wos_thermal.h +++ b/qcperf/backends/wos-thermal/inc/wos_thermal.h @@ -1,65 +1,65 @@ -/* - Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - Redistribution and use in source and binary forms, with or without - modification, are permitted (subject to the limitations in the - disclaimer below) provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Qualcomm Technologies, Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE - GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT - HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/** - * @file wos_thermal.h - * @brief WOS Thermal backend interface for libqcperf - * @author Skand Gupta (skangupt@qti.qualcomm.com) - * - * This header provides the public interface for the WOS (Windows on Snapdragon) - * Thermal backend, which monitors temperature and passive cooling metrics for - * various thermal zones. This backend interfaces with the Windows thermal - * monitoring subsystem to collect real-time temperature data and passive - * cooling states. - */ - -#ifndef WOS_THERMAL_H -#define WOS_THERMAL_H - -#include "wos_thermal_info.h" - -struct QcPerfBackendPrivate; - -/** - * @brief Create and initialize the WOS Thermal backend - * - * This function configures the WOS Thermal backend by populating the backend - * private structure with function pointers for all required backend - * operations including initialization, start, stop, deinitialization, - * and callback registration. The backend provides temperature and passive cooling - * monitoring for various thermal zones. - * - * @param[in,out] backend Pointer to backend private structure to be configured - * - * @return QC_PERF_RETURN_CODE_SUCCESS on successful creation - * @return QC_PERF_RETURN_CODE_NULL_POINTER if backend pointer is NULL - */ -enum QcPerfReturnCode qcperf_wos_thermal_backend_create(struct QcPerfBackendPrivate* backend); - -#endif // WOS_THERMAL_H +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file wos_thermal.h + * @brief WOS Thermal backend interface for libqcperf + * @author Skand Gupta (skangupt@qti.qualcomm.com) + * + * This header provides the public interface for the WOS (Windows on Snapdragon) + * Thermal backend, which monitors temperature and passive cooling metrics for + * various thermal zones. This backend interfaces with the Windows thermal + * monitoring subsystem to collect real-time temperature data and passive + * cooling states. + */ + +#ifndef WOS_THERMAL_H +#define WOS_THERMAL_H + +#include "wos_thermal_info.h" + +struct QcPerfBackendPrivate; + +/** + * @brief Create and initialize the WOS Thermal backend + * + * This function configures the WOS Thermal backend by populating the backend + * private structure with function pointers for all required backend + * operations including initialization, start, stop, deinitialization, + * and callback registration. The backend provides temperature and passive cooling + * monitoring for various thermal zones. + * + * @param[in,out] backend Pointer to backend private structure to be configured + * + * @return QC_PERF_RETURN_CODE_SUCCESS on successful creation + * @return QC_PERF_RETURN_CODE_NULL_POINTER if backend pointer is NULL + */ +enum QcPerfReturnCode qcperf_wos_thermal_backend_create(struct QcPerfBackendPrivate* backend); + +#endif // WOS_THERMAL_H diff --git a/qcperf/backends/wos-thermal/inc/wos_thermal_info.h b/qcperf/backends/wos-thermal/inc/wos_thermal_info.h index c729607..0f6db62 100644 --- a/qcperf/backends/wos-thermal/inc/wos_thermal_info.h +++ b/qcperf/backends/wos-thermal/inc/wos_thermal_info.h @@ -1,454 +1,454 @@ -/* - Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - Redistribution and use in source and binary forms, with or without - modification, are permitted (subject to the limitations in the - disclaimer below) provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Qualcomm Technologies, Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE - GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT - HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/** - * @file wos_thermal_info.h - * @brief Static metric definitions and initialization functions for WOS Thermal backend - * @author Skand Gupta (skangupt@qti.qualcomm.com) - * - * This header defines all metric IDs, names, descriptions, and units for the - * WOS Thermal backend's capabilities. It includes definitions for temperature - * and passive cooling metrics for various thermal zones, and provides initialization - * functions to populate metric information structures with these static definitions. - */ - -#ifndef WOS_THERMAL_INFO_H -#define WOS_THERMAL_INFO_H - -#include "qcperf_common.h" - -#define WOS_THERMAL_CAPABILITY_ID 0 -#define WOS_THERMAL_CAPABILITIES_LEN 1 - -#define WOS_THERMAL_STREAMING_RATES_LEN 2 -#define WOS_THERMAL_STREAMING_RATES 200, 1000 - -#define WOS_THERMAL_SAMPLING_RATES_LEN 2 -#define WOS_THERMAL_SAMPLING_RATES 50, 100 - -#define WOS_THERMAL_CAPABILITY "thermal" -#define WOS_THERMAL_CAPABILITY_METRIC_COUNT 44 // 22 thermal zones * 2 metrics (temperature and passive cooling) - -/** - * @enum WosThermalMetricIndex - * @brief Array indices for WOS Thermal metrics - * @author Skand Gupta (skangupt@qti.qualcomm.com) - * This enum defines the array indices for accessing metrics in the - * metrics_data array, providing better code readability and maintainability. - * For each thermal zone, index 2n is for temperature and index 2n+1 is for passive cooling. - */ -enum WosThermalMetricIndex { - // CPU Cluster 0 Thermal Zone - WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP = 0, - WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING, - - // CPU Cluster 1 Thermal Zone - WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP, - WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING, - - // CPU Cluster 2 Thermal Zone - WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP, - WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING, - - // QMX0 Thermal Zone - WOS_THERMAL_METRIC_INDEX_QMX0_TEMP, - WOS_THERMAL_METRIC_INDEX_QMX0_COOLING, - - // QMX1 Thermal Zone - WOS_THERMAL_METRIC_INDEX_QMX1_TEMP, - WOS_THERMAL_METRIC_INDEX_QMX1_COOLING, - - // QMX2 Thermal Zone - WOS_THERMAL_METRIC_INDEX_QMX2_TEMP, - WOS_THERMAL_METRIC_INDEX_QMX2_COOLING, - - // GPU Thermal Zone - WOS_THERMAL_METRIC_INDEX_GPU_TEMP, - WOS_THERMAL_METRIC_INDEX_GPU_COOLING, - - // NSP Thermal Zone - WOS_THERMAL_METRIC_INDEX_NSP_TEMP, - WOS_THERMAL_METRIC_INDEX_NSP_COOLING, - - // QCLimitsPolicy CPU coreparking - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP, - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING, - - // QCLimitsPolicy CPU DCVS All Clusters - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP, - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING, - - // QCLimitsPolicy CPU DCVS Cluster0 - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP, - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING, - - // QCLimitsPolicy CPU DCVS Cluster1 - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP, - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING, - - // QCLimitsPolicy CPU DCVS Cluster2 - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP, - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING, - - // QCLimitsPolicy GPU - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP, - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING, - - // QCLimitsPolicy NSP - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP, - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING, - - // QCLimitsPolicy Modem BCL - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP, - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING, - - // QCLimitsPolicy Modem Skin - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP, - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING, - - // QCLimitsPolicy WLAN - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP, - WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING, - - // Critical Thermal Zones for All Internal TSENS - WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP, - WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING, - - // EC thermistor 1 - WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP, - WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING, - - // EC thermistor 2 - WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP, - WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING, - - // EC thermistor 3 - WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP, - WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING -}; - -// CPU Cluster 0 Thermal Zone -#define WOS_THERMAL_METRIC_CPU_CLUSTER_0_ZONE_NAME "CPU Cluster 0 Thermal Zone" -#define WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_ID 0 -#define WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_NAME "Zone id : 0 CPU Cluster 0 Thermal Zone Temperature" -#define WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_DESCRIPTION "Temperature of CPU Cluster 0 Thermal Zone" -#define WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_ID 1 -#define WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_NAME "Zone id : 0 CPU Cluster 0 Thermal Zone Passive Cooling" -#define WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_DESCRIPTION "Passive Cooling of CPU Cluster 0 Thermal Zone" -#define WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_UNIT "%" - -// CPU Cluster 1 Thermal Zone -#define WOS_THERMAL_METRIC_CPU_CLUSTER_1_ZONE_NAME "CPU Cluster 1 Thermal Zone" -#define WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_ID 2 -#define WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_NAME "Zone id : 1 CPU Cluster 1 Thermal Zone Temperature" -#define WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_DESCRIPTION "Temperature of CPU Cluster 1 Thermal Zone" -#define WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_ID 3 -#define WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_NAME "Zone id : 1 CPU Cluster 1 Thermal Zone Passive Cooling" -#define WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_DESCRIPTION "Passive Cooling of CPU Cluster 1 Thermal Zone" -#define WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_UNIT "%" - -// CPU Cluster 2 Thermal Zone -#define WOS_THERMAL_METRIC_CPU_CLUSTER_2_ZONE_NAME "CPU Cluster 2 Thermal Zone" -#define WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_ID 4 -#define WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_NAME "Zone id : 2 CPU Cluster 2 Thermal Zone Temperature" -#define WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_DESCRIPTION "Temperature of CPU Cluster 2 Thermal Zone" -#define WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_ID 5 -#define WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_NAME "Zone id : 2 CPU Cluster 2 Thermal Zone Passive Cooling" -#define WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_DESCRIPTION "Passive Cooling of CPU Cluster 2 Thermal Zone" -#define WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_UNIT "%" - -// QMX0 Thermal Zone -#define WOS_THERMAL_METRIC_QMX0_ZONE_NAME "QMX0 Thermal Zone" -#define WOS_THERMAL_METRIC_QMX0_TEMP_ID 6 -#define WOS_THERMAL_METRIC_QMX0_TEMP_NAME "Zone id : 3 QMX0 Thermal Zone Temperature" -#define WOS_THERMAL_METRIC_QMX0_TEMP_DESCRIPTION "Temperature of QMX0 Thermal Zone" -#define WOS_THERMAL_METRIC_QMX0_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_QMX0_COOLING_ID 7 -#define WOS_THERMAL_METRIC_QMX0_COOLING_NAME "Zone id : 3 QMX0 Thermal Zone Passive Cooling" -#define WOS_THERMAL_METRIC_QMX0_COOLING_DESCRIPTION "Passive Cooling of QMX0 Thermal Zone" -#define WOS_THERMAL_METRIC_QMX0_COOLING_UNIT "%" - -// QMX1 Thermal Zone -#define WOS_THERMAL_METRIC_QMX1_ZONE_NAME "QMX1 Thermal Zone" -#define WOS_THERMAL_METRIC_QMX1_TEMP_ID 8 -#define WOS_THERMAL_METRIC_QMX1_TEMP_NAME "Zone id : 4 QMX1 Thermal Zone Temperature" -#define WOS_THERMAL_METRIC_QMX1_TEMP_DESCRIPTION "Temperature of QMX1 Thermal Zone" -#define WOS_THERMAL_METRIC_QMX1_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_QMX1_COOLING_ID 9 -#define WOS_THERMAL_METRIC_QMX1_COOLING_NAME "Zone id : 4 QMX1 Thermal Zone Passive Cooling" -#define WOS_THERMAL_METRIC_QMX1_COOLING_DESCRIPTION "Passive Cooling of QMX1 Thermal Zone" -#define WOS_THERMAL_METRIC_QMX1_COOLING_UNIT "%" - -// QMX2 Thermal Zone -#define WOS_THERMAL_METRIC_QMX2_ZONE_NAME "QMX2 Thermal Zone" -#define WOS_THERMAL_METRIC_QMX2_TEMP_ID 10 -#define WOS_THERMAL_METRIC_QMX2_TEMP_NAME "Zone id : 5 QMX2 Thermal Zone Temperature" -#define WOS_THERMAL_METRIC_QMX2_TEMP_DESCRIPTION "Temperature of QMX2 Thermal Zone" -#define WOS_THERMAL_METRIC_QMX2_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_QMX2_COOLING_ID 11 -#define WOS_THERMAL_METRIC_QMX2_COOLING_NAME "Zone id : 5 QMX2 Thermal Zone Passive Cooling" -#define WOS_THERMAL_METRIC_QMX2_COOLING_DESCRIPTION "Passive Cooling of QMX2 Thermal Zone" -#define WOS_THERMAL_METRIC_QMX2_COOLING_UNIT "%" - -// GPU Thermal Zone -#define WOS_THERMAL_METRIC_GPU_ZONE_NAME "GPU Thermal Zone" -#define WOS_THERMAL_METRIC_GPU_TEMP_ID 12 -#define WOS_THERMAL_METRIC_GPU_TEMP_NAME "Zone id : 6 GPU Thermal Zone Temperature" -#define WOS_THERMAL_METRIC_GPU_TEMP_DESCRIPTION "Temperature of GPU Thermal Zone" -#define WOS_THERMAL_METRIC_GPU_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_GPU_COOLING_ID 13 -#define WOS_THERMAL_METRIC_GPU_COOLING_NAME "Zone id : 6 GPU Thermal Zone Passive Cooling" -#define WOS_THERMAL_METRIC_GPU_COOLING_DESCRIPTION "Passive Cooling of GPU Thermal Zone" -#define WOS_THERMAL_METRIC_GPU_COOLING_UNIT "%" - -// NSP Thermal Zone -#define WOS_THERMAL_METRIC_NSP_ZONE_NAME "NSP Thermal Zone" -#define WOS_THERMAL_METRIC_NSP_TEMP_ID 14 -#define WOS_THERMAL_METRIC_NSP_TEMP_NAME "Zone id : 11 NSP Thermal Zone Temperature" -#define WOS_THERMAL_METRIC_NSP_TEMP_DESCRIPTION "Temperature of NSP Thermal Zone" -#define WOS_THERMAL_METRIC_NSP_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_NSP_COOLING_ID 15 -#define WOS_THERMAL_METRIC_NSP_COOLING_NAME "Zone id : 11 NSP Thermal Zone Passive Cooling" -#define WOS_THERMAL_METRIC_NSP_COOLING_DESCRIPTION "Passive Cooling of NSP Thermal Zone" -#define WOS_THERMAL_METRIC_NSP_COOLING_UNIT "%" - -// QCLimitsPolicy CPU coreparking -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_ZONE_NAME "QCLimitsPolicy CPU coreparking" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_ID 16 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_NAME "Zone id : 15 QCLimitsPolicy CPU coreparking Temperature" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy CPU coreparking" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_ID 17 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_NAME "Zone id : 15 QCLimitsPolicy CPU coreparking Passive Cooling" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy CPU coreparking" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_UNIT "%" - -// QCLimitsPolicy CPU DCVS All Clusters -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_ZONE_NAME "QCLimitsPolicy CPU DCVS All Clusters" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_ID 18 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_NAME "Zone id : 16 QCLimitsPolicy CPU DCVS All Clusters Temperature" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy CPU DCVS All Clusters" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_ID 19 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_NAME "Zone id : 16 QCLimitsPolicy CPU DCVS All Clusters Passive Cooling" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy CPU DCVS All Clusters" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_UNIT "%" - -// QCLimitsPolicy CPU DCVS Cluster0 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_ZONE_NAME "QCLimitsPolicy CPU DCVS Cluster0" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_ID 20 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_NAME "Zone id : 17 QCLimitsPolicy CPU DCVS Cluster0 Temperature" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy CPU DCVS Cluster0" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_ID 21 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_NAME "Zone id : 17 QCLimitsPolicy CPU DCVS Cluster0 Passive Cooling" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy CPU DCVS Cluster0" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_UNIT "%" - -// QCLimitsPolicy CPU DCVS Cluster1 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_ZONE_NAME "QCLimitsPolicy CPU DCVS Cluster1" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_ID 22 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_NAME "Zone id : 18 QCLimitsPolicy CPU DCVS Cluster1 Temperature" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy CPU DCVS Cluster1" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_ID 23 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_NAME "Zone id : 18 QCLimitsPolicy CPU DCVS Cluster1 Passive Cooling" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy CPU DCVS Cluster1" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_UNIT "%" - -// QCLimitsPolicy CPU DCVS Cluster2 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_ZONE_NAME "QCLimitsPolicy CPU DCVS Cluster2" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_ID 24 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_NAME "Zone id : 19 QCLimitsPolicy CPU DCVS Cluster2 Temperature" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy CPU DCVS Cluster2" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_ID 25 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_NAME "Zone id : 19 QCLimitsPolicy CPU DCVS Cluster2 Passive Cooling" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy CPU DCVS Cluster2" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_UNIT "%" - -// QCLimitsPolicy GPU -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_ZONE_NAME "QCLimitsPolicy GPU" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_ID 26 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_NAME "Zone id : 20 QCLimitsPolicy GPU Temperature" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy GPU" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_ID 27 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_NAME "Zone id : 20 QCLimitsPolicy GPU Passive Cooling" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy GPU" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_UNIT "%" - -// QCLimitsPolicy NSP -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_ZONE_NAME "QCLimitsPolicy NSP" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_ID 28 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_NAME "Zone id : 21 QCLimitsPolicy NSP Temperature" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy NSP" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_ID 29 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_NAME "Zone id : 21 QCLimitsPolicy NSP Passive Cooling" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy NSP" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_UNIT "%" - -// QCLimitsPolicy Modem BCL -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_ZONE_NAME "QCLimitsPolicy Modem BCL" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_ID 30 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_NAME "Zone id : 22 QCLimitsPolicy Modem BCL Temperature" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy Modem BCL" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_ID 31 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_NAME "Zone id : 22 QCLimitsPolicy Modem BCL Passive Cooling" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy Modem BCL" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_UNIT "%" - -// QCLimitsPolicy Modem Skin -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_ZONE_NAME "QCLimitsPolicy Modem Skin" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_ID 32 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_NAME "Zone id : 23 QCLimitsPolicy Modem Skin Temperature" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy Modem Skin" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_ID 33 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_NAME "Zone id : 23 QCLimitsPolicy Modem Skin Passive Cooling" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy Modem Skin" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_UNIT "%" - -// QCLimitsPolicy WLAN -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_ZONE_NAME "QCLimitsPolicy WLAN" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_ID 34 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_NAME "Zone id : 24 QCLimitsPolicy WLAN Temperature" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy WLAN" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_ID 35 -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_NAME "Zone id : 24 QCLimitsPolicy WLAN Passive Cooling" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy WLAN" -#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_UNIT "%" - -// Critical Thermal Zones for All Internal TSENS -#define WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_ZONE_NAME "Critical Thermal Zones" -#define WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_ID 36 -#define WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_NAME "Zone id : 99 Critical Thermal Zones for All Internal TSENS Temperature" -#define WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_DESCRIPTION "Temperature of Critical Thermal Zones for All Internal TSENS" -#define WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_ID 37 -#define WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_NAME "Zone id : 99 Critical Thermal Zones for All Internal TSENS Passive Cooling" -#define WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_DESCRIPTION "Passive Cooling of Critical Thermal Zones for All Internal TSENS" -#define WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_UNIT "%" - -// EC thermistor 1 -#define WOS_THERMAL_METRIC_EC_THERMISTOR_1_ZONE_NAME "EC thermistor 1" -#define WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_ID 38 -#define WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_NAME "Zone id : 31 EC thermistor 1 Temperature" -#define WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_DESCRIPTION "Temperature of EC thermistor 1" -#define WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_ID 39 -#define WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_NAME "Zone id : 31 EC thermistor 1 Passive Cooling" -#define WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_DESCRIPTION "Passive Cooling of EC thermistor 1" -#define WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_UNIT "%" - -// EC thermistor 2 -#define WOS_THERMAL_METRIC_EC_THERMISTOR_2_ZONE_NAME "EC thermistor 2" -#define WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_ID 40 -#define WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_NAME "Zone id : 32 EC thermistor 2 Temperature" -#define WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_DESCRIPTION "Temperature of EC thermistor 2" -#define WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_ID 41 -#define WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_NAME "Zone id : 32 EC thermistor 2 Passive Cooling" -#define WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_DESCRIPTION "Passive Cooling of EC thermistor 2" -#define WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_UNIT "%" - -// EC thermistor 3 -#define WOS_THERMAL_METRIC_EC_THERMISTOR_3_ZONE_NAME "EC thermistor 3" -#define WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_ID 42 -#define WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_NAME "Zone id : 33 EC thermistor 3 Temperature" -#define WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_DESCRIPTION "Temperature of EC thermistor 3" -#define WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_UNIT "deg C" - -#define WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_ID 43 -#define WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_NAME "Zone id : 33 EC thermistor 3 Passive Cooling" -#define WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_DESCRIPTION "Passive Cooling of EC thermistor 3" -#define WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_UNIT "%" - -/** - * @brief Initialize WOS Thermal metrics data - * - * Populates the provided metrics_data array with metric information for - * the WOS Thermal capability, including metric IDs, names, descriptions, - * and units for all temperature and passive cooling metrics. - * - * @param[out] metrics_data Array to be populated with WOS Thermal metric information - * (must have space for WOS_THERMAL_CAPABILITY_METRIC_COUNT entries) - */ -void wos_thermal_capability_init_metrics(struct QcPerfMetricInfo* metrics_data); - -/** - * @brief Initialize WOS Thermal metrics data for available zones - * - * This function queries the available thermal zones and initializes metrics - * only for those zones that are actually present on the system. - * - * @param[out] metrics_data Array to be populated with WOS Thermal metric information - * @param[out] metric_count Pointer to store the number of metrics initialized - * @return WOS_THERMAL_INFO_SUCCESS on success, error code otherwise - */ -void wos_thermal_capability_init_available_metrics(struct QcPerfMetricInfo* metrics_data, uint8_t* metric_count); - -/** - * @brief Get metric index for a thermal zone and metric type - * - * @param[in] zone_id ID of the thermal zone - * @param[in] is_cooling Whether to get the cooling metric (true) or temperature metric (false) - * @param[out] metric_index Pointer to store the metric index - * @return WOS_THERMAL_INFO_SUCCESS on success, error code otherwise - */ -void wos_thermal_get_metric_index(uint8_t zone_id, bool is_cooling, uint16_t* metric_index); - -#endif /* WOS_THERMAL_INFO_H */ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file wos_thermal_info.h + * @brief Static metric definitions and initialization functions for WOS Thermal backend + * @author Skand Gupta (skangupt@qti.qualcomm.com) + * + * This header defines all metric IDs, names, descriptions, and units for the + * WOS Thermal backend's capabilities. It includes definitions for temperature + * and passive cooling metrics for various thermal zones, and provides initialization + * functions to populate metric information structures with these static definitions. + */ + +#ifndef WOS_THERMAL_INFO_H +#define WOS_THERMAL_INFO_H + +#include "qcperf_common.h" + +#define WOS_THERMAL_CAPABILITY_ID 0 +#define WOS_THERMAL_CAPABILITIES_LEN 1 + +#define WOS_THERMAL_STREAMING_RATES_LEN 2 +#define WOS_THERMAL_STREAMING_RATES 200, 1000 + +#define WOS_THERMAL_SAMPLING_RATES_LEN 2 +#define WOS_THERMAL_SAMPLING_RATES 50, 100 + +#define WOS_THERMAL_CAPABILITY "thermal" +#define WOS_THERMAL_CAPABILITY_METRIC_COUNT 44 // 22 thermal zones * 2 metrics (temperature and passive cooling) + +/** + * @enum WosThermalMetricIndex + * @brief Array indices for WOS Thermal metrics + * @author Skand Gupta (skangupt@qti.qualcomm.com) + * This enum defines the array indices for accessing metrics in the + * metrics_data array, providing better code readability and maintainability. + * For each thermal zone, index 2n is for temperature and index 2n+1 is for passive cooling. + */ +enum WosThermalMetricIndex { + // CPU Cluster 0 Thermal Zone + WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP = 0, + WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING, + + // CPU Cluster 1 Thermal Zone + WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP, + WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING, + + // CPU Cluster 2 Thermal Zone + WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP, + WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING, + + // QMX0 Thermal Zone + WOS_THERMAL_METRIC_INDEX_QMX0_TEMP, + WOS_THERMAL_METRIC_INDEX_QMX0_COOLING, + + // QMX1 Thermal Zone + WOS_THERMAL_METRIC_INDEX_QMX1_TEMP, + WOS_THERMAL_METRIC_INDEX_QMX1_COOLING, + + // QMX2 Thermal Zone + WOS_THERMAL_METRIC_INDEX_QMX2_TEMP, + WOS_THERMAL_METRIC_INDEX_QMX2_COOLING, + + // GPU Thermal Zone + WOS_THERMAL_METRIC_INDEX_GPU_TEMP, + WOS_THERMAL_METRIC_INDEX_GPU_COOLING, + + // NSP Thermal Zone + WOS_THERMAL_METRIC_INDEX_NSP_TEMP, + WOS_THERMAL_METRIC_INDEX_NSP_COOLING, + + // QCLimitsPolicy CPU coreparking + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP, + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING, + + // QCLimitsPolicy CPU DCVS All Clusters + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP, + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING, + + // QCLimitsPolicy CPU DCVS Cluster0 + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP, + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING, + + // QCLimitsPolicy CPU DCVS Cluster1 + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP, + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING, + + // QCLimitsPolicy CPU DCVS Cluster2 + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP, + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING, + + // QCLimitsPolicy GPU + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP, + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING, + + // QCLimitsPolicy NSP + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP, + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING, + + // QCLimitsPolicy Modem BCL + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP, + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING, + + // QCLimitsPolicy Modem Skin + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP, + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING, + + // QCLimitsPolicy WLAN + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP, + WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING, + + // Critical Thermal Zones for All Internal TSENS + WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP, + WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING, + + // EC thermistor 1 + WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP, + WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING, + + // EC thermistor 2 + WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP, + WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING, + + // EC thermistor 3 + WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP, + WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING +}; + +// CPU Cluster 0 Thermal Zone +#define WOS_THERMAL_METRIC_CPU_CLUSTER_0_ZONE_NAME "CPU Cluster 0 Thermal Zone" +#define WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_ID 0 +#define WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_NAME "Zone id : 0 CPU Cluster 0 Thermal Zone Temperature" +#define WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_DESCRIPTION "Temperature of CPU Cluster 0 Thermal Zone" +#define WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_ID 1 +#define WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_NAME "Zone id : 0 CPU Cluster 0 Thermal Zone Passive Cooling" +#define WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_DESCRIPTION "Passive Cooling of CPU Cluster 0 Thermal Zone" +#define WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_UNIT "%" + +// CPU Cluster 1 Thermal Zone +#define WOS_THERMAL_METRIC_CPU_CLUSTER_1_ZONE_NAME "CPU Cluster 1 Thermal Zone" +#define WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_ID 2 +#define WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_NAME "Zone id : 1 CPU Cluster 1 Thermal Zone Temperature" +#define WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_DESCRIPTION "Temperature of CPU Cluster 1 Thermal Zone" +#define WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_ID 3 +#define WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_NAME "Zone id : 1 CPU Cluster 1 Thermal Zone Passive Cooling" +#define WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_DESCRIPTION "Passive Cooling of CPU Cluster 1 Thermal Zone" +#define WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_UNIT "%" + +// CPU Cluster 2 Thermal Zone +#define WOS_THERMAL_METRIC_CPU_CLUSTER_2_ZONE_NAME "CPU Cluster 2 Thermal Zone" +#define WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_ID 4 +#define WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_NAME "Zone id : 2 CPU Cluster 2 Thermal Zone Temperature" +#define WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_DESCRIPTION "Temperature of CPU Cluster 2 Thermal Zone" +#define WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_ID 5 +#define WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_NAME "Zone id : 2 CPU Cluster 2 Thermal Zone Passive Cooling" +#define WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_DESCRIPTION "Passive Cooling of CPU Cluster 2 Thermal Zone" +#define WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_UNIT "%" + +// QMX0 Thermal Zone +#define WOS_THERMAL_METRIC_QMX0_ZONE_NAME "QMX0 Thermal Zone" +#define WOS_THERMAL_METRIC_QMX0_TEMP_ID 6 +#define WOS_THERMAL_METRIC_QMX0_TEMP_NAME "Zone id : 3 QMX0 Thermal Zone Temperature" +#define WOS_THERMAL_METRIC_QMX0_TEMP_DESCRIPTION "Temperature of QMX0 Thermal Zone" +#define WOS_THERMAL_METRIC_QMX0_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_QMX0_COOLING_ID 7 +#define WOS_THERMAL_METRIC_QMX0_COOLING_NAME "Zone id : 3 QMX0 Thermal Zone Passive Cooling" +#define WOS_THERMAL_METRIC_QMX0_COOLING_DESCRIPTION "Passive Cooling of QMX0 Thermal Zone" +#define WOS_THERMAL_METRIC_QMX0_COOLING_UNIT "%" + +// QMX1 Thermal Zone +#define WOS_THERMAL_METRIC_QMX1_ZONE_NAME "QMX1 Thermal Zone" +#define WOS_THERMAL_METRIC_QMX1_TEMP_ID 8 +#define WOS_THERMAL_METRIC_QMX1_TEMP_NAME "Zone id : 4 QMX1 Thermal Zone Temperature" +#define WOS_THERMAL_METRIC_QMX1_TEMP_DESCRIPTION "Temperature of QMX1 Thermal Zone" +#define WOS_THERMAL_METRIC_QMX1_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_QMX1_COOLING_ID 9 +#define WOS_THERMAL_METRIC_QMX1_COOLING_NAME "Zone id : 4 QMX1 Thermal Zone Passive Cooling" +#define WOS_THERMAL_METRIC_QMX1_COOLING_DESCRIPTION "Passive Cooling of QMX1 Thermal Zone" +#define WOS_THERMAL_METRIC_QMX1_COOLING_UNIT "%" + +// QMX2 Thermal Zone +#define WOS_THERMAL_METRIC_QMX2_ZONE_NAME "QMX2 Thermal Zone" +#define WOS_THERMAL_METRIC_QMX2_TEMP_ID 10 +#define WOS_THERMAL_METRIC_QMX2_TEMP_NAME "Zone id : 5 QMX2 Thermal Zone Temperature" +#define WOS_THERMAL_METRIC_QMX2_TEMP_DESCRIPTION "Temperature of QMX2 Thermal Zone" +#define WOS_THERMAL_METRIC_QMX2_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_QMX2_COOLING_ID 11 +#define WOS_THERMAL_METRIC_QMX2_COOLING_NAME "Zone id : 5 QMX2 Thermal Zone Passive Cooling" +#define WOS_THERMAL_METRIC_QMX2_COOLING_DESCRIPTION "Passive Cooling of QMX2 Thermal Zone" +#define WOS_THERMAL_METRIC_QMX2_COOLING_UNIT "%" + +// GPU Thermal Zone +#define WOS_THERMAL_METRIC_GPU_ZONE_NAME "GPU Thermal Zone" +#define WOS_THERMAL_METRIC_GPU_TEMP_ID 12 +#define WOS_THERMAL_METRIC_GPU_TEMP_NAME "Zone id : 6 GPU Thermal Zone Temperature" +#define WOS_THERMAL_METRIC_GPU_TEMP_DESCRIPTION "Temperature of GPU Thermal Zone" +#define WOS_THERMAL_METRIC_GPU_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_GPU_COOLING_ID 13 +#define WOS_THERMAL_METRIC_GPU_COOLING_NAME "Zone id : 6 GPU Thermal Zone Passive Cooling" +#define WOS_THERMAL_METRIC_GPU_COOLING_DESCRIPTION "Passive Cooling of GPU Thermal Zone" +#define WOS_THERMAL_METRIC_GPU_COOLING_UNIT "%" + +// NSP Thermal Zone +#define WOS_THERMAL_METRIC_NSP_ZONE_NAME "NSP Thermal Zone" +#define WOS_THERMAL_METRIC_NSP_TEMP_ID 14 +#define WOS_THERMAL_METRIC_NSP_TEMP_NAME "Zone id : 11 NSP Thermal Zone Temperature" +#define WOS_THERMAL_METRIC_NSP_TEMP_DESCRIPTION "Temperature of NSP Thermal Zone" +#define WOS_THERMAL_METRIC_NSP_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_NSP_COOLING_ID 15 +#define WOS_THERMAL_METRIC_NSP_COOLING_NAME "Zone id : 11 NSP Thermal Zone Passive Cooling" +#define WOS_THERMAL_METRIC_NSP_COOLING_DESCRIPTION "Passive Cooling of NSP Thermal Zone" +#define WOS_THERMAL_METRIC_NSP_COOLING_UNIT "%" + +// QCLimitsPolicy CPU coreparking +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_ZONE_NAME "QCLimitsPolicy CPU coreparking" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_ID 16 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_NAME "Zone id : 15 QCLimitsPolicy CPU coreparking Temperature" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy CPU coreparking" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_ID 17 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_NAME "Zone id : 15 QCLimitsPolicy CPU coreparking Passive Cooling" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy CPU coreparking" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_UNIT "%" + +// QCLimitsPolicy CPU DCVS All Clusters +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_ZONE_NAME "QCLimitsPolicy CPU DCVS All Clusters" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_ID 18 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_NAME "Zone id : 16 QCLimitsPolicy CPU DCVS All Clusters Temperature" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy CPU DCVS All Clusters" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_ID 19 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_NAME "Zone id : 16 QCLimitsPolicy CPU DCVS All Clusters Passive Cooling" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy CPU DCVS All Clusters" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_UNIT "%" + +// QCLimitsPolicy CPU DCVS Cluster0 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_ZONE_NAME "QCLimitsPolicy CPU DCVS Cluster0" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_ID 20 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_NAME "Zone id : 17 QCLimitsPolicy CPU DCVS Cluster0 Temperature" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy CPU DCVS Cluster0" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_ID 21 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_NAME "Zone id : 17 QCLimitsPolicy CPU DCVS Cluster0 Passive Cooling" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy CPU DCVS Cluster0" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_UNIT "%" + +// QCLimitsPolicy CPU DCVS Cluster1 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_ZONE_NAME "QCLimitsPolicy CPU DCVS Cluster1" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_ID 22 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_NAME "Zone id : 18 QCLimitsPolicy CPU DCVS Cluster1 Temperature" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy CPU DCVS Cluster1" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_ID 23 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_NAME "Zone id : 18 QCLimitsPolicy CPU DCVS Cluster1 Passive Cooling" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy CPU DCVS Cluster1" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_UNIT "%" + +// QCLimitsPolicy CPU DCVS Cluster2 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_ZONE_NAME "QCLimitsPolicy CPU DCVS Cluster2" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_ID 24 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_NAME "Zone id : 19 QCLimitsPolicy CPU DCVS Cluster2 Temperature" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy CPU DCVS Cluster2" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_ID 25 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_NAME "Zone id : 19 QCLimitsPolicy CPU DCVS Cluster2 Passive Cooling" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy CPU DCVS Cluster2" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_UNIT "%" + +// QCLimitsPolicy GPU +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_ZONE_NAME "QCLimitsPolicy GPU" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_ID 26 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_NAME "Zone id : 20 QCLimitsPolicy GPU Temperature" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy GPU" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_ID 27 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_NAME "Zone id : 20 QCLimitsPolicy GPU Passive Cooling" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy GPU" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_UNIT "%" + +// QCLimitsPolicy NSP +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_ZONE_NAME "QCLimitsPolicy NSP" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_ID 28 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_NAME "Zone id : 21 QCLimitsPolicy NSP Temperature" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy NSP" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_ID 29 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_NAME "Zone id : 21 QCLimitsPolicy NSP Passive Cooling" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy NSP" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_UNIT "%" + +// QCLimitsPolicy Modem BCL +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_ZONE_NAME "QCLimitsPolicy Modem BCL" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_ID 30 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_NAME "Zone id : 22 QCLimitsPolicy Modem BCL Temperature" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy Modem BCL" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_ID 31 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_NAME "Zone id : 22 QCLimitsPolicy Modem BCL Passive Cooling" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy Modem BCL" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_UNIT "%" + +// QCLimitsPolicy Modem Skin +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_ZONE_NAME "QCLimitsPolicy Modem Skin" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_ID 32 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_NAME "Zone id : 23 QCLimitsPolicy Modem Skin Temperature" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy Modem Skin" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_ID 33 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_NAME "Zone id : 23 QCLimitsPolicy Modem Skin Passive Cooling" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy Modem Skin" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_UNIT "%" + +// QCLimitsPolicy WLAN +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_ZONE_NAME "QCLimitsPolicy WLAN" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_ID 34 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_NAME "Zone id : 24 QCLimitsPolicy WLAN Temperature" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_DESCRIPTION "Temperature of QCLimitsPolicy WLAN" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_ID 35 +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_NAME "Zone id : 24 QCLimitsPolicy WLAN Passive Cooling" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_DESCRIPTION "Passive Cooling of QCLimitsPolicy WLAN" +#define WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_UNIT "%" + +// Critical Thermal Zones for All Internal TSENS +#define WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_ZONE_NAME "Critical Thermal Zones" +#define WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_ID 36 +#define WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_NAME "Zone id : 99 Critical Thermal Zones for All Internal TSENS Temperature" +#define WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_DESCRIPTION "Temperature of Critical Thermal Zones for All Internal TSENS" +#define WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_ID 37 +#define WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_NAME "Zone id : 99 Critical Thermal Zones for All Internal TSENS Passive Cooling" +#define WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_DESCRIPTION "Passive Cooling of Critical Thermal Zones for All Internal TSENS" +#define WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_UNIT "%" + +// EC thermistor 1 +#define WOS_THERMAL_METRIC_EC_THERMISTOR_1_ZONE_NAME "EC thermistor 1" +#define WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_ID 38 +#define WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_NAME "Zone id : 31 EC thermistor 1 Temperature" +#define WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_DESCRIPTION "Temperature of EC thermistor 1" +#define WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_ID 39 +#define WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_NAME "Zone id : 31 EC thermistor 1 Passive Cooling" +#define WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_DESCRIPTION "Passive Cooling of EC thermistor 1" +#define WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_UNIT "%" + +// EC thermistor 2 +#define WOS_THERMAL_METRIC_EC_THERMISTOR_2_ZONE_NAME "EC thermistor 2" +#define WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_ID 40 +#define WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_NAME "Zone id : 32 EC thermistor 2 Temperature" +#define WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_DESCRIPTION "Temperature of EC thermistor 2" +#define WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_ID 41 +#define WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_NAME "Zone id : 32 EC thermistor 2 Passive Cooling" +#define WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_DESCRIPTION "Passive Cooling of EC thermistor 2" +#define WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_UNIT "%" + +// EC thermistor 3 +#define WOS_THERMAL_METRIC_EC_THERMISTOR_3_ZONE_NAME "EC thermistor 3" +#define WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_ID 42 +#define WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_NAME "Zone id : 33 EC thermistor 3 Temperature" +#define WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_DESCRIPTION "Temperature of EC thermistor 3" +#define WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_UNIT "deg C" + +#define WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_ID 43 +#define WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_NAME "Zone id : 33 EC thermistor 3 Passive Cooling" +#define WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_DESCRIPTION "Passive Cooling of EC thermistor 3" +#define WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_UNIT "%" + +/** + * @brief Initialize WOS Thermal metrics data + * + * Populates the provided metrics_data array with metric information for + * the WOS Thermal capability, including metric IDs, names, descriptions, + * and units for all temperature and passive cooling metrics. + * + * @param[out] metrics_data Array to be populated with WOS Thermal metric information + * (must have space for WOS_THERMAL_CAPABILITY_METRIC_COUNT entries) + */ +void wos_thermal_capability_init_metrics(struct QcPerfMetricInfo* metrics_data); + +/** + * @brief Initialize WOS Thermal metrics data for available zones + * + * This function queries the available thermal zones and initializes metrics + * only for those zones that are actually present on the system. + * + * @param[out] metrics_data Array to be populated with WOS Thermal metric information + * @param[out] metric_count Pointer to store the number of metrics initialized + * @return WOS_THERMAL_INFO_SUCCESS on success, error code otherwise + */ +void wos_thermal_capability_init_available_metrics(struct QcPerfMetricInfo* metrics_data, uint8_t* metric_count); + +/** + * @brief Get metric index for a thermal zone and metric type + * + * @param[in] zone_id ID of the thermal zone + * @param[in] is_cooling Whether to get the cooling metric (true) or temperature metric (false) + * @param[out] metric_index Pointer to store the metric index + * @return WOS_THERMAL_INFO_SUCCESS on success, error code otherwise + */ +void wos_thermal_get_metric_index(uint8_t zone_id, bool is_cooling, uint16_t* metric_index); + +#endif /* WOS_THERMAL_INFO_H */ diff --git a/qcperf/backends/wos-thermal/inc/wos_thermal_lib.h b/qcperf/backends/wos-thermal/inc/wos_thermal_lib.h index f9f0f2b..409fb19 100644 --- a/qcperf/backends/wos-thermal/inc/wos_thermal_lib.h +++ b/qcperf/backends/wos-thermal/inc/wos_thermal_lib.h @@ -1,169 +1,169 @@ -/* - Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - Redistribution and use in source and binary forms, with or without - modification, are permitted (subject to the limitations in the - disclaimer below) provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Qualcomm Technologies, Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE - GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT - HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/** - * @file wos_thermal_lib.h - * @brief WOS Thermal library implementation for libqcperf - * @author Skand Gupta (skangupt@qti.qualcomm.com) - * - * This header provides the implementation for the WOS (Windows on Snapdragon) - * Thermal library, which collects temperature and passive cooling data from - * various thermal zones. It provides functions for initializing the library, - * starting and stopping data collection, and retrieving thermal information. - * - * The library uses high-precision nanosecond timestamps for all time measurements, - * providing accurate timing information for performance profiling. Sampling and - * streaming rates are specified in milliseconds but internally converted to - * nanoseconds for precise timing calculations. - */ - -#ifndef WOS_THERMAL_LIB_H -#define WOS_THERMAL_LIB_H - -#include -#include -#include "qcperf_common.h" -/** - * @def MAX_THERMAL_ZONES - * @brief Maximum number of thermal zones supported - */ -#define MAX_THERMAL_ZONES 64 - -/** - * @enum WosThermalLibReturnCode - * @brief Return codes for WOS Thermal library functions - */ -enum WosThermalLibReturnCode { - WOS_THERMAL_LIB_SUCCESS = 0, - WOS_THERMAL_LIB_ERROR_FAILED, - WOS_THERMAL_LIB_ERROR_INIT_FAILED, - WOS_THERMAL_LIB_ERROR_ALREADY_INITIALIZED, - WOS_THERMAL_LIB_ERROR_NOT_INITIALIZED, - WOS_THERMAL_LIB_ERROR_NULL_POINTER, - WOS_THERMAL_LIB_ERROR_MEMORY_ALLOCATION, - WOS_THERMAL_LIB_ERROR_INVALID_ARGUMENT, - WOS_THERMAL_LIB_ERROR_NATIVE_FUNCTION_FAILED, - WOS_THERMAL_LIB_ERROR_THREAD_CREATE_FAILED, - WOS_THERMAL_LIB_ERROR_THREAD_JOIN_FAILED, - WOS_THERMAL_LIB_ERROR_THREAD_DESTROY_FAILED, - WOS_THERMAL_LIB_ERROR_MUTEX_OPERATION_FAILED, - WOS_THERMAL_LIB_ERROR_THERMAL_SENSOR_INIT_FAILED, - WOS_THERMAL_LIB_ERROR_PASSIVE_COOLING_INIT_FAILED, - WOS_THERMAL_LIB_ERROR_THERMAL_COMMON_INIT_FAILED, - WOS_THERMAL_LIB_ERROR_GET_ZONE_NAMES_FAILED, - WOS_THERMAL_LIB_ERROR_GET_THERMAL_INFO_FAILED, - WOS_THERMAL_LIB_ERROR_GET_PASSIVE_COOLING_INFO_FAILED, - WOS_THERMAL_LIB_ERROR_THERMAL_SENSOR_CLEANUP_FAILED, - WOS_THERMAL_LIB_ERROR_PASSIVE_COOLING_CLEANUP_FAILED, - WOS_THERMAL_LIB_ERROR_THERMAL_COMMON_CLEANUP_FAILED, -}; - -/** - * @struct WosThermalZoneData - * @brief Structure to hold thermal zone data - */ -struct WosThermalZoneData { - uint8_t zone_id; /**< Thermal zone ID */ - char zone_name[64]; /**< Thermal zone name */ - size_t zone_name_length; - double temperature; /**< Temperature in Celsius */ - double passive_cooling; /**< Passive cooling percentage */ -}; - -/** - * @struct WosThermalData - * @brief Structure to hold thermal data for all zones - */ -struct WosThermalData { - struct WosThermalZoneData zones[MAX_THERMAL_ZONES]; /**< Array of thermal zone data */ - uint8_t zone_count; /**< Number of valid zones */ - uint64_t timestamp; /**< Timestamp when data was collected (in nanoseconds) */ -}; - -/** - * @typedef WosThermalDataCallback - * @brief Callback function type for thermal data updates - */ -typedef void (*WosThermalDataCallback)(struct WosThermalData* data); - -/** - * @brief Initialize the WOS Thermal library - * - * This function initializes the WOS Thermal library, including the thermal - * sensor, passive cooling, and thermal common components. - * - * @return WOS_THERMAL_LIB_SUCCESS on success - * @return Error code on failure - */ -enum WosThermalLibReturnCode wos_thermal_lib_init(void); - -/** - * @brief Clean up the WOS Thermal library - * - * This function cleans up resources used by the WOS Thermal library. - * - * @return WOS_THERMAL_LIB_SUCCESS on success - * @return Error code on failure - */ -enum WosThermalLibReturnCode wos_thermal_lib_cleanup(void); - -/** - * @brief Get the number of thermal zones - * - * This function returns the number of thermal zones available. - * - * @param[out] zone_count Pointer to store the zone count - * - * @return WOS_THERMAL_LIB_SUCCESS on success - * @return Error code on failure - */ -enum WosThermalLibReturnCode wos_thermal_lib_get_zone_count(uint8_t* zone_count); - -/** - * @brief Get thermal zone information - * - * This function returns information about all thermal zones, including - * temperature and passive cooling data. It populates the provided thermal_data - * structure with the current thermal zone information, including zone IDs, - * names, temperatures, and passive cooling percentages. - * - * The function uses the global zone name map that was populated during - * initialization to identify thermal zones and retrieve their current state. - * - * @param[out] thermal_data Pointer to store thermal zone data - * - * @return WOS_THERMAL_LIB_SUCCESS on success - * @return WOS_THERMAL_LIB_ERROR_NOT_INITIALIZED if library is not initialized - * @return WOS_THERMAL_LIB_ERROR_NULL_POINTER if thermal_data is NULL - * @return WOS_THERMAL_LIB_ERROR_GET_THERMAL_INFO_FAILED if getting thermal info fails - * @return WOS_THERMAL_LIB_ERROR_GET_PASSIVE_COOLING_INFO_FAILED if getting passive cooling info fails - */ -enum WosThermalLibReturnCode wos_thermal_lib_get_zone_info(struct WosThermalData* data); - -#endif /* WOS_THERMAL_LIB_H */ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file wos_thermal_lib.h + * @brief WOS Thermal library implementation for libqcperf + * @author Skand Gupta (skangupt@qti.qualcomm.com) + * + * This header provides the implementation for the WOS (Windows on Snapdragon) + * Thermal library, which collects temperature and passive cooling data from + * various thermal zones. It provides functions for initializing the library, + * starting and stopping data collection, and retrieving thermal information. + * + * The library uses high-precision nanosecond timestamps for all time measurements, + * providing accurate timing information for performance profiling. Sampling and + * streaming rates are specified in milliseconds but internally converted to + * nanoseconds for precise timing calculations. + */ + +#ifndef WOS_THERMAL_LIB_H +#define WOS_THERMAL_LIB_H + +#include +#include +#include "qcperf_common.h" +/** + * @def MAX_THERMAL_ZONES + * @brief Maximum number of thermal zones supported + */ +#define MAX_THERMAL_ZONES 64 + +/** + * @enum WosThermalLibReturnCode + * @brief Return codes for WOS Thermal library functions + */ +enum WosThermalLibReturnCode { + WOS_THERMAL_LIB_SUCCESS = 0, + WOS_THERMAL_LIB_ERROR_FAILED, + WOS_THERMAL_LIB_ERROR_INIT_FAILED, + WOS_THERMAL_LIB_ERROR_ALREADY_INITIALIZED, + WOS_THERMAL_LIB_ERROR_NOT_INITIALIZED, + WOS_THERMAL_LIB_ERROR_NULL_POINTER, + WOS_THERMAL_LIB_ERROR_MEMORY_ALLOCATION, + WOS_THERMAL_LIB_ERROR_INVALID_ARGUMENT, + WOS_THERMAL_LIB_ERROR_NATIVE_FUNCTION_FAILED, + WOS_THERMAL_LIB_ERROR_THREAD_CREATE_FAILED, + WOS_THERMAL_LIB_ERROR_THREAD_JOIN_FAILED, + WOS_THERMAL_LIB_ERROR_THREAD_DESTROY_FAILED, + WOS_THERMAL_LIB_ERROR_MUTEX_OPERATION_FAILED, + WOS_THERMAL_LIB_ERROR_THERMAL_SENSOR_INIT_FAILED, + WOS_THERMAL_LIB_ERROR_PASSIVE_COOLING_INIT_FAILED, + WOS_THERMAL_LIB_ERROR_THERMAL_COMMON_INIT_FAILED, + WOS_THERMAL_LIB_ERROR_GET_ZONE_NAMES_FAILED, + WOS_THERMAL_LIB_ERROR_GET_THERMAL_INFO_FAILED, + WOS_THERMAL_LIB_ERROR_GET_PASSIVE_COOLING_INFO_FAILED, + WOS_THERMAL_LIB_ERROR_THERMAL_SENSOR_CLEANUP_FAILED, + WOS_THERMAL_LIB_ERROR_PASSIVE_COOLING_CLEANUP_FAILED, + WOS_THERMAL_LIB_ERROR_THERMAL_COMMON_CLEANUP_FAILED, +}; + +/** + * @struct WosThermalZoneData + * @brief Structure to hold thermal zone data + */ +struct WosThermalZoneData { + uint8_t zone_id; /**< Thermal zone ID */ + char zone_name[64]; /**< Thermal zone name */ + size_t zone_name_length; + double temperature; /**< Temperature in Celsius */ + double passive_cooling; /**< Passive cooling percentage */ +}; + +/** + * @struct WosThermalData + * @brief Structure to hold thermal data for all zones + */ +struct WosThermalData { + struct WosThermalZoneData zones[MAX_THERMAL_ZONES]; /**< Array of thermal zone data */ + uint8_t zone_count; /**< Number of valid zones */ + uint64_t timestamp; /**< Timestamp when data was collected (in nanoseconds) */ +}; + +/** + * @typedef WosThermalDataCallback + * @brief Callback function type for thermal data updates + */ +typedef void (*WosThermalDataCallback)(struct WosThermalData* data); + +/** + * @brief Initialize the WOS Thermal library + * + * This function initializes the WOS Thermal library, including the thermal + * sensor, passive cooling, and thermal common components. + * + * @return WOS_THERMAL_LIB_SUCCESS on success + * @return Error code on failure + */ +enum WosThermalLibReturnCode wos_thermal_lib_init(void); + +/** + * @brief Clean up the WOS Thermal library + * + * This function cleans up resources used by the WOS Thermal library. + * + * @return WOS_THERMAL_LIB_SUCCESS on success + * @return Error code on failure + */ +enum WosThermalLibReturnCode wos_thermal_lib_cleanup(void); + +/** + * @brief Get the number of thermal zones + * + * This function returns the number of thermal zones available. + * + * @param[out] zone_count Pointer to store the zone count + * + * @return WOS_THERMAL_LIB_SUCCESS on success + * @return Error code on failure + */ +enum WosThermalLibReturnCode wos_thermal_lib_get_zone_count(uint8_t* zone_count); + +/** + * @brief Get thermal zone information + * + * This function returns information about all thermal zones, including + * temperature and passive cooling data. It populates the provided thermal_data + * structure with the current thermal zone information, including zone IDs, + * names, temperatures, and passive cooling percentages. + * + * The function uses the global zone name map that was populated during + * initialization to identify thermal zones and retrieve their current state. + * + * @param[out] thermal_data Pointer to store thermal zone data + * + * @return WOS_THERMAL_LIB_SUCCESS on success + * @return WOS_THERMAL_LIB_ERROR_NOT_INITIALIZED if library is not initialized + * @return WOS_THERMAL_LIB_ERROR_NULL_POINTER if thermal_data is NULL + * @return WOS_THERMAL_LIB_ERROR_GET_THERMAL_INFO_FAILED if getting thermal info fails + * @return WOS_THERMAL_LIB_ERROR_GET_PASSIVE_COOLING_INFO_FAILED if getting passive cooling info fails + */ +enum WosThermalLibReturnCode wos_thermal_lib_get_zone_info(struct WosThermalData* data); + +#endif /* WOS_THERMAL_LIB_H */ diff --git a/qcperf/backends/wos-thermal/inc/wos_thermal_logger.h b/qcperf/backends/wos-thermal/inc/wos_thermal_logger.h index 89fcfde..81e7e51 100644 --- a/qcperf/backends/wos-thermal/inc/wos_thermal_logger.h +++ b/qcperf/backends/wos-thermal/inc/wos_thermal_logger.h @@ -1,84 +1,84 @@ -/* - Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - Redistribution and use in source and binary forms, with or without - modification, are permitted (subject to the limitations in the - disclaimer below) provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Qualcomm Technologies, Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE - GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT - HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/** - * @file wos_thermal_logger.h - * @brief Logging utilities for WOS Thermal backend - * @author Skand Gupta (skangupt@qti.qualcomm.com) - * - * This header provides logging utilities for the WOS (Windows on Snapdragon) - * Thermal backend. It defines functions and macros for sending log messages - * with different severity levels to the application through a callback mechanism. - */ - -#ifndef WOS_THERMAL_LOGGER_H -#define WOS_THERMAL_LOGGER_H - -#include "qcperf_common.h" - -/** - * @def MESSAGE_LEVEL_LENGTH - * @brief Maximum length of message buffer - * - * Defines the maximum buffer size for storing log messages. - */ -#define MESSAGE_LEVEL_LENGTH 256 - -/** - * @def SEND_MESSAGE - * @brief Macro for sending log messages - * - * Convenience macro for calling wos_thermal_logger_send_message with the - * specified level and format string. - */ -#define SEND_MESSAGE(level, format, ...) wos_thermal_logger_send_message(level, format, ##__VA_ARGS__) - -/** - * @brief Set the message callback function - * - * This function sets the callback function that will be used to deliver - * log messages to the application. - * - * @param message_callback Pointer to the message callback function - */ -void wos_thermal_logger_set_message_callback(QcPerfMessageCallback message_callback); - -/** - * @brief Send a log message - * - * This function formats and sends a log message using the registered - * message callback function. - * - * @param level Severity level of the message - * @param format Format string for the message - * @param ... Variable arguments for the format string - */ -void wos_thermal_logger_send_message(enum QcPerfMessageLevel level, const char* format, ...); - -#endif /* WOS_THERMAL_LOGGER_H */ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file wos_thermal_logger.h + * @brief Logging utilities for WOS Thermal backend + * @author Skand Gupta (skangupt@qti.qualcomm.com) + * + * This header provides logging utilities for the WOS (Windows on Snapdragon) + * Thermal backend. It defines functions and macros for sending log messages + * with different severity levels to the application through a callback mechanism. + */ + +#ifndef WOS_THERMAL_LOGGER_H +#define WOS_THERMAL_LOGGER_H + +#include "qcperf_common.h" + +/** + * @def MESSAGE_LEVEL_LENGTH + * @brief Maximum length of message buffer + * + * Defines the maximum buffer size for storing log messages. + */ +#define MESSAGE_LEVEL_LENGTH 256 + +/** + * @def SEND_MESSAGE + * @brief Macro for sending log messages + * + * Convenience macro for calling wos_thermal_logger_send_message with the + * specified level and format string. + */ +#define SEND_MESSAGE(level, format, ...) wos_thermal_logger_send_message(level, format, ##__VA_ARGS__) + +/** + * @brief Set the message callback function + * + * This function sets the callback function that will be used to deliver + * log messages to the application. + * + * @param message_callback Pointer to the message callback function + */ +void wos_thermal_logger_set_message_callback(QcPerfMessageCallback message_callback); + +/** + * @brief Send a log message + * + * This function formats and sends a log message using the registered + * message callback function. + * + * @param level Severity level of the message + * @param format Format string for the message + * @param ... Variable arguments for the format string + */ +void wos_thermal_logger_send_message(enum QcPerfMessageLevel level, const char* format, ...); + +#endif /* WOS_THERMAL_LOGGER_H */ diff --git a/qcperf/backends/wos-thermal/src/wos_thermal.c b/qcperf/backends/wos-thermal/src/wos_thermal.c index 75b677e..c57fe5d 100644 --- a/qcperf/backends/wos-thermal/src/wos_thermal.c +++ b/qcperf/backends/wos-thermal/src/wos_thermal.c @@ -1,625 +1,625 @@ -/* - Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - Redistribution and use in source and binary forms, with or without - modification, are permitted (subject to the limitations in the - disclaimer below) provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Qualcomm Technologies, Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE - GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT - HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/** - * @file wos_thermal.c - * @brief Implementation of the WOS Thermal backend for libqcperf - * @author Skand Gupta (skangupt@qti.qualcomm.com) - * - * This file implements the WOS (Windows on Snapdragon) Thermal backend for - * the QcPerf library. It provides functionality for monitoring temperature - * and passive cooling metrics for various thermal zones on Windows platforms. - * - * The implementation follows the QcPerf backend interface pattern, providing - * functions for initialization, data collection, and cleanup. It interfaces - * with the WOS Thermal library to collect thermal data and delivers it to - * the application through the QcPerf callback mechanism. - */ - -#include -#include -#include -#include - -#include "wos_thermal.h" -#include "wos_thermal_lib.h" -#include "wos_thermal_logger.h" -#include "qcperf_backend_interface.h" -#include "qcperf_backend_enum.h" -#include "qthread.h" -#include "qtime.h" - -#define METRIC_PER_ZONE 2 - -// Static variables -static bool g_is_initialized = false; -static volatile bool g_is_running = false; -static QcPerfDataCallback g_data_callback = NULL; -static struct QcPerfBackendInfo g_backend_info = {0}; -static struct QThreadInfo g_thread_info = {0}; -static struct QcPerfCapabilityInfo g_capability_info = {0}; -static struct QcPerfMetricInfo g_metrics_data[WOS_THERMAL_CAPABILITY_METRIC_COUNT] = {0}; -static struct QcPerfRequest g_current_request = {0}; - -// Streaming and sampling rates -static const uint16_t g_streaming_rates[WOS_THERMAL_STREAMING_RATES_LEN] = {WOS_THERMAL_STREAMING_RATES}; -static const uint16_t g_sampling_rates[WOS_THERMAL_SAMPLING_RATES_LEN] = {WOS_THERMAL_SAMPLING_RATES}; - -/** - * @brief Thread function for collecting thermal data - * - * This function runs in a separate thread and continuously collects thermal data - * at the specified sampling rate and delivers updates via the callback at the - * specified streaming rate. It allocates memory for the QcPerfData structure and - * metric responses, collects thermal data at regular intervals, and sends batched - * updates to the registered callback. - * - * The function properly manages memory by freeing all allocated resources before - * exiting, and implements bounds checking to prevent buffer overflows. It also - * resets the metric index after each callback to ensure proper data tracking. - * - * @param[in] param Thread parameters (pointer to QcPerfRequest) - * - * @return NULL - */ -static void* thermal_data_collection_thread(void* param) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; - enum WosThermalLibReturnCode thermal_return_code = WOS_THERMAL_LIB_ERROR_FAILED; - uint32_t samples_per_stream = 0; - uint32_t sample_count = 0; - uint64_t current_time = 0; - struct QcPerfRequest* request = (struct QcPerfRequest*)param; - struct QcPerfData* data = NULL; - struct WosThermalData* thermal_data = NULL; - uint32_t metric_count = 0; - uint32_t metric_index = 0; - uint8_t zone_count = 0; - uint64_t last_stream_time = 0; - // Calculate how many samples to collect before streaming - // Convert ms to ns for consistent calculations - uint64_t sampling_rate_ns = (uint64_t)request->sampling_rate * 1000000ULL; - uint64_t streaming_rate_ns = (uint64_t)request->streaming_rate * 1000000ULL; - uint64_t elapsed_ns = 0; - uint16_t temp_metric_id = UINT16_MAX; - uint16_t cooling_metric_id = UINT16_MAX; - - g_is_running = true; - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Thermal data collection thread started"); - samples_per_stream = streaming_rate_ns / sampling_rate_ns; - thermal_return_code = wos_thermal_lib_get_zone_count(&zone_count); // Get number of thermal zones from lib - if (thermal_return_code != WOS_THERMAL_LIB_SUCCESS) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to get thermal zone count from lib"); // Log error - g_is_running = false; - } else { - thermal_data = (struct WosThermalData*)calloc(1, sizeof(struct WosThermalData)); - if (NULL == thermal_data) { - return_code = QC_PERF_RETURN_CODE_CALLOC_FAILED; - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to allocate memory for WosThermalData"); - } else { - data = (struct QcPerfData*)calloc(1, sizeof(struct QcPerfData)); - if (NULL == data) { - return_code = QC_PERF_RETURN_CODE_CALLOC_FAILED; - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to allocate memory for QcPerfData"); - } else { - // Track time for streaming rate - metric_count = zone_count * METRIC_PER_ZONE * samples_per_stream; - data->metric_response = (struct QcPerfMetricResponse*)calloc(metric_count, sizeof(struct QcPerfMetricResponse)); - if (NULL == data->metric_response) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to allocate memory for thermal metric responses"); - g_is_running = false; - } else { - thermal_return_code = get_time_ns(¤t_time); - last_stream_time = current_time; - while (true == g_is_running) { - // Fill in data structure - data->backend_id = QC_PERF_BACKEND_THERMAL; - data->capabilityId = WOS_THERMAL_CAPABILITY_ID; - // Get current timestamp in nanoseconds - thermal_return_code = get_time_ns(¤t_time); - - // Get thermal data - thermal_return_code = wos_thermal_lib_get_zone_info(thermal_data); - if (thermal_return_code != WOS_THERMAL_LIB_SUCCESS) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to get thermal zone info"); - } else { - // Update the thermal data structure with collected values - // Fill in metric responses - for (uint8_t i = 0; i < thermal_data->zone_count && metric_index < metric_count - 1; i++) { - uint8_t zone_id = thermal_data->zones[i].zone_id; - - // Get metric indices for temperature and cooling - wos_thermal_get_metric_index(zone_id, false, &temp_metric_id); - wos_thermal_get_metric_index(zone_id, true, &cooling_metric_id); - - // Skip zones that don't have metrics defined - if (temp_metric_id == 0xFFFF || cooling_metric_id == 0xFFFF) { - continue; - } - - // Check if we have space for both metrics - if (metric_index + 1 >= metric_count) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Metric index exceeds allocated size"); - break; - } - - // Temperature metric - data->metric_response[metric_index].timestamp = thermal_data->timestamp; - data->metric_response[metric_index].metric_id = temp_metric_id; - data->metric_response[metric_index].metric_value.data_type = QC_PERF_DATA_TYPE_DOUBLE; - data->metric_response[metric_index].metric_value.double_value = thermal_data->zones[i].temperature; - metric_index++; - - // Passive cooling metric - data->metric_response[metric_index].timestamp = thermal_data->timestamp; - data->metric_response[metric_index].metric_id = cooling_metric_id; - data->metric_response[metric_index].metric_value.data_type = QC_PERF_DATA_TYPE_DOUBLE; - data->metric_response[metric_index].metric_value.double_value = thermal_data->zones[i].passive_cooling; - metric_index++; - } - - data->metric_response_len = metric_index; - // Increment sample count - sample_count = sample_count + 1; - } - - // Check if it's time to stream data (either by sample count or elapsed time) - elapsed_ns = current_time - last_stream_time; - if (sample_count >= samples_per_stream || elapsed_ns >= streaming_rate_ns) { - // Call the callback with the thermal data - if (NULL != g_data_callback) { - // Call data callback - g_data_callback(data); // Pass data directly, not &data - memset(data->metric_response, 0, metric_count * sizeof(struct QcPerfMetricResponse)); - } - - // Reset counters - sample_count = 0; - metric_index = 0; // Reset metric index after each callback - last_stream_time = current_time; - } - - // Sleep for the sampling rate - if (g_is_running) { - Sleep(request->sampling_rate); - } - } - } - } - } - } - // free WosThermalData - if (NULL != thermal_data) { - free(thermal_data); - thermal_data = NULL; - } - // free QcPerfData - if (NULL != data) { - if (NULL != data->metric_response) { - free(data->metric_response); // Free allocated memory for metric responses - data->metric_response = NULL; - data->metric_response_len = 0; - } - free(data); - data = NULL; - } - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Thermal data collection thread stopped"); - return NULL; -} - -/** - * @brief Set the message callback function - * - * This function registers a callback function that will be invoked to deliver - * informational, warning, or error messages from the WOS Thermal backend to the - * application. - * - * @param[in] message_callback Function pointer to the message callback - * - * @return QC_PERF_RETURN_CODE_SUCCESS on successful callback registration - */ -static enum QcPerfReturnCode wos_thermal_set_message_callback(QcPerfMessageCallback message_callback) { - wos_thermal_logger_set_message_callback(message_callback); - return QC_PERF_RETURN_CODE_SUCCESS; -} - -/** - * @brief Set the result callback function - * - * This function registers a callback function that will be invoked to deliver - * performance metric results from the WOS Thermal backend to the application. - * - * @param[in] data_callback Function pointer to the result callback - * - * @return QC_PERF_RETURN_CODE_SUCCESS on successful callback registration - * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if data_callback is NULL - * @return QC_PERF_RETURN_CODE_CALLBACK_ALREADY_SET if callback is already set - */ -static enum QcPerfReturnCode wos_thermal_set_data_callback(QcPerfDataCallback data_callback) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; - - if (NULL == data_callback) { - return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; - } else if (NULL != g_data_callback) { - return_code = QC_PERF_RETURN_CODE_CALLBACK_ALREADY_SET; - } else { - g_data_callback = data_callback; - return_code = QC_PERF_RETURN_CODE_SUCCESS; - } - - return return_code; -} - -/** - * @brief Initialize the WOS Thermal backend - * - * This function initializes the WOS Thermal backend. It allocates memory for - * backend information including capabilities and metrics, and populates - * them with the backend's configuration. - * - * @return QC_PERF_RETURN_CODE_SUCCESS on successful initialization - * @return QC_PERF_RETURN_CODE_ALREADY_INITIALIZED if already initialized - * @return QC_PERF_RETURN_CODE_FAILED if initialization fails - */ -static enum QcPerfReturnCode wos_thermal_init(void) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; - enum WosThermalLibReturnCode lib_ret = WOS_THERMAL_LIB_SUCCESS; - uint8_t available_metric_count = 0; - - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Initializing WOS Thermal backend"); - - if (g_is_initialized) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "WOS Thermal backend is already initialized"); - return_code = QC_PERF_RETURN_CODE_ALREADY_INITIALIZED; - } else { - // Initialize thermal library first to get available zones - lib_ret = wos_thermal_lib_init(); - if (WOS_THERMAL_LIB_SUCCESS != lib_ret) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to initialize WOS Thermal library, error: %d", lib_ret); - return_code = QC_PERF_RETURN_CODE_FAILED; - } else { - // Initialize backend info - g_backend_info.backend_id = QC_PERF_BACKEND_THERMAL; - g_backend_info.capabilities_list = &g_capability_info; - g_backend_info.capabilities_list_length = WOS_THERMAL_CAPABILITIES_LEN; - - // Initialize capability info - g_capability_info.capability_id = WOS_THERMAL_CAPABILITY_ID; - g_capability_info.capability_name_len = snprintf(g_capability_info.capability_name, CAPABILITY_NAME_MAX_LEN, "%s", WOS_THERMAL_CAPABILITY); - g_capability_info.metric_ids_list = g_metrics_data; - - // Dynamically initialize metrics only for available zones - wos_thermal_capability_init_available_metrics(g_metrics_data, &available_metric_count); - if (available_metric_count > 0) { - g_capability_info.metric_ids_list_len = available_metric_count; - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Initialized %d metrics for available thermal zones", available_metric_count); - } else { - // Fallback to static initialization if dynamic fails - wos_thermal_capability_init_metrics(g_metrics_data); - g_capability_info.metric_ids_list_len = WOS_THERMAL_CAPABILITY_METRIC_COUNT; - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "Failed to dynamically detect thermal zones, using static configuration"); - } - - // Set streaming rates - for (uint8_t i = 0; i < WOS_THERMAL_STREAMING_RATES_LEN && i < MAX_SAMPLING_STREAMING_RATES_LEN; i++) { - g_capability_info.streaming_rate[i] = g_streaming_rates[i]; - g_capability_info.streaming_rate_len++; - } - - // Set sampling rates - for (uint8_t i = 0; i < WOS_THERMAL_SAMPLING_RATES_LEN && i < MAX_SAMPLING_STREAMING_RATES_LEN; i++) { - g_capability_info.sampling_rate[i] = g_sampling_rates[i]; - g_capability_info.sampling_rate_len++; - } - - g_is_initialized = true; - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "WOS Thermal backend initialized successfully"); - } - } - return return_code; -} - -/** - * @brief Get backend information including capabilities and metrics - * - * This function provides access to the WOS Thermal backend's information by - * copying the pre-allocated backend information structure that was - * initialized during backend initialization. - * - * @param[in,out] backend_info Pointer to structure to be filled with backend information - * - * @return QC_PERF_RETURN_CODE_SUCCESS on successful information retrieval - * @return QC_PERF_RETURN_CODE_NULL_POINTER if backend_info pointer is NULL - * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if backend is not initialized - */ -static enum QcPerfReturnCode wos_thermal_backend_info(struct QcPerfBackendInfo* backend_info) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; - - if (NULL == backend_info) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Backend info pointer is NULL"); - return_code = QC_PERF_RETURN_CODE_NULL_POINTER; - } else if (false == g_is_initialized) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "WOS Thermal backend is not initialized"); - return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; - } else { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Retrieving WOS Thermal backend capabilities information"); - // Copy backend info - *backend_info = g_backend_info; - } - return return_code; -} - -/** - * @brief Validate the performance monitoring request - * - * This function validates that the request parameters are valid: - * - Capability ID must match the WOS Thermal capability - * - Sampling rate must match one of the supported sampling rates - * - Streaming rate must match one of the supported streaming rates - * - * @param[in] request Pointer to the performance request structure - * - * @return QC_PERF_RETURN_CODE_SUCCESS if validation passes - * @return QC_PERF_RETURN_CODE_NULL_POINTER if request is NULL - * @return QC_PERF_RETURN_CODE_CAPABILITY_NOT_FOUND if capability ID is not found - * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if sampling or streaming rate is invalid - */ -static enum QcPerfReturnCode validate_request(struct QcPerfRequest* request) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; - bool sampling_rate_valid = false; - bool streaming_rate_valid = false; - - if (NULL == request) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Request pointer is NULL"); - return_code = QC_PERF_RETURN_CODE_NULL_POINTER; - } else { - // Check capability ID - if (request->capability_id != WOS_THERMAL_CAPABILITY_ID) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Invalid capability ID: %u", request->capability_id); - return_code = QC_PERF_RETURN_CODE_CAPABILITY_NOT_FOUND; - } else { - // Check sampling rate - if (g_capability_info.sampling_rate_len == 2) { - if (g_capability_info.sampling_rate[0] <= request->sampling_rate && request->sampling_rate <= g_capability_info.sampling_rate[1]) { - sampling_rate_valid = true; - } - } else { - for (uint8_t i = 0; i < g_capability_info.sampling_rate_len; i++) { - if (g_capability_info.sampling_rate[i] == request->sampling_rate) { - sampling_rate_valid = true; - break; - } - } - } - if (false == sampling_rate_valid) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Invalid sampling rate: %u", request->sampling_rate); - return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; - } else { - // Check streaming rate - if (g_capability_info.streaming_rate_len == 2) { - if (g_capability_info.streaming_rate[0] <= request->streaming_rate && request->streaming_rate <= g_capability_info.streaming_rate[1]) { - streaming_rate_valid = true; - } - } else { - for (uint8_t i = 0; i < g_capability_info.streaming_rate_len; i++) { - if (g_capability_info.streaming_rate[i] == request->streaming_rate) { - streaming_rate_valid = true; - break; - } - } - } - if (false == streaming_rate_valid) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Invalid streaming rate: %u", request->streaming_rate); - return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; - } - } - } - } - return return_code; -} - -/** - * @brief Start performance data collection - * - * This function initiates performance data collection for the specified - * capability with the given sampling and streaming rates. It validates - * the request and starts the data collection process. - * - * @param[in] request Pointer to the performance request structure - * - * @return QC_PERF_RETURN_CODE_SUCCESS on successful start - * @return QC_PERF_RETURN_CODE_NULL_POINTER if request pointer is NULL - * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if backend is not initialized - * @return QC_PERF_RETURN_CODE_ALREADY_INITIALIZED if data collection is already running - * @return QC_PERF_RETURN_CODE_CAPABILITY_NOT_FOUND if capability ID is not found - * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if sampling or streaming rate is invalid - * @return QC_PERF_RETURN_CODE_FAILED if data collection fails to start - */ -static enum QcPerfReturnCode wos_thermal_start(struct QcPerfRequest* request) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; - enum QThreadReturnCode thread_ret = RET_QTHREAD_CREATE_SUCCESS; - struct QThreadAttributes thread_attrs = {0}; - - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Starting WOS Thermal data collection"); - - if (false == g_is_initialized) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "WOS Thermal backend is not initialized"); - return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; - } else if (true == g_is_running) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "WOS Thermal data collection is already running"); - return_code = QC_PERF_RETURN_CODE_ALREADY_INITIALIZED; - } else if (NULL == g_data_callback) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Data callback is not set"); - return_code = QC_PERF_RETURN_CODE_FAILED; - } else { - // Validate request - return_code = validate_request(request); - if (QC_PERF_RETURN_CODE_SUCCESS == return_code) { - // Create thread - thread_attrs.stack_size = 0; - thread_attrs.thread_params = request; - thread_attrs.thread_fn = thermal_data_collection_thread; - snprintf((char*)thread_attrs.thread_name, THREAD_NAME_SIZE, "wos_thermal_thread"); - thread_attrs.thread_name_len = (uint8_t)strlen((char*)thread_attrs.thread_name); - - thread_ret = thread_create(&thread_attrs, &g_thread_info); - if (RET_QTHREAD_CREATE_SUCCESS != thread_ret) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to create thermal data collection thread, error: %d", thread_ret); - return_code = WOS_THERMAL_LIB_ERROR_THREAD_CREATE_FAILED; - } else { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Thermal data collection started successfully"); - // Store current request - g_current_request = *request; - - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "WOS Thermal data collection started successfully"); - } - } - } - return return_code; -} - -/** - * @brief Stop performance data collection - * - * This function stops performance data collection for the specified - * capability. - * - * @param[in] request Pointer to the performance request structure - * - * @return QC_PERF_RETURN_CODE_SUCCESS on successful stop - * @return QC_PERF_RETURN_CODE_NULL_POINTER if request pointer is NULL - * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if backend is not initialized - * @return QC_PERF_RETURN_CODE_FAILED if data collection fails to stop - */ -static enum QcPerfReturnCode wos_thermal_stop(struct QcPerfRequest* request) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; - enum QThreadReturnCode thread_ret = RET_QTHREAD_JOIN_FAILED; - - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Stopping WOS Thermal data collection"); - - if (NULL == request) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Request pointer is NULL"); - return_code = QC_PERF_RETURN_CODE_NULL_POINTER; - } else if (false == g_is_initialized) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "WOS Thermal backend is not initialized"); - return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; - } else if (false == g_is_running) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "WOS Thermal data collection is not running"); - return_code = QC_PERF_RETURN_CODE_SUCCESS; - } else { - // Signal thread to stop - g_is_running = false; - // Wait for thread to finish - thread_ret = thread_join(&g_thread_info); - if (RET_QTHREAD_JOIN_SUCCESS != thread_ret) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to join thermal data collection thread, error: %d", thread_ret); - return_code = WOS_THERMAL_LIB_ERROR_THREAD_JOIN_FAILED; - } - // Destroy thread - thread_ret = thread_destroy(&g_thread_info); - if (RET_QTHREAD_DESTROY_SUCCESS != thread_ret) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to destroy thermal data collection thread, error: %d", thread_ret); - return_code = WOS_THERMAL_LIB_ERROR_THREAD_DESTROY_FAILED; - } else { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "WOS Thermal data collection stopped successfully"); - } - } - return return_code; -} - -/** - * @brief Deinitialize the WOS Thermal backend - * - * This function deinitializes the WOS Thermal backend. It stops data collection - * if it is running and cleans up resources. - * - * @return QC_PERF_RETURN_CODE_SUCCESS on successful deinitialization - * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if backend is not initialized - * @return QC_PERF_RETURN_CODE_FAILED if deinitialization fails - */ -static enum QcPerfReturnCode wos_thermal_deinit(void) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; - enum WosThermalLibReturnCode lib_ret = WOS_THERMAL_LIB_SUCCESS; - - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Deinitializing WOS Thermal backend"); - - if (false == g_is_initialized) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "WOS Thermal backend is not initialized"); - return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; - } else { - // Stop data collection if running - if (g_is_running) { - return_code = wos_thermal_stop(&g_current_request); - if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to stop WOS Thermal data collection during deinitialization"); - // Continue with deinitialization anyway - } - } - - // Clean up thermal library - lib_ret = wos_thermal_lib_cleanup(); - if (WOS_THERMAL_LIB_SUCCESS != lib_ret) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to clean up WOS Thermal library, error: %d", lib_ret); - return_code = QC_PERF_RETURN_CODE_FAILED; - } else { - g_is_initialized = false; - g_data_callback = NULL; - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "WOS Thermal backend deinitialized successfully"); - } - } - return return_code; -} - -/** - * @brief Create and configure the WOS Thermal backend - * - * This function sets up the WOS Thermal backend by assigning function pointers - * to the backend interface structure. It configures all required callbacks - * for backend lifecycle management and performance monitoring operations. - * - * @param[in] backend Pointer to the backend private structure to be configured - * - * @return QC_PERF_RETURN_CODE_SUCCESS on successful creation - * @return QC_PERF_RETURN_CODE_NULL_POINTER if backend pointer is NULL - */ -enum QcPerfReturnCode qcperf_wos_thermal_backend_create(struct QcPerfBackendPrivate* backend) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; - - if (NULL == backend) { - return_code = QC_PERF_RETURN_CODE_NULL_POINTER; - } else { - backend->qcperf_backend_init = wos_thermal_init; - backend->qcperf_backend_start = wos_thermal_start; - backend->qcperf_backend_stop = wos_thermal_stop; - backend->qcperf_backend_deinit = wos_thermal_deinit; - backend->qcperf_backend_info = wos_thermal_backend_info; - backend->set_message_callback = wos_thermal_set_message_callback; - backend->set_data_callback = wos_thermal_set_data_callback; - } - return return_code; -} +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file wos_thermal.c + * @brief Implementation of the WOS Thermal backend for libqcperf + * @author Skand Gupta (skangupt@qti.qualcomm.com) + * + * This file implements the WOS (Windows on Snapdragon) Thermal backend for + * the QcPerf library. It provides functionality for monitoring temperature + * and passive cooling metrics for various thermal zones on Windows platforms. + * + * The implementation follows the QcPerf backend interface pattern, providing + * functions for initialization, data collection, and cleanup. It interfaces + * with the WOS Thermal library to collect thermal data and delivers it to + * the application through the QcPerf callback mechanism. + */ + +#include +#include +#include +#include + +#include "wos_thermal.h" +#include "wos_thermal_lib.h" +#include "wos_thermal_logger.h" +#include "qcperf_backend_interface.h" +#include "qcperf_backend_enum.h" +#include "QThread.h" +#include "qtime.h" + +#define METRIC_PER_ZONE 2 + +// Static variables +static bool g_is_initialized = false; +static volatile bool g_is_running = false; +static QcPerfDataCallback g_data_callback = NULL; +static struct QcPerfBackendInfo g_backend_info = {0}; +static struct QThreadInfo g_thread_info = {0}; +static struct QcPerfCapabilityInfo g_capability_info = {0}; +static struct QcPerfMetricInfo g_metrics_data[WOS_THERMAL_CAPABILITY_METRIC_COUNT] = {0}; +static struct QcPerfRequest g_current_request = {0}; + +// Streaming and sampling rates +static const uint16_t g_streaming_rates[WOS_THERMAL_STREAMING_RATES_LEN] = {WOS_THERMAL_STREAMING_RATES}; +static const uint16_t g_sampling_rates[WOS_THERMAL_SAMPLING_RATES_LEN] = {WOS_THERMAL_SAMPLING_RATES}; + +/** + * @brief Thread function for collecting thermal data + * + * This function runs in a separate thread and continuously collects thermal data + * at the specified sampling rate and delivers updates via the callback at the + * specified streaming rate. It allocates memory for the QcPerfData structure and + * metric responses, collects thermal data at regular intervals, and sends batched + * updates to the registered callback. + * + * The function properly manages memory by freeing all allocated resources before + * exiting, and implements bounds checking to prevent buffer overflows. It also + * resets the metric index after each callback to ensure proper data tracking. + * + * @param[in] param Thread parameters (pointer to QcPerfRequest) + * + * @return NULL + */ +static void* thermal_data_collection_thread(void* param) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; + enum WosThermalLibReturnCode thermal_return_code = WOS_THERMAL_LIB_ERROR_FAILED; + uint32_t samples_per_stream = 0; + uint32_t sample_count = 0; + uint64_t current_time = 0; + struct QcPerfRequest* request = (struct QcPerfRequest*)param; + struct QcPerfData* data = NULL; + struct WosThermalData* thermal_data = NULL; + uint32_t metric_count = 0; + uint32_t metric_index = 0; + uint8_t zone_count = 0; + uint64_t last_stream_time = 0; + // Calculate how many samples to collect before streaming + // Convert ms to ns for consistent calculations + uint64_t sampling_rate_ns = (uint64_t)request->sampling_rate * 1000000ULL; + uint64_t streaming_rate_ns = (uint64_t)request->streaming_rate * 1000000ULL; + uint64_t elapsed_ns = 0; + uint16_t temp_metric_id = UINT16_MAX; + uint16_t cooling_metric_id = UINT16_MAX; + + g_is_running = true; + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Thermal data collection thread started"); + samples_per_stream = streaming_rate_ns / sampling_rate_ns; + thermal_return_code = wos_thermal_lib_get_zone_count(&zone_count); // Get number of thermal zones from lib + if (thermal_return_code != WOS_THERMAL_LIB_SUCCESS) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to get thermal zone count from lib"); // Log error + g_is_running = false; + } else { + thermal_data = (struct WosThermalData*)calloc(1, sizeof(struct WosThermalData)); + if (NULL == thermal_data) { + return_code = QC_PERF_RETURN_CODE_CALLOC_FAILED; + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to allocate memory for WosThermalData"); + } else { + data = (struct QcPerfData*)calloc(1, sizeof(struct QcPerfData)); + if (NULL == data) { + return_code = QC_PERF_RETURN_CODE_CALLOC_FAILED; + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to allocate memory for QcPerfData"); + } else { + // Track time for streaming rate + metric_count = zone_count * METRIC_PER_ZONE * samples_per_stream; + data->metric_response = (struct QcPerfMetricResponse*)calloc(metric_count, sizeof(struct QcPerfMetricResponse)); + if (NULL == data->metric_response) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to allocate memory for thermal metric responses"); + g_is_running = false; + } else { + thermal_return_code = get_time_ns(¤t_time); + last_stream_time = current_time; + while (true == g_is_running) { + // Fill in data structure + data->backend_id = QC_PERF_BACKEND_THERMAL; + data->capabilityId = WOS_THERMAL_CAPABILITY_ID; + // Get current timestamp in nanoseconds + thermal_return_code = get_time_ns(¤t_time); + + // Get thermal data + thermal_return_code = wos_thermal_lib_get_zone_info(thermal_data); + if (thermal_return_code != WOS_THERMAL_LIB_SUCCESS) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to get thermal zone info"); + } else { + // Update the thermal data structure with collected values + // Fill in metric responses + for (uint8_t i = 0; i < thermal_data->zone_count && metric_index < metric_count - 1; i++) { + uint8_t zone_id = thermal_data->zones[i].zone_id; + + // Get metric indices for temperature and cooling + wos_thermal_get_metric_index(zone_id, false, &temp_metric_id); + wos_thermal_get_metric_index(zone_id, true, &cooling_metric_id); + + // Skip zones that don't have metrics defined + if (temp_metric_id == 0xFFFF || cooling_metric_id == 0xFFFF) { + continue; + } + + // Check if we have space for both metrics + if (metric_index + 1 >= metric_count) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Metric index exceeds allocated size"); + break; + } + + // Temperature metric + data->metric_response[metric_index].timestamp = thermal_data->timestamp; + data->metric_response[metric_index].metric_id = temp_metric_id; + data->metric_response[metric_index].metric_value.data_type = QC_PERF_DATA_TYPE_DOUBLE; + data->metric_response[metric_index].metric_value.double_value = thermal_data->zones[i].temperature; + metric_index++; + + // Passive cooling metric + data->metric_response[metric_index].timestamp = thermal_data->timestamp; + data->metric_response[metric_index].metric_id = cooling_metric_id; + data->metric_response[metric_index].metric_value.data_type = QC_PERF_DATA_TYPE_DOUBLE; + data->metric_response[metric_index].metric_value.double_value = thermal_data->zones[i].passive_cooling; + metric_index++; + } + + data->metric_response_len = metric_index; + // Increment sample count + sample_count = sample_count + 1; + } + + // Check if it's time to stream data (either by sample count or elapsed time) + elapsed_ns = current_time - last_stream_time; + if (sample_count >= samples_per_stream || elapsed_ns >= streaming_rate_ns) { + // Call the callback with the thermal data + if (NULL != g_data_callback) { + // Call data callback + g_data_callback(data); // Pass data directly, not &data + memset(data->metric_response, 0, metric_count * sizeof(struct QcPerfMetricResponse)); + } + + // Reset counters + sample_count = 0; + metric_index = 0; // Reset metric index after each callback + last_stream_time = current_time; + } + + // Sleep for the sampling rate + if (g_is_running) { + Sleep(request->sampling_rate); + } + } + } + } + } + } + // free WosThermalData + if (NULL != thermal_data) { + free(thermal_data); + thermal_data = NULL; + } + // free QcPerfData + if (NULL != data) { + if (NULL != data->metric_response) { + free(data->metric_response); // Free allocated memory for metric responses + data->metric_response = NULL; + data->metric_response_len = 0; + } + free(data); + data = NULL; + } + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Thermal data collection thread stopped"); + return NULL; +} + +/** + * @brief Set the message callback function + * + * This function registers a callback function that will be invoked to deliver + * informational, warning, or error messages from the WOS Thermal backend to the + * application. + * + * @param[in] message_callback Function pointer to the message callback + * + * @return QC_PERF_RETURN_CODE_SUCCESS on successful callback registration + */ +static enum QcPerfReturnCode wos_thermal_set_message_callback(QcPerfMessageCallback message_callback) { + wos_thermal_logger_set_message_callback(message_callback); + return QC_PERF_RETURN_CODE_SUCCESS; +} + +/** + * @brief Set the result callback function + * + * This function registers a callback function that will be invoked to deliver + * performance metric results from the WOS Thermal backend to the application. + * + * @param[in] data_callback Function pointer to the result callback + * + * @return QC_PERF_RETURN_CODE_SUCCESS on successful callback registration + * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if data_callback is NULL + * @return QC_PERF_RETURN_CODE_CALLBACK_ALREADY_SET if callback is already set + */ +static enum QcPerfReturnCode wos_thermal_set_data_callback(QcPerfDataCallback data_callback) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; + + if (NULL == data_callback) { + return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; + } else if (NULL != g_data_callback) { + return_code = QC_PERF_RETURN_CODE_CALLBACK_ALREADY_SET; + } else { + g_data_callback = data_callback; + return_code = QC_PERF_RETURN_CODE_SUCCESS; + } + + return return_code; +} + +/** + * @brief Initialize the WOS Thermal backend + * + * This function initializes the WOS Thermal backend. It allocates memory for + * backend information including capabilities and metrics, and populates + * them with the backend's configuration. + * + * @return QC_PERF_RETURN_CODE_SUCCESS on successful initialization + * @return QC_PERF_RETURN_CODE_ALREADY_INITIALIZED if already initialized + * @return QC_PERF_RETURN_CODE_FAILED if initialization fails + */ +static enum QcPerfReturnCode wos_thermal_init(void) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; + enum WosThermalLibReturnCode lib_ret = WOS_THERMAL_LIB_SUCCESS; + uint8_t available_metric_count = 0; + + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Initializing WOS Thermal backend"); + + if (g_is_initialized) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "WOS Thermal backend is already initialized"); + return_code = QC_PERF_RETURN_CODE_ALREADY_INITIALIZED; + } else { + // Initialize thermal library first to get available zones + lib_ret = wos_thermal_lib_init(); + if (WOS_THERMAL_LIB_SUCCESS != lib_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to initialize WOS Thermal library, error: %d", lib_ret); + return_code = QC_PERF_RETURN_CODE_FAILED; + } else { + // Initialize backend info + g_backend_info.backend_id = QC_PERF_BACKEND_THERMAL; + g_backend_info.capabilities_list = &g_capability_info; + g_backend_info.capabilities_list_length = WOS_THERMAL_CAPABILITIES_LEN; + + // Initialize capability info + g_capability_info.capability_id = WOS_THERMAL_CAPABILITY_ID; + g_capability_info.capability_name_len = snprintf(g_capability_info.capability_name, CAPABILITY_NAME_MAX_LEN, "%s", WOS_THERMAL_CAPABILITY); + g_capability_info.metric_ids_list = g_metrics_data; + + // Dynamically initialize metrics only for available zones + wos_thermal_capability_init_available_metrics(g_metrics_data, &available_metric_count); + if (available_metric_count > 0) { + g_capability_info.metric_ids_list_len = available_metric_count; + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Initialized %d metrics for available thermal zones", available_metric_count); + } else { + // Fallback to static initialization if dynamic fails + wos_thermal_capability_init_metrics(g_metrics_data); + g_capability_info.metric_ids_list_len = WOS_THERMAL_CAPABILITY_METRIC_COUNT; + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "Failed to dynamically detect thermal zones, using static configuration"); + } + + // Set streaming rates + for (uint8_t i = 0; i < WOS_THERMAL_STREAMING_RATES_LEN && i < MAX_SAMPLING_STREAMING_RATES_LEN; i++) { + g_capability_info.streaming_rate[i] = g_streaming_rates[i]; + g_capability_info.streaming_rate_len++; + } + + // Set sampling rates + for (uint8_t i = 0; i < WOS_THERMAL_SAMPLING_RATES_LEN && i < MAX_SAMPLING_STREAMING_RATES_LEN; i++) { + g_capability_info.sampling_rate[i] = g_sampling_rates[i]; + g_capability_info.sampling_rate_len++; + } + + g_is_initialized = true; + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "WOS Thermal backend initialized successfully"); + } + } + return return_code; +} + +/** + * @brief Get backend information including capabilities and metrics + * + * This function provides access to the WOS Thermal backend's information by + * copying the pre-allocated backend information structure that was + * initialized during backend initialization. + * + * @param[in,out] backend_info Pointer to structure to be filled with backend information + * + * @return QC_PERF_RETURN_CODE_SUCCESS on successful information retrieval + * @return QC_PERF_RETURN_CODE_NULL_POINTER if backend_info pointer is NULL + * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if backend is not initialized + */ +static enum QcPerfReturnCode wos_thermal_backend_info(struct QcPerfBackendInfo* backend_info) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; + + if (NULL == backend_info) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Backend info pointer is NULL"); + return_code = QC_PERF_RETURN_CODE_NULL_POINTER; + } else if (false == g_is_initialized) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "WOS Thermal backend is not initialized"); + return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Retrieving WOS Thermal backend capabilities information"); + // Copy backend info + *backend_info = g_backend_info; + } + return return_code; +} + +/** + * @brief Validate the performance monitoring request + * + * This function validates that the request parameters are valid: + * - Capability ID must match the WOS Thermal capability + * - Sampling rate must match one of the supported sampling rates + * - Streaming rate must match one of the supported streaming rates + * + * @param[in] request Pointer to the performance request structure + * + * @return QC_PERF_RETURN_CODE_SUCCESS if validation passes + * @return QC_PERF_RETURN_CODE_NULL_POINTER if request is NULL + * @return QC_PERF_RETURN_CODE_CAPABILITY_NOT_FOUND if capability ID is not found + * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if sampling or streaming rate is invalid + */ +static enum QcPerfReturnCode validate_request(struct QcPerfRequest* request) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; + bool sampling_rate_valid = false; + bool streaming_rate_valid = false; + + if (NULL == request) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Request pointer is NULL"); + return_code = QC_PERF_RETURN_CODE_NULL_POINTER; + } else { + // Check capability ID + if (request->capability_id != WOS_THERMAL_CAPABILITY_ID) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Invalid capability ID: %u", request->capability_id); + return_code = QC_PERF_RETURN_CODE_CAPABILITY_NOT_FOUND; + } else { + // Check sampling rate + if (g_capability_info.sampling_rate_len == 2) { + if (g_capability_info.sampling_rate[0] <= request->sampling_rate && request->sampling_rate <= g_capability_info.sampling_rate[1]) { + sampling_rate_valid = true; + } + } else { + for (uint8_t i = 0; i < g_capability_info.sampling_rate_len; i++) { + if (g_capability_info.sampling_rate[i] == request->sampling_rate) { + sampling_rate_valid = true; + break; + } + } + } + if (false == sampling_rate_valid) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Invalid sampling rate: %u", request->sampling_rate); + return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; + } else { + // Check streaming rate + if (g_capability_info.streaming_rate_len == 2) { + if (g_capability_info.streaming_rate[0] <= request->streaming_rate && request->streaming_rate <= g_capability_info.streaming_rate[1]) { + streaming_rate_valid = true; + } + } else { + for (uint8_t i = 0; i < g_capability_info.streaming_rate_len; i++) { + if (g_capability_info.streaming_rate[i] == request->streaming_rate) { + streaming_rate_valid = true; + break; + } + } + } + if (false == streaming_rate_valid) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Invalid streaming rate: %u", request->streaming_rate); + return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; + } + } + } + } + return return_code; +} + +/** + * @brief Start performance data collection + * + * This function initiates performance data collection for the specified + * capability with the given sampling and streaming rates. It validates + * the request and starts the data collection process. + * + * @param[in] request Pointer to the performance request structure + * + * @return QC_PERF_RETURN_CODE_SUCCESS on successful start + * @return QC_PERF_RETURN_CODE_NULL_POINTER if request pointer is NULL + * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if backend is not initialized + * @return QC_PERF_RETURN_CODE_ALREADY_INITIALIZED if data collection is already running + * @return QC_PERF_RETURN_CODE_CAPABILITY_NOT_FOUND if capability ID is not found + * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if sampling or streaming rate is invalid + * @return QC_PERF_RETURN_CODE_FAILED if data collection fails to start + */ +static enum QcPerfReturnCode wos_thermal_start(struct QcPerfRequest* request) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; + enum QThreadReturnCode thread_ret = RET_QTHREAD_CREATE_SUCCESS; + struct QThreadAttributes thread_attrs = {0}; + + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Starting WOS Thermal data collection"); + + if (false == g_is_initialized) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "WOS Thermal backend is not initialized"); + return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; + } else if (true == g_is_running) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "WOS Thermal data collection is already running"); + return_code = QC_PERF_RETURN_CODE_ALREADY_INITIALIZED; + } else if (NULL == g_data_callback) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Data callback is not set"); + return_code = QC_PERF_RETURN_CODE_FAILED; + } else { + // Validate request + return_code = validate_request(request); + if (QC_PERF_RETURN_CODE_SUCCESS == return_code) { + // Create thread + thread_attrs.stack_size = 0; + thread_attrs.thread_params = request; + thread_attrs.thread_fn = thermal_data_collection_thread; + snprintf((char*)thread_attrs.thread_name, THREAD_NAME_SIZE, "wos_thermal_thread"); + thread_attrs.thread_name_len = (uint8_t)strlen((char*)thread_attrs.thread_name); + + thread_ret = thread_create(&thread_attrs, &g_thread_info); + if (RET_QTHREAD_CREATE_SUCCESS != thread_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to create thermal data collection thread, error: %d", thread_ret); + return_code = WOS_THERMAL_LIB_ERROR_THREAD_CREATE_FAILED; + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Thermal data collection started successfully"); + // Store current request + g_current_request = *request; + + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "WOS Thermal data collection started successfully"); + } + } + } + return return_code; +} + +/** + * @brief Stop performance data collection + * + * This function stops performance data collection for the specified + * capability. + * + * @param[in] request Pointer to the performance request structure + * + * @return QC_PERF_RETURN_CODE_SUCCESS on successful stop + * @return QC_PERF_RETURN_CODE_NULL_POINTER if request pointer is NULL + * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if backend is not initialized + * @return QC_PERF_RETURN_CODE_FAILED if data collection fails to stop + */ +static enum QcPerfReturnCode wos_thermal_stop(struct QcPerfRequest* request) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; + enum QThreadReturnCode thread_ret = RET_QTHREAD_JOIN_FAILED; + + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Stopping WOS Thermal data collection"); + + if (NULL == request) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Request pointer is NULL"); + return_code = QC_PERF_RETURN_CODE_NULL_POINTER; + } else if (false == g_is_initialized) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "WOS Thermal backend is not initialized"); + return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; + } else if (false == g_is_running) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "WOS Thermal data collection is not running"); + return_code = QC_PERF_RETURN_CODE_SUCCESS; + } else { + // Signal thread to stop + g_is_running = false; + // Wait for thread to finish + thread_ret = thread_join(&g_thread_info); + if (RET_QTHREAD_JOIN_SUCCESS != thread_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to join thermal data collection thread, error: %d", thread_ret); + return_code = WOS_THERMAL_LIB_ERROR_THREAD_JOIN_FAILED; + } + // Destroy thread + thread_ret = thread_destroy(&g_thread_info); + if (RET_QTHREAD_DESTROY_SUCCESS != thread_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to destroy thermal data collection thread, error: %d", thread_ret); + return_code = WOS_THERMAL_LIB_ERROR_THREAD_DESTROY_FAILED; + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "WOS Thermal data collection stopped successfully"); + } + } + return return_code; +} + +/** + * @brief Deinitialize the WOS Thermal backend + * + * This function deinitializes the WOS Thermal backend. It stops data collection + * if it is running and cleans up resources. + * + * @return QC_PERF_RETURN_CODE_SUCCESS on successful deinitialization + * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if backend is not initialized + * @return QC_PERF_RETURN_CODE_FAILED if deinitialization fails + */ +static enum QcPerfReturnCode wos_thermal_deinit(void) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; + enum WosThermalLibReturnCode lib_ret = WOS_THERMAL_LIB_SUCCESS; + + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Deinitializing WOS Thermal backend"); + + if (false == g_is_initialized) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "WOS Thermal backend is not initialized"); + return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; + } else { + // Stop data collection if running + if (g_is_running) { + return_code = wos_thermal_stop(&g_current_request); + if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to stop WOS Thermal data collection during deinitialization"); + // Continue with deinitialization anyway + } + } + + // Clean up thermal library + lib_ret = wos_thermal_lib_cleanup(); + if (WOS_THERMAL_LIB_SUCCESS != lib_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to clean up WOS Thermal library, error: %d", lib_ret); + return_code = QC_PERF_RETURN_CODE_FAILED; + } else { + g_is_initialized = false; + g_data_callback = NULL; + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "WOS Thermal backend deinitialized successfully"); + } + } + return return_code; +} + +/** + * @brief Create and configure the WOS Thermal backend + * + * This function sets up the WOS Thermal backend by assigning function pointers + * to the backend interface structure. It configures all required callbacks + * for backend lifecycle management and performance monitoring operations. + * + * @param[in] backend Pointer to the backend private structure to be configured + * + * @return QC_PERF_RETURN_CODE_SUCCESS on successful creation + * @return QC_PERF_RETURN_CODE_NULL_POINTER if backend pointer is NULL + */ +enum QcPerfReturnCode qcperf_wos_thermal_backend_create(struct QcPerfBackendPrivate* backend) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; + + if (NULL == backend) { + return_code = QC_PERF_RETURN_CODE_NULL_POINTER; + } else { + backend->qcperf_backend_init = wos_thermal_init; + backend->qcperf_backend_start = wos_thermal_start; + backend->qcperf_backend_stop = wos_thermal_stop; + backend->qcperf_backend_deinit = wos_thermal_deinit; + backend->qcperf_backend_info = wos_thermal_backend_info; + backend->set_message_callback = wos_thermal_set_message_callback; + backend->set_data_callback = wos_thermal_set_data_callback; + } + return return_code; +} diff --git a/qcperf/backends/wos-thermal/src/wos_thermal_info.c b/qcperf/backends/wos-thermal/src/wos_thermal_info.c index 502683f..3903ef1 100644 --- a/qcperf/backends/wos-thermal/src/wos_thermal_info.c +++ b/qcperf/backends/wos-thermal/src/wos_thermal_info.c @@ -1,1223 +1,1223 @@ -/* - Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - Redistribution and use in source and binary forms, with or without - modification, are permitted (subject to the limitations in the - disclaimer below) provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Qualcomm Technologies, Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE - GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT - HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/** - * @file wos_thermal_info.c - * @brief Metric initialization implementation for WOS Thermal backend - * @author Skand Gupta (skangupt@qti.qualcomm.com) - * - * This file implements the initialization function that populates metric - * information structures with static definitions for the WOS Thermal backend's - * temperature and passive cooling monitoring capability. - * - * The implementation initializes metric information for 22 thermal zones, with - * each zone having two metrics: temperature (in degrees Celsius) and passive - * cooling (as a percentage). These metrics are used by the WOS Thermal backend - * to report thermal conditions to applications. - */ - -#include -#include -#include "wos_thermal_info.h" -#include "wos_thermal_logger.h" -#include "qcperf_common.h" -#include "thermal_common.h" - -// Mapping from zone ID to metric indices [0] = temperature metric, [1] = cooling metric -static uint16_t g_zone_id_to_metric_index_map[MAX_THERMAL_ZONE_ID][2] = {0}; - -/** - * @brief Initialize WOS Thermal metrics data - * - * This function populates the metric information for WOS Thermal capability - * using the static macro definitions from wos_thermal_info.h. For each thermal - * zone, it initializes two metrics: - * 1. Temperature metric (in degrees Celsius) - * 2. Passive cooling metric (as a percentage) - * - * The function sets the metric ID, name, description, and unit for each metric, - * along with the corresponding string lengths. This information is used by the - * QcPerf framework to provide metadata about the metrics to applications. - * - * @param[out] metrics_data Array to be populated with WOS Thermal metric information - * (must have space for WOS_THERMAL_CAPABILITY_METRIC_COUNT entries) - */ -void wos_thermal_capability_init_metrics(struct QcPerfMetricInfo* metrics_data) { - // CPU Cluster 0 Thermal Zone - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_unit); - - // CPU Cluster 0 Thermal Zone - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_unit); - - // CPU Cluster 1 Thermal Zone - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_unit); - - // CPU Cluster 1 Thermal Zone - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_unit); - - // CPU Cluster 2 Thermal Zone - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_unit); - - // CPU Cluster 2 Thermal Zone - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_unit); - - // QMX0 Thermal Zone - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_id = WOS_THERMAL_METRIC_QMX0_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX0_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX0_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX0_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_unit); - - // QMX0 Thermal Zone - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_id = WOS_THERMAL_METRIC_QMX0_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX0_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX0_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX0_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_unit); - - // QMX1 Thermal Zone - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_id = WOS_THERMAL_METRIC_QMX1_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX1_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX1_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX1_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_unit); - - // QMX1 Thermal Zone - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_id = WOS_THERMAL_METRIC_QMX1_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX1_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX1_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX1_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_unit); - - // QMX2 Thermal Zone - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_id = WOS_THERMAL_METRIC_QMX2_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX2_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX2_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX2_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_unit); - - // QMX2 Thermal Zone - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_id = WOS_THERMAL_METRIC_QMX2_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX2_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX2_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX2_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_unit); - - // GPU Thermal Zone - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_id = WOS_THERMAL_METRIC_GPU_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_GPU_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_GPU_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_GPU_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_unit); - - // GPU Thermal Zone - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_id = WOS_THERMAL_METRIC_GPU_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_GPU_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_GPU_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_GPU_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_unit); - - // NSP Thermal Zone - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_id = WOS_THERMAL_METRIC_NSP_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_NSP_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_NSP_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_NSP_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_unit); - - // NSP Thermal Zone - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_id = WOS_THERMAL_METRIC_NSP_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_NSP_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_NSP_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_NSP_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_unit); - - // QCLimitsPolicy CPU coreparking - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", - WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_description_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_unit); - - // QCLimitsPolicy CPU coreparking - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", - WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_description_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_unit); - - // QCLimitsPolicy CPU DCVS All Clusters - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", - WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_name_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", - WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_description_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", - WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_unit_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_unit); - - // QCLimitsPolicy CPU DCVS All Clusters - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", - WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_name_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", - WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_description_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", - WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_unit_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_unit); - - // QCLimitsPolicy CPU DCVS Cluster0 - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", - WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_description_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_unit); - - // QCLimitsPolicy CPU DCVS Cluster0 - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_name_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", - WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_description_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_unit_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_unit); - - // QCLimitsPolicy CPU DCVS Cluster1 - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", - WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_description_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_unit); - - // QCLimitsPolicy CPU DCVS Cluster1 - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_name_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", - WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_description_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_unit_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_unit); - - // QCLimitsPolicy CPU DCVS Cluster2 - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", - WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_description_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_unit); - - // QCLimitsPolicy CPU DCVS Cluster2 - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_name_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", - WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_description_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_unit_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_unit); - - // QCLimitsPolicy GPU - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_unit); - - // QCLimitsPolicy GPU - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_unit); - - // QCLimitsPolicy NSP - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_unit); - - // QCLimitsPolicy NSP - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_unit); - - // QCLimitsPolicy Modem BCL - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_unit); - - // QCLimitsPolicy Modem BCL - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", - WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_unit); - - // QCLimitsPolicy Modem Skin - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_unit); - - // QCLimitsPolicy Modem Skin - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", - WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_description_len = - strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_unit); - - // QCLimitsPolicy WLAN - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_unit); - - // QCLimitsPolicy WLAN - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_unit); - - // Critical Thermal Zones for All Internal TSENS - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_id = WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_unit); - - // Critical Thermal Zones for All Internal TSENS - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_id = WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_unit); - - // EC thermistor 1 - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_unit); - - // EC thermistor 1 - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_unit); - - // EC thermistor 2 - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_unit); - - // EC thermistor 2 - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_unit); - - // EC thermistor 3 - Temperature - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_unit); - - // EC thermistor 3 - Passive Cooling - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_ID; - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_NAME); - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_name); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_DESCRIPTION); - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_description); - snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_UNIT); - metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_unit); -} - -/** - * @brief Initialize WOS Thermal metrics data for available zones - * - * This function queries the available thermal zones and initializes metrics - * only for those zones that are actually present on the system. - * It maps the zone names to the predefined metrics in the header file. - * - * @param[out] metrics_data Array to be populated with WOS Thermal metric information - * @param[out] metric_count Pointer to store the number of metrics initialized - */ -void wos_thermal_capability_init_available_metrics(struct QcPerfMetricInfo* metrics_data, uint8_t* metric_count) { - struct ThermalCommonZoneNameMap zone_map = {0}; - enum ThermalCommonReturnCode common_ret = RETURN_CODE_THERMAL_COMMON_SUCCESS; - uint8_t metric_index = 0; - - // Clear the zone ID to metric index mapping - memset(g_zone_id_to_metric_index_map, 0xFF, sizeof(g_zone_id_to_metric_index_map)); - - // Initialize metric count to 0 - if (NULL == metric_count) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Metric count pointer is NULL"); - return; - } else { - *metric_count = 0; - // Get available thermal zones - common_ret = thermal_common_getzone_names(&zone_map); - if (RETURN_CODE_THERMAL_COMMON_SUCCESS != common_ret) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to get thermal zone names, error: %d", common_ret); - } else { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Found %d thermal zones", zone_map.zone_names_ids_length); - - // Create a mapping between zone IDs and metric indices - for (uint8_t i = 0; i < zone_map.zone_names_ids_length; i++) { - uint8_t zone_id = zone_map.zone_ids[i]; - const char* zone_name = zone_map.zone_names[i].string; - bool found_match = false; - - if (zone_id >= MAX_THERMAL_ZONE_ID) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "Zone ID %d exceeds maximum allowed (%d), skipping", zone_id, MAX_THERMAL_ZONE_ID - 1); - continue; - } else { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Initializing metrics for zone %d: %s", zone_id, zone_name); - // Check if this zone matches any of our predefined zones - // CPU Cluster 0 - if (strstr(zone_name, WOS_THERMAL_METRIC_CPU_CLUSTER_0_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // CPU Cluster 1 - else if (strstr(zone_name, WOS_THERMAL_METRIC_CPU_CLUSTER_1_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // CPU Cluster 2 - else if (strstr(zone_name, WOS_THERMAL_METRIC_CPU_CLUSTER_2_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // QMX0 - else if (strstr(zone_name, WOS_THERMAL_METRIC_QMX0_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QMX0_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX0_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX0_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX0_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QMX0_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX0_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX0_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX0_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // QMX1 - else if (strstr(zone_name, WOS_THERMAL_METRIC_QMX1_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QMX1_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX1_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX1_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX1_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QMX1_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX1_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX1_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX1_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // QMX2 - else if (strstr(zone_name, WOS_THERMAL_METRIC_QMX2_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QMX2_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX2_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX2_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX2_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QMX2_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX2_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX2_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX2_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // GPU - else if (strstr(zone_name, WOS_THERMAL_METRIC_GPU_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_GPU_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_GPU_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_GPU_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_GPU_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_GPU_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_GPU_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_GPU_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_GPU_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // NSP - else if (strstr(zone_name, WOS_THERMAL_METRIC_NSP_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_NSP_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_NSP_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_NSP_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_NSP_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_NSP_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_NSP_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_NSP_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_NSP_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // QCLimitsPolicy CPU coreparking - else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // QCLimitsPolicy CPU DCVS All Clusters - else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // QCLimitsPolicy CPU DCVS Cluster0 - else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // QCLimitsPolicy CPU DCVS Cluster1 - else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // QCLimitsPolicy CPU DCVS Cluster2 - else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // QCLimitsPolicy GPU - else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_ZONE_NAME) != NULL && strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_ZONE_NAME) == zone_name) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // QCLimitsPolicy NSP - else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // QCLimitsPolicy Modem BCL - else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // QCLimitsPolicy Modem Skin - else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // QCLimitsPolicy WLAN - else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // Critical Thermal Zones - else if (strstr(zone_name, WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // EC thermistor 1 - else if (strstr(zone_name, WOS_THERMAL_METRIC_EC_THERMISTOR_1_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // EC thermistor 2 - else if (strstr(zone_name, WOS_THERMAL_METRIC_EC_THERMISTOR_2_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - // EC thermistor 3 - else if (strstr(zone_name, WOS_THERMAL_METRIC_EC_THERMISTOR_3_ZONE_NAME) != NULL) { - // Temperature metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][0] = metric_index; - metric_index++; - - // Cooling metric - metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_ID; - snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_NAME); - metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); - snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_DESCRIPTION); - metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); - snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_UNIT); - metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); - - // Store mapping - g_zone_id_to_metric_index_map[zone_id][1] = metric_index; - metric_index++; - found_match = true; - } - - // If no match was found, use generic naming - if (!found_match) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Metric not defined for zone : %s", zone_name); - } - } - } - - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Initialized %d metrics for %d thermal zones", metric_index, zone_map.zone_names_ids_length); - } - // Set the metric count - *metric_count = metric_index; - } -} - -/** - * @brief Get metric index for a thermal zone and metric type - * - * @param[in] zone_id ID of the thermal zone - * @param[in] is_cooling Whether to get the cooling metric (true) or temperature metric (false) - * @param[out] metric_index Pointer to store the metric index - */ -void wos_thermal_get_metric_index(uint8_t zone_id, bool is_cooling, uint16_t* metric_index) { - if (metric_index == NULL) { - return; - } - - if (zone_id >= MAX_THERMAL_ZONE_ID) { - *metric_index = 0xFFFF; // Invalid zone ID - return; - } - if (true == is_cooling) { - *metric_index = g_zone_id_to_metric_index_map[zone_id][1]; - } else { - *metric_index = g_zone_id_to_metric_index_map[zone_id][0]; - } -} +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file wos_thermal_info.c + * @brief Metric initialization implementation for WOS Thermal backend + * @author Skand Gupta (skangupt@qti.qualcomm.com) + * + * This file implements the initialization function that populates metric + * information structures with static definitions for the WOS Thermal backend's + * temperature and passive cooling monitoring capability. + * + * The implementation initializes metric information for 22 thermal zones, with + * each zone having two metrics: temperature (in degrees Celsius) and passive + * cooling (as a percentage). These metrics are used by the WOS Thermal backend + * to report thermal conditions to applications. + */ + +#include +#include +#include "wos_thermal_info.h" +#include "wos_thermal_logger.h" +#include "qcperf_common.h" +#include "thermal_common.h" + +// Mapping from zone ID to metric indices [0] = temperature metric, [1] = cooling metric +static uint16_t g_zone_id_to_metric_index_map[MAX_THERMAL_ZONE_ID][2] = {0}; + +/** + * @brief Initialize WOS Thermal metrics data + * + * This function populates the metric information for WOS Thermal capability + * using the static macro definitions from wos_thermal_info.h. For each thermal + * zone, it initializes two metrics: + * 1. Temperature metric (in degrees Celsius) + * 2. Passive cooling metric (as a percentage) + * + * The function sets the metric ID, name, description, and unit for each metric, + * along with the corresponding string lengths. This information is used by the + * QcPerf framework to provide metadata about the metrics to applications. + * + * @param[out] metrics_data Array to be populated with WOS Thermal metric information + * (must have space for WOS_THERMAL_CAPABILITY_METRIC_COUNT entries) + */ +void wos_thermal_capability_init_metrics(struct QcPerfMetricInfo* metrics_data) { + // CPU Cluster 0 Thermal Zone - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_TEMP].metric_unit); + + // CPU Cluster 0 Thermal Zone - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_0_COOLING].metric_unit); + + // CPU Cluster 1 Thermal Zone - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_TEMP].metric_unit); + + // CPU Cluster 1 Thermal Zone - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_1_COOLING].metric_unit); + + // CPU Cluster 2 Thermal Zone - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_TEMP].metric_unit); + + // CPU Cluster 2 Thermal Zone - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CPU_CLUSTER_2_COOLING].metric_unit); + + // QMX0 Thermal Zone - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_id = WOS_THERMAL_METRIC_QMX0_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX0_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX0_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX0_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_TEMP].metric_unit); + + // QMX0 Thermal Zone - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_id = WOS_THERMAL_METRIC_QMX0_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX0_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX0_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX0_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX0_COOLING].metric_unit); + + // QMX1 Thermal Zone - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_id = WOS_THERMAL_METRIC_QMX1_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX1_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX1_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX1_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_TEMP].metric_unit); + + // QMX1 Thermal Zone - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_id = WOS_THERMAL_METRIC_QMX1_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX1_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX1_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX1_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX1_COOLING].metric_unit); + + // QMX2 Thermal Zone - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_id = WOS_THERMAL_METRIC_QMX2_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX2_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX2_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX2_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_TEMP].metric_unit); + + // QMX2 Thermal Zone - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_id = WOS_THERMAL_METRIC_QMX2_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX2_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX2_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX2_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QMX2_COOLING].metric_unit); + + // GPU Thermal Zone - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_id = WOS_THERMAL_METRIC_GPU_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_GPU_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_GPU_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_GPU_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_TEMP].metric_unit); + + // GPU Thermal Zone - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_id = WOS_THERMAL_METRIC_GPU_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_GPU_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_GPU_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_GPU_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_GPU_COOLING].metric_unit); + + // NSP Thermal Zone - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_id = WOS_THERMAL_METRIC_NSP_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_NSP_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_NSP_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_NSP_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_TEMP].metric_unit); + + // NSP Thermal Zone - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_id = WOS_THERMAL_METRIC_NSP_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_NSP_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_NSP_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_NSP_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_NSP_COOLING].metric_unit); + + // QCLimitsPolicy CPU coreparking - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", + WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_description_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_TEMP].metric_unit); + + // QCLimitsPolicy CPU coreparking - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", + WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_description_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_COREPARKING_COOLING].metric_unit); + + // QCLimitsPolicy CPU DCVS All Clusters - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", + WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_name_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", + WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_description_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", + WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_unit_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP].metric_unit); + + // QCLimitsPolicy CPU DCVS All Clusters - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", + WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_name_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", + WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_description_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", + WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_unit_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING].metric_unit); + + // QCLimitsPolicy CPU DCVS Cluster0 - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", + WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_description_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP].metric_unit); + + // QCLimitsPolicy CPU DCVS Cluster0 - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_name_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", + WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_description_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_unit_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING].metric_unit); + + // QCLimitsPolicy CPU DCVS Cluster1 - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", + WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_description_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP].metric_unit); + + // QCLimitsPolicy CPU DCVS Cluster1 - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_name_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", + WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_description_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_unit_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING].metric_unit); + + // QCLimitsPolicy CPU DCVS Cluster2 - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", + WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_description_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP].metric_unit); + + // QCLimitsPolicy CPU DCVS Cluster2 - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_name_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", + WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_description_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_unit_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING].metric_unit); + + // QCLimitsPolicy GPU - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_TEMP].metric_unit); + + // QCLimitsPolicy GPU - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_GPU_COOLING].metric_unit); + + // QCLimitsPolicy NSP - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_TEMP].metric_unit); + + // QCLimitsPolicy NSP - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_NSP_COOLING].metric_unit); + + // QCLimitsPolicy Modem BCL - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_TEMP].metric_unit); + + // QCLimitsPolicy Modem BCL - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", + WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_BCL_COOLING].metric_unit); + + // QCLimitsPolicy Modem Skin - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_TEMP].metric_unit); + + // QCLimitsPolicy Modem Skin - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", + WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_description_len = + strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_MODEM_SKIN_COOLING].metric_unit); + + // QCLimitsPolicy WLAN - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_TEMP].metric_unit); + + // QCLimitsPolicy WLAN - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_QCLIMITSPOLICY_WLAN_COOLING].metric_unit); + + // Critical Thermal Zones for All Internal TSENS - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_id = WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_TEMP].metric_unit); + + // Critical Thermal Zones for All Internal TSENS - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_id = WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_CRITICAL_THERMAL_ZONES_COOLING].metric_unit); + + // EC thermistor 1 - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_TEMP].metric_unit); + + // EC thermistor 1 - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_1_COOLING].metric_unit); + + // EC thermistor 2 - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_TEMP].metric_unit); + + // EC thermistor 2 - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_2_COOLING].metric_unit); + + // EC thermistor 3 - Temperature + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_TEMP].metric_unit); + + // EC thermistor 3 - Passive Cooling + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_ID; + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_NAME); + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_name_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_name); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_DESCRIPTION); + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_description_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_description); + snprintf(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_UNIT); + metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_unit_len = strlen(metrics_data[WOS_THERMAL_METRIC_INDEX_EC_THERMISTOR_3_COOLING].metric_unit); +} + +/** + * @brief Initialize WOS Thermal metrics data for available zones + * + * This function queries the available thermal zones and initializes metrics + * only for those zones that are actually present on the system. + * It maps the zone names to the predefined metrics in the header file. + * + * @param[out] metrics_data Array to be populated with WOS Thermal metric information + * @param[out] metric_count Pointer to store the number of metrics initialized + */ +void wos_thermal_capability_init_available_metrics(struct QcPerfMetricInfo* metrics_data, uint8_t* metric_count) { + struct ThermalCommonZoneNameMap zone_map = {0}; + enum ThermalCommonReturnCode common_ret = RETURN_CODE_THERMAL_COMMON_SUCCESS; + uint8_t metric_index = 0; + + // Clear the zone ID to metric index mapping + memset(g_zone_id_to_metric_index_map, 0xFF, sizeof(g_zone_id_to_metric_index_map)); + + // Initialize metric count to 0 + if (NULL == metric_count) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Metric count pointer is NULL"); + return; + } else { + *metric_count = 0; + // Get available thermal zones + common_ret = thermal_common_getzone_names(&zone_map); + if (RETURN_CODE_THERMAL_COMMON_SUCCESS != common_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to get thermal zone names, error: %d", common_ret); + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_INFO, "Found %d thermal zones", zone_map.zone_names_ids_length); + + // Create a mapping between zone IDs and metric indices + for (uint8_t i = 0; i < zone_map.zone_names_ids_length; i++) { + uint8_t zone_id = zone_map.zone_ids[i]; + const char* zone_name = zone_map.zone_names[i].string; + bool found_match = false; + + if (zone_id >= MAX_THERMAL_ZONE_ID) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "Zone ID %d exceeds maximum allowed (%d), skipping", zone_id, MAX_THERMAL_ZONE_ID - 1); + continue; + } else { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Initializing metrics for zone %d: %s", zone_id, zone_name); + // Check if this zone matches any of our predefined zones + // CPU Cluster 0 + if (strstr(zone_name, WOS_THERMAL_METRIC_CPU_CLUSTER_0_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_0_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // CPU Cluster 1 + else if (strstr(zone_name, WOS_THERMAL_METRIC_CPU_CLUSTER_1_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_1_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // CPU Cluster 2 + else if (strstr(zone_name, WOS_THERMAL_METRIC_CPU_CLUSTER_2_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CPU_CLUSTER_2_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // QMX0 + else if (strstr(zone_name, WOS_THERMAL_METRIC_QMX0_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QMX0_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX0_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX0_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX0_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QMX0_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX0_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX0_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX0_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // QMX1 + else if (strstr(zone_name, WOS_THERMAL_METRIC_QMX1_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QMX1_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX1_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX1_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX1_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QMX1_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX1_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX1_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX1_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // QMX2 + else if (strstr(zone_name, WOS_THERMAL_METRIC_QMX2_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QMX2_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX2_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX2_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX2_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QMX2_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QMX2_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QMX2_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QMX2_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // GPU + else if (strstr(zone_name, WOS_THERMAL_METRIC_GPU_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_GPU_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_GPU_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_GPU_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_GPU_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_GPU_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_GPU_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_GPU_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_GPU_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // NSP + else if (strstr(zone_name, WOS_THERMAL_METRIC_NSP_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_NSP_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_NSP_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_NSP_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_NSP_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_NSP_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_NSP_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_NSP_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_NSP_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // QCLimitsPolicy CPU coreparking + else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_COREPARKING_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // QCLimitsPolicy CPU DCVS All Clusters + else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_ALL_CLUSTERS_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // QCLimitsPolicy CPU DCVS Cluster0 + else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER0_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // QCLimitsPolicy CPU DCVS Cluster1 + else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER1_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // QCLimitsPolicy CPU DCVS Cluster2 + else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_CPU_DCVS_CLUSTER2_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // QCLimitsPolicy GPU + else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_ZONE_NAME) != NULL && strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_ZONE_NAME) == zone_name) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_GPU_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // QCLimitsPolicy NSP + else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_NSP_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // QCLimitsPolicy Modem BCL + else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_BCL_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // QCLimitsPolicy Modem Skin + else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_MODEM_SKIN_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // QCLimitsPolicy WLAN + else if (strstr(zone_name, WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_QCLIMITSPOLICY_WLAN_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // Critical Thermal Zones + else if (strstr(zone_name, WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_CRITICAL_THERMAL_ZONES_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // EC thermistor 1 + else if (strstr(zone_name, WOS_THERMAL_METRIC_EC_THERMISTOR_1_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_1_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // EC thermistor 2 + else if (strstr(zone_name, WOS_THERMAL_METRIC_EC_THERMISTOR_2_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_2_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + // EC thermistor 3 + else if (strstr(zone_name, WOS_THERMAL_METRIC_EC_THERMISTOR_3_ZONE_NAME) != NULL) { + // Temperature metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_TEMP_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][0] = metric_index; + metric_index++; + + // Cooling metric + metrics_data[metric_index].metric_id = WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_ID; + snprintf(metrics_data[metric_index].metric_name, METRIC_NAME_MAX_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_NAME); + metrics_data[metric_index].metric_name_len = strlen(metrics_data[metric_index].metric_name); + snprintf(metrics_data[metric_index].metric_description, MAX_METRIC_DESCRIPTION_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_DESCRIPTION); + metrics_data[metric_index].metric_description_len = strlen(metrics_data[metric_index].metric_description); + snprintf(metrics_data[metric_index].metric_unit, MAX_METRIC_UNIT_LEN, "%s", WOS_THERMAL_METRIC_EC_THERMISTOR_3_COOLING_UNIT); + metrics_data[metric_index].metric_unit_len = strlen(metrics_data[metric_index].metric_unit); + + // Store mapping + g_zone_id_to_metric_index_map[zone_id][1] = metric_index; + metric_index++; + found_match = true; + } + + // If no match was found, use generic naming + if (!found_match) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Metric not defined for zone : %s", zone_name); + } + } + } + + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Initialized %d metrics for %d thermal zones", metric_index, zone_map.zone_names_ids_length); + } + // Set the metric count + *metric_count = metric_index; + } +} + +/** + * @brief Get metric index for a thermal zone and metric type + * + * @param[in] zone_id ID of the thermal zone + * @param[in] is_cooling Whether to get the cooling metric (true) or temperature metric (false) + * @param[out] metric_index Pointer to store the metric index + */ +void wos_thermal_get_metric_index(uint8_t zone_id, bool is_cooling, uint16_t* metric_index) { + if (metric_index == NULL) { + return; + } + + if (zone_id >= MAX_THERMAL_ZONE_ID) { + *metric_index = 0xFFFF; // Invalid zone ID + return; + } + if (true == is_cooling) { + *metric_index = g_zone_id_to_metric_index_map[zone_id][1]; + } else { + *metric_index = g_zone_id_to_metric_index_map[zone_id][0]; + } +} diff --git a/qcperf/backends/wos-thermal/src/wos_thermal_lib.c b/qcperf/backends/wos-thermal/src/wos_thermal_lib.c index 28661b0..c748c36 100644 --- a/qcperf/backends/wos-thermal/src/wos_thermal_lib.c +++ b/qcperf/backends/wos-thermal/src/wos_thermal_lib.c @@ -1,271 +1,271 @@ -/* - Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - Redistribution and use in source and binary forms, with or without - modification, are permitted (subject to the limitations in the - disclaimer below) provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Qualcomm Technologies, Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE - GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT - HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/** - * @file wos_thermal_lib.c - * @brief Implementation of the WOS Thermal library - * @author Skand Gupta (skangupt@qti.qualcomm.com) - * - * This file implements the public API functions defined in wos_thermal_lib.h, - * providing functionality for monitoring thermal zones and passive cooling on - * Windows platforms. It uses the CPU-thermal-etw library to collect temperature - * and passive cooling data from the system. - * - * The implementation includes functions for initializing the library, starting - * and stopping data collection, retrieving thermal zone information, and cleaning - * up resources. It uses a separate thread for continuous data collection at - * specified sampling and streaming rates. - */ - -#include -#include -#include - -#include "wos_thermal_lib.h" -#include "wos_thermal_logger.h" -#include "cpu_thermal_etw_library.h" -#include "passive_cooling.h" -#include "thermal_common.h" -#include "qthread.h" -#include "qtime.h" - -// Static variables -static volatile bool g_is_initialized = false; -static struct ThermalCommonZoneNameMap g_zone_name_map = {0}; -static struct ThermalInfoQuery g_temperature_query = {0}; -static struct PassiveCoolingInfoQuery g_passive_cooling_query = {0}; - -enum WosThermalLibReturnCode wos_thermal_lib_init(void) { - enum WosThermalLibReturnCode return_code = WOS_THERMAL_LIB_SUCCESS; - enum CpuThermalETWReturnCode thermal_ret = RETURN_CODE_CPU_THERMAL_SUCCESS; - enum PassiveCoolingReturnCode cooling_ret = RETURN_CODE_PASSIVE_COOLING_SUCCESS; - enum ThermalCommonReturnCode common_ret = RETURN_CODE_THERMAL_COMMON_SUCCESS; - - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Initializing WOS Thermal library"); - - if (true == g_is_initialized) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "WOS Thermal library is already initialized"); - return_code = WOS_THERMAL_LIB_ERROR_ALREADY_INITIALIZED; - } else { - // Initialize thermal common - common_ret = thermal_common_init(); - if (RETURN_CODE_THERMAL_COMMON_SUCCESS != common_ret) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to initialize thermal common, error: %d", common_ret); - return_code = WOS_THERMAL_LIB_ERROR_THERMAL_COMMON_INIT_FAILED; - } else { - // Get zone names - common_ret = thermal_common_getzone_names(&g_zone_name_map); - if (RETURN_CODE_THERMAL_COMMON_SUCCESS != common_ret) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to get thermal zone names, error: %d", common_ret); - thermal_common_cleanup(); - return_code = WOS_THERMAL_LIB_ERROR_GET_ZONE_NAMES_FAILED; - } else { - // Debug: Print all available thermal zones - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Found %d thermal zones:", g_zone_name_map.zone_names_ids_length); - // Initialize thermal sensor - thermal_ret = thermal_sensor_init(&g_zone_name_map); - if (RETURN_CODE_CPU_THERMAL_SUCCESS != thermal_ret) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to initialize thermal sensor, error: %d", thermal_ret); - thermal_common_cleanup(); - return_code = WOS_THERMAL_LIB_ERROR_THERMAL_SENSOR_INIT_FAILED; - } else { - // Initialize passive cooling - cooling_ret = passive_cooling_init(&g_zone_name_map); - if (RETURN_CODE_PASSIVE_COOLING_SUCCESS != cooling_ret) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to initialize passive cooling, error: %d", cooling_ret); - thermal_sensor_cleanup(); - thermal_common_cleanup(); - return_code = WOS_THERMAL_LIB_ERROR_PASSIVE_COOLING_INIT_FAILED; - } else { - // Allocate memory for temperature and passive cooling queries - g_temperature_query.temperatures_length = MAX_THERMAL_ZONES; - g_temperature_query.temperatures = (double*)calloc(g_temperature_query.temperatures_length, sizeof(double)); - if (NULL == g_temperature_query.temperatures) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to allocate memory for temperature query"); - passive_cooling_cleanup(); - thermal_sensor_cleanup(); - thermal_common_cleanup(); - return_code = WOS_THERMAL_LIB_ERROR_MEMORY_ALLOCATION; - } else { - g_passive_cooling_query.passive_cooling_length = MAX_THERMAL_ZONES; - g_passive_cooling_query.passive_cooling = (double*)calloc(g_passive_cooling_query.passive_cooling_length, sizeof(double)); - if (NULL == g_passive_cooling_query.passive_cooling) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to allocate memory for passive cooling query"); - free(g_temperature_query.temperatures); - g_temperature_query.temperatures = NULL; - passive_cooling_cleanup(); - thermal_sensor_cleanup(); - thermal_common_cleanup(); - return_code = WOS_THERMAL_LIB_ERROR_MEMORY_ALLOCATION; - } else { - g_is_initialized = true; - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "WOS Thermal library initialized successfully"); - } - } - } - } - } - } - } - - return return_code; -} - -enum WosThermalLibReturnCode wos_thermal_lib_cleanup(void) { - enum WosThermalLibReturnCode return_code = WOS_THERMAL_LIB_SUCCESS; - enum CpuThermalETWReturnCode thermal_ret = RETURN_CODE_CPU_THERMAL_SUCCESS; - enum PassiveCoolingReturnCode cooling_ret = RETURN_CODE_PASSIVE_COOLING_SUCCESS; - enum ThermalCommonReturnCode common_ret = RETURN_CODE_THERMAL_COMMON_SUCCESS; - - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Cleaning up WOS Thermal library"); - - if (false == g_is_initialized) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "WOS Thermal library is not initialized"); - return_code = WOS_THERMAL_LIB_ERROR_NOT_INITIALIZED; - } else { - // Free allocated memory - if (NULL != g_temperature_query.temperatures) { - free(g_temperature_query.temperatures); - g_temperature_query.temperatures = NULL; - } - - if (NULL != g_passive_cooling_query.passive_cooling) { - free(g_passive_cooling_query.passive_cooling); - g_passive_cooling_query.passive_cooling = NULL; - } - - // Clean up passive cooling - cooling_ret = passive_cooling_cleanup(); - if (RETURN_CODE_PASSIVE_COOLING_SUCCESS != cooling_ret) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to clean up passive cooling, error: %d", cooling_ret); - return_code = WOS_THERMAL_LIB_ERROR_PASSIVE_COOLING_CLEANUP_FAILED; - // Continue with cleanup anyway - } - - // Clean up thermal sensor - thermal_ret = thermal_sensor_cleanup(); - if (RETURN_CODE_CPU_THERMAL_SUCCESS != thermal_ret) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to clean up thermal sensor, error: %d", thermal_ret); - return_code = WOS_THERMAL_LIB_ERROR_THERMAL_SENSOR_CLEANUP_FAILED; - // Continue with cleanup anyway - } - - // Clean up thermal common - common_ret = thermal_common_cleanup(); - if (RETURN_CODE_THERMAL_COMMON_SUCCESS != common_ret) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to clean up thermal common, error: %d", common_ret); - return_code = WOS_THERMAL_LIB_ERROR_THERMAL_COMMON_CLEANUP_FAILED; - // Continue with cleanup anyway - } - - g_is_initialized = false; - } - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "WOS Thermal library cleaned up successfully"); - - return return_code; -} - -enum WosThermalLibReturnCode wos_thermal_lib_get_zone_count(uint8_t* zone_count) { - enum WosThermalLibReturnCode return_code = WOS_THERMAL_LIB_ERROR_FAILED; - - if (false == g_is_initialized) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "WOS Thermal library is not initialized"); - return_code = WOS_THERMAL_LIB_ERROR_NOT_INITIALIZED; - } else if (NULL == zone_count) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Zone count pointer is NULL"); - return_code = WOS_THERMAL_LIB_ERROR_NULL_POINTER; - } else { - *zone_count = g_zone_name_map.zone_names_ids_length; - return_code = WOS_THERMAL_LIB_SUCCESS; - } - return return_code; -} - -/** - * @brief Get thermal zone information - * - * This function returns information about all thermal zones, including - * temperature and passive cooling data. It populates the provided thermal_data - * structure with the current thermal zone information, including zone IDs, - * names, temperatures, and passive cooling percentages. - * - * The function uses the global zone name map that was populated during - * initialization to identify thermal zones and retrieve their current state. - * - * @param[out] thermal_data Pointer to store thermal zone data - * - * @return WOS_THERMAL_LIB_SUCCESS on success - * @return WOS_THERMAL_LIB_ERROR_NOT_INITIALIZED if library is not initialized - * @return WOS_THERMAL_LIB_ERROR_NULL_POINTER if thermal_data is NULL - * @return WOS_THERMAL_LIB_ERROR_GET_THERMAL_INFO_FAILED if getting thermal info fails - * @return WOS_THERMAL_LIB_ERROR_GET_PASSIVE_COOLING_INFO_FAILED if getting passive cooling info fails - */ -enum WosThermalLibReturnCode wos_thermal_lib_get_zone_info(struct WosThermalData* thermal_data) { - enum WosThermalLibReturnCode return_code = WOS_THERMAL_LIB_ERROR_FAILED; - enum CpuThermalETWReturnCode thermal_ret = RETURN_CODE_CPU_THERMAL_SUCCESS; - enum PassiveCoolingReturnCode cooling_ret = RETURN_CODE_PASSIVE_COOLING_SUCCESS; - - uint64_t current_time_ns = 0; - if (false == g_is_initialized) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "WOS Thermal library is not initialized"); - return_code = WOS_THERMAL_LIB_ERROR_NOT_INITIALIZED; - } else if (NULL == thermal_data) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Data pointer is NULL"); - return_code = WOS_THERMAL_LIB_ERROR_NULL_POINTER; - } else { - return_code = get_time_ns(¤t_time_ns); - thermal_data->timestamp = current_time_ns; - // Get thermal data - thermal_ret = thermal_sensor_get_info(&g_temperature_query); - if (RETURN_CODE_CPU_THERMAL_SUCCESS != thermal_ret) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to get thermal sensor info, error: %d", thermal_ret); - return_code = WOS_THERMAL_LIB_ERROR_GET_THERMAL_INFO_FAILED; - } else { - // Get passive cooling data - cooling_ret = passive_cooling_get_info(&g_passive_cooling_query); - if (RETURN_CODE_PASSIVE_COOLING_SUCCESS != cooling_ret) { - SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to get passive cooling info, error: %d", cooling_ret); - return_code = WOS_THERMAL_LIB_ERROR_GET_PASSIVE_COOLING_INFO_FAILED; - } else { - // Update thermal data structure - thermal_data->zone_count = g_zone_name_map.zone_names_ids_length; - - for (uint8_t i = 0; i < g_zone_name_map.zone_names_ids_length && i < MAX_THERMAL_ZONES; i++) { - thermal_data->zones[i].zone_id = g_zone_name_map.zone_ids[i]; - thermal_data->zones[i].zone_name_length = strncpy(thermal_data->zones[i].zone_name, (const char*)g_zone_name_map.zone_names[i].string, 64); - thermal_data->zones[i].temperature = g_temperature_query.temperatures[i]; - thermal_data->zones[i].passive_cooling = g_passive_cooling_query.passive_cooling[i]; - } - return_code = WOS_THERMAL_LIB_SUCCESS; - } - } - } - - return return_code; -} +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file wos_thermal_lib.c + * @brief Implementation of the WOS Thermal library + * @author Skand Gupta (skangupt@qti.qualcomm.com) + * + * This file implements the public API functions defined in wos_thermal_lib.h, + * providing functionality for monitoring thermal zones and passive cooling on + * Windows platforms. It uses the CPU-thermal-etw library to collect temperature + * and passive cooling data from the system. + * + * The implementation includes functions for initializing the library, starting + * and stopping data collection, retrieving thermal zone information, and cleaning + * up resources. It uses a separate thread for continuous data collection at + * specified sampling and streaming rates. + */ + +#include +#include +#include + +#include "wos_thermal_lib.h" +#include "wos_thermal_logger.h" +#include "cpu_thermal_etw_library.h" +#include "passive_cooling.h" +#include "thermal_common.h" +#include "QThread.h" +#include "qtime.h" + +// Static variables +static volatile bool g_is_initialized = false; +static struct ThermalCommonZoneNameMap g_zone_name_map = {0}; +static struct ThermalInfoQuery g_temperature_query = {0}; +static struct PassiveCoolingInfoQuery g_passive_cooling_query = {0}; + +enum WosThermalLibReturnCode wos_thermal_lib_init(void) { + enum WosThermalLibReturnCode return_code = WOS_THERMAL_LIB_SUCCESS; + enum CpuThermalETWReturnCode thermal_ret = RETURN_CODE_CPU_THERMAL_SUCCESS; + enum PassiveCoolingReturnCode cooling_ret = RETURN_CODE_PASSIVE_COOLING_SUCCESS; + enum ThermalCommonReturnCode common_ret = RETURN_CODE_THERMAL_COMMON_SUCCESS; + + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Initializing WOS Thermal library"); + + if (true == g_is_initialized) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "WOS Thermal library is already initialized"); + return_code = WOS_THERMAL_LIB_ERROR_ALREADY_INITIALIZED; + } else { + // Initialize thermal common + common_ret = thermal_common_init(); + if (RETURN_CODE_THERMAL_COMMON_SUCCESS != common_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to initialize thermal common, error: %d", common_ret); + return_code = WOS_THERMAL_LIB_ERROR_THERMAL_COMMON_INIT_FAILED; + } else { + // Get zone names + common_ret = thermal_common_getzone_names(&g_zone_name_map); + if (RETURN_CODE_THERMAL_COMMON_SUCCESS != common_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to get thermal zone names, error: %d", common_ret); + thermal_common_cleanup(); + return_code = WOS_THERMAL_LIB_ERROR_GET_ZONE_NAMES_FAILED; + } else { + // Debug: Print all available thermal zones + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Found %d thermal zones:", g_zone_name_map.zone_names_ids_length); + // Initialize thermal sensor + thermal_ret = thermal_sensor_init(&g_zone_name_map); + if (RETURN_CODE_CPU_THERMAL_SUCCESS != thermal_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to initialize thermal sensor, error: %d", thermal_ret); + thermal_common_cleanup(); + return_code = WOS_THERMAL_LIB_ERROR_THERMAL_SENSOR_INIT_FAILED; + } else { + // Initialize passive cooling + cooling_ret = passive_cooling_init(&g_zone_name_map); + if (RETURN_CODE_PASSIVE_COOLING_SUCCESS != cooling_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to initialize passive cooling, error: %d", cooling_ret); + thermal_sensor_cleanup(); + thermal_common_cleanup(); + return_code = WOS_THERMAL_LIB_ERROR_PASSIVE_COOLING_INIT_FAILED; + } else { + // Allocate memory for temperature and passive cooling queries + g_temperature_query.temperatures_length = MAX_THERMAL_ZONES; + g_temperature_query.temperatures = (double*)calloc(g_temperature_query.temperatures_length, sizeof(double)); + if (NULL == g_temperature_query.temperatures) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to allocate memory for temperature query"); + passive_cooling_cleanup(); + thermal_sensor_cleanup(); + thermal_common_cleanup(); + return_code = WOS_THERMAL_LIB_ERROR_MEMORY_ALLOCATION; + } else { + g_passive_cooling_query.passive_cooling_length = MAX_THERMAL_ZONES; + g_passive_cooling_query.passive_cooling = (double*)calloc(g_passive_cooling_query.passive_cooling_length, sizeof(double)); + if (NULL == g_passive_cooling_query.passive_cooling) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to allocate memory for passive cooling query"); + free(g_temperature_query.temperatures); + g_temperature_query.temperatures = NULL; + passive_cooling_cleanup(); + thermal_sensor_cleanup(); + thermal_common_cleanup(); + return_code = WOS_THERMAL_LIB_ERROR_MEMORY_ALLOCATION; + } else { + g_is_initialized = true; + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "WOS Thermal library initialized successfully"); + } + } + } + } + } + } + } + + return return_code; +} + +enum WosThermalLibReturnCode wos_thermal_lib_cleanup(void) { + enum WosThermalLibReturnCode return_code = WOS_THERMAL_LIB_SUCCESS; + enum CpuThermalETWReturnCode thermal_ret = RETURN_CODE_CPU_THERMAL_SUCCESS; + enum PassiveCoolingReturnCode cooling_ret = RETURN_CODE_PASSIVE_COOLING_SUCCESS; + enum ThermalCommonReturnCode common_ret = RETURN_CODE_THERMAL_COMMON_SUCCESS; + + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "Cleaning up WOS Thermal library"); + + if (false == g_is_initialized) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_WARNING, "WOS Thermal library is not initialized"); + return_code = WOS_THERMAL_LIB_ERROR_NOT_INITIALIZED; + } else { + // Free allocated memory + if (NULL != g_temperature_query.temperatures) { + free(g_temperature_query.temperatures); + g_temperature_query.temperatures = NULL; + } + + if (NULL != g_passive_cooling_query.passive_cooling) { + free(g_passive_cooling_query.passive_cooling); + g_passive_cooling_query.passive_cooling = NULL; + } + + // Clean up passive cooling + cooling_ret = passive_cooling_cleanup(); + if (RETURN_CODE_PASSIVE_COOLING_SUCCESS != cooling_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to clean up passive cooling, error: %d", cooling_ret); + return_code = WOS_THERMAL_LIB_ERROR_PASSIVE_COOLING_CLEANUP_FAILED; + // Continue with cleanup anyway + } + + // Clean up thermal sensor + thermal_ret = thermal_sensor_cleanup(); + if (RETURN_CODE_CPU_THERMAL_SUCCESS != thermal_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to clean up thermal sensor, error: %d", thermal_ret); + return_code = WOS_THERMAL_LIB_ERROR_THERMAL_SENSOR_CLEANUP_FAILED; + // Continue with cleanup anyway + } + + // Clean up thermal common + common_ret = thermal_common_cleanup(); + if (RETURN_CODE_THERMAL_COMMON_SUCCESS != common_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to clean up thermal common, error: %d", common_ret); + return_code = WOS_THERMAL_LIB_ERROR_THERMAL_COMMON_CLEANUP_FAILED; + // Continue with cleanup anyway + } + + g_is_initialized = false; + } + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_DEBUG, "WOS Thermal library cleaned up successfully"); + + return return_code; +} + +enum WosThermalLibReturnCode wos_thermal_lib_get_zone_count(uint8_t* zone_count) { + enum WosThermalLibReturnCode return_code = WOS_THERMAL_LIB_ERROR_FAILED; + + if (false == g_is_initialized) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "WOS Thermal library is not initialized"); + return_code = WOS_THERMAL_LIB_ERROR_NOT_INITIALIZED; + } else if (NULL == zone_count) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Zone count pointer is NULL"); + return_code = WOS_THERMAL_LIB_ERROR_NULL_POINTER; + } else { + *zone_count = g_zone_name_map.zone_names_ids_length; + return_code = WOS_THERMAL_LIB_SUCCESS; + } + return return_code; +} + +/** + * @brief Get thermal zone information + * + * This function returns information about all thermal zones, including + * temperature and passive cooling data. It populates the provided thermal_data + * structure with the current thermal zone information, including zone IDs, + * names, temperatures, and passive cooling percentages. + * + * The function uses the global zone name map that was populated during + * initialization to identify thermal zones and retrieve their current state. + * + * @param[out] thermal_data Pointer to store thermal zone data + * + * @return WOS_THERMAL_LIB_SUCCESS on success + * @return WOS_THERMAL_LIB_ERROR_NOT_INITIALIZED if library is not initialized + * @return WOS_THERMAL_LIB_ERROR_NULL_POINTER if thermal_data is NULL + * @return WOS_THERMAL_LIB_ERROR_GET_THERMAL_INFO_FAILED if getting thermal info fails + * @return WOS_THERMAL_LIB_ERROR_GET_PASSIVE_COOLING_INFO_FAILED if getting passive cooling info fails + */ +enum WosThermalLibReturnCode wos_thermal_lib_get_zone_info(struct WosThermalData* thermal_data) { + enum WosThermalLibReturnCode return_code = WOS_THERMAL_LIB_ERROR_FAILED; + enum CpuThermalETWReturnCode thermal_ret = RETURN_CODE_CPU_THERMAL_SUCCESS; + enum PassiveCoolingReturnCode cooling_ret = RETURN_CODE_PASSIVE_COOLING_SUCCESS; + + uint64_t current_time_ns = 0; + if (false == g_is_initialized) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "WOS Thermal library is not initialized"); + return_code = WOS_THERMAL_LIB_ERROR_NOT_INITIALIZED; + } else if (NULL == thermal_data) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Data pointer is NULL"); + return_code = WOS_THERMAL_LIB_ERROR_NULL_POINTER; + } else { + return_code = get_time_ns(¤t_time_ns); + thermal_data->timestamp = current_time_ns; + // Get thermal data + thermal_ret = thermal_sensor_get_info(&g_temperature_query); + if (RETURN_CODE_CPU_THERMAL_SUCCESS != thermal_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to get thermal sensor info, error: %d", thermal_ret); + return_code = WOS_THERMAL_LIB_ERROR_GET_THERMAL_INFO_FAILED; + } else { + // Get passive cooling data + cooling_ret = passive_cooling_get_info(&g_passive_cooling_query); + if (RETURN_CODE_PASSIVE_COOLING_SUCCESS != cooling_ret) { + SEND_MESSAGE(QC_PERF_MESSAGE_LEVEL_ERROR, "Failed to get passive cooling info, error: %d", cooling_ret); + return_code = WOS_THERMAL_LIB_ERROR_GET_PASSIVE_COOLING_INFO_FAILED; + } else { + // Update thermal data structure + thermal_data->zone_count = g_zone_name_map.zone_names_ids_length; + + for (uint8_t i = 0; i < g_zone_name_map.zone_names_ids_length && i < MAX_THERMAL_ZONES; i++) { + thermal_data->zones[i].zone_id = g_zone_name_map.zone_ids[i]; + thermal_data->zones[i].zone_name_length = strncpy(thermal_data->zones[i].zone_name, (const char*)g_zone_name_map.zone_names[i].string, 64); + thermal_data->zones[i].temperature = g_temperature_query.temperatures[i]; + thermal_data->zones[i].passive_cooling = g_passive_cooling_query.passive_cooling[i]; + } + return_code = WOS_THERMAL_LIB_SUCCESS; + } + } + } + + return return_code; +} diff --git a/qcperf/backends/wos-thermal/src/wos_thermal_logger.c b/qcperf/backends/wos-thermal/src/wos_thermal_logger.c index fcf408c..224cddc 100644 --- a/qcperf/backends/wos-thermal/src/wos_thermal_logger.c +++ b/qcperf/backends/wos-thermal/src/wos_thermal_logger.c @@ -1,72 +1,72 @@ -/* - Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - Redistribution and use in source and binary forms, with or without - modification, are permitted (subject to the limitations in the - disclaimer below) provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Qualcomm Technologies, Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE - GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT - HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/** - * @file wos_thermal_logger.c - * @brief Implementation of the WOS Thermal logger functionality - * @author Skand Gupta (skangupt@qti.qualcomm.com) - * - * This file implements the logging functionality for the WOS Thermal backend. - * It provides functions for setting a message callback and sending formatted - * messages to the registered callback. These messages can include informational, - * warning, or error messages related to the WOS Thermal backend's operation. - * - * The implementation uses a simple callback mechanism to deliver messages to - * the application, allowing for flexible handling of log messages based on - * their severity level. - */ - -#include -#include -#include -#include "wos_thermal_logger.h" -#include "qcperf_backend_enum.h" - -static QcPerfMessageCallback g_message_callback = NULL; - -void wos_thermal_logger_set_message_callback(QcPerfMessageCallback message_callback) { g_message_callback = message_callback; } - -void wos_thermal_logger_send_message(enum QcPerfMessageLevel level, const char* format, ...) { - if (NULL != g_message_callback) { - struct QcPerfMessage message = {0}; - va_list args; - char buffer[MESSAGE_LEVEL_LENGTH] = {0}; - - va_start(args, format); - vsnprintf(buffer, MESSAGE_LEVEL_LENGTH, format, args); - va_end(args); - - message.backend_id = QC_PERF_BACKEND_THERMAL; - message.message = buffer; - message.message_length = strlen(buffer); - message.message_level = level; - - g_message_callback(&message); - } -} +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file wos_thermal_logger.c + * @brief Implementation of the WOS Thermal logger functionality + * @author Skand Gupta (skangupt@qti.qualcomm.com) + * + * This file implements the logging functionality for the WOS Thermal backend. + * It provides functions for setting a message callback and sending formatted + * messages to the registered callback. These messages can include informational, + * warning, or error messages related to the WOS Thermal backend's operation. + * + * The implementation uses a simple callback mechanism to deliver messages to + * the application, allowing for flexible handling of log messages based on + * their severity level. + */ + +#include +#include +#include +#include "wos_thermal_logger.h" +#include "qcperf_backend_enum.h" + +static QcPerfMessageCallback g_message_callback = NULL; + +void wos_thermal_logger_set_message_callback(QcPerfMessageCallback message_callback) { g_message_callback = message_callback; } + +void wos_thermal_logger_send_message(enum QcPerfMessageLevel level, const char* format, ...) { + if (NULL != g_message_callback) { + struct QcPerfMessage message = {0}; + va_list args; + char buffer[MESSAGE_LEVEL_LENGTH] = {0}; + + va_start(args, format); + vsnprintf(buffer, MESSAGE_LEVEL_LENGTH, format, args); + va_end(args); + + message.backend_id = QC_PERF_BACKEND_THERMAL; + message.message = buffer; + message.message_length = strlen(buffer); + message.message_level = level; + + g_message_callback(&message); + } +} diff --git a/qcperf/cmake/BuildConfig.cmake b/qcperf/cmake/BuildConfig.cmake index bc7bd81..fa96a2a 100644 --- a/qcperf/cmake/BuildConfig.cmake +++ b/qcperf/cmake/BuildConfig.cmake @@ -1,294 +1,398 @@ -# ============================================================================ -# QcPerf - Combined Build Configuration -# ============================================================================ -# This file centralizes all build configuration for the QcPerf library: -# - Platform detection (OS and architecture) -# - Platform-specific compiler flags and definitions -# - Compiler configuration and optimization settings -# - Platform types and standard header checks -# -# It is designed to support multiple platforms (Windows, Linux) and -# architectures (x86_64, ARM64) with a focus on Windows ARM64 support. -# ============================================================================ - -# ============================================================================ -# Platform Detection -# ============================================================================ -# Detect operating system and architecture to set appropriate build flags -# and definitions. This enables conditional compilation for platform-specific -# code throughout the project. - -# Detect OS -if(WIN32) - set(QCPERF_OS_WINDOWS TRUE) - message(STATUS "Detected Windows platform") -elseif(UNIX) - set(QCPERF_OS_LINUX TRUE) - message(STATUS "Detected Linux platform") -else() - message(WARNING "Unknown platform detected") -endif() - -# Detect architecture -# For Visual Studio, we need to check CMAKE_VS_PLATFORM_NAME -if(MSVC AND CMAKE_VS_PLATFORM_NAME MATCHES "ARM64") - set(QCPERF_ARCH_ARM64 TRUE) - # Override CMAKE_SYSTEM_PROCESSOR for Visual Studio ARM64 builds - set(CMAKE_SYSTEM_PROCESSOR "ARM64") - message(STATUS "Detected ARM64 architecture (Visual Studio)") -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64|x86_64") - set(QCPERF_ARCH_X86_64 TRUE) - message(STATUS "Detected x86_64 architecture") -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64|arm64") - set(QCPERF_ARCH_ARM64 TRUE) - message(STATUS "Detected ARM64 architecture") -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i686|i386") - set(QCPERF_ARCH_X86 TRUE) - message(STATUS "Detected x86 architecture") -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "armv7|armhf") - set(QCPERF_ARCH_ARM32 TRUE) - message(STATUS "Detected ARM32 architecture") -else() - message(STATUS "Architecture detection using CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}") - if(DEFINED CMAKE_VS_PLATFORM_NAME) - message(STATUS "Visual Studio platform name: ${CMAKE_VS_PLATFORM_NAME}") - endif() - message(WARNING "Unknown architecture - defaulting to x86_64") - set(QCPERF_ARCH_X86_64 TRUE) -endif() - -# Set combined platform variables for convenience -if(QCPERF_OS_WINDOWS AND QCPERF_ARCH_ARM64) - set(QCPERF_PLATFORM_WINDOWS_ARM64 TRUE) -elseif(QCPERF_OS_WINDOWS AND QCPERF_ARCH_X86_64) - set(QCPERF_PLATFORM_WINDOWS_X86_64 TRUE) -elseif(QCPERF_OS_LINUX AND QCPERF_ARCH_ARM64) - set(QCPERF_PLATFORM_LINUX_ARM64 TRUE) -elseif(QCPERF_OS_LINUX AND QCPERF_ARCH_X86_64) - set(QCPERF_PLATFORM_LINUX_X86_64 TRUE) -endif() - -# Print platform summary -message(STATUS "QcPerf Platform Configuration:") -message(STATUS " OS: ${CMAKE_SYSTEM_NAME}") -message(STATUS " Architecture: ${CMAKE_SYSTEM_PROCESSOR}") - -# ============================================================================ -# Platform-Specific Configurations -# ============================================================================ -# Apply platform-specific compiler flags, definitions, and optimizations -# based on the detected OS and architecture combinations. - -# Windows-specific configurations -if(QCPERF_OS_WINDOWS) - # Enable Windows-specific definitions - add_compile_definitions(QCPERF_PLATFORM_WINDOWS) - - # Windows-specific compiler flags - if(MSVC) - # Enable multi-processor compilation - add_compile_options(/MP) - - # Warning level - add_compile_options(/W4) - - # Disable specific warnings if needed - # add_compile_options(/wd4100) # Unused parameter - - # Enable additional security features - add_compile_definitions( - _CRT_SECURE_NO_WARNINGS - _SCL_SECURE_NO_WARNINGS - ) - endif() - - # ARM64 specific configurations - if(QCPERF_PLATFORM_WINDOWS_ARM64) - message(STATUS "Configuring for Windows ARM64") - - # Add ARM64-specific compile definitions - add_compile_definitions(WIN32_ARM64) - endif() - - # x86_64 specific configurations - if(QCPERF_PLATFORM_WINDOWS_X86_64) - message(STATUS "Configuring for Windows x86_64") - endif() - - message(STATUS "Windows platform configuration loaded") -endif() - -# Linux-specific configurations -if(QCPERF_OS_LINUX) - # Enable Linux-specific definitions - add_compile_definitions(QCPERF_PLATFORM_LINUX) - - # Linux-specific compiler flags - if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) - # GCC-specific flags - add_compile_options( - -Wall - -Wextra - -Wpedantic - -fPIC - ) - - # Enable additional warnings - add_compile_options( - -Wcast-align - -Wunused - -Wconversion - -Wsign-conversion - ) - elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - # Clang-specific flags - add_compile_options( - -Wall - -Wextra - -Wpedantic - -fPIC - ) - endif() - - # ARM64 specific configurations - if(QCPERF_PLATFORM_LINUX_ARM64) - message(STATUS "Configuring for Linux ARM64") - - # Add ARM64-specific compile definitions - add_compile_definitions(LINUX_ARM64) - - if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) - # Enable ARM64 specific optimizations - add_compile_options(-march=armv8-a) - endif() - endif() - - message(STATUS "Linux platform configuration loaded") -endif() - -# ============================================================================ -# Compiler Configuration -# ============================================================================ -# Configure compiler settings that apply across all platforms: -# - C language standard -# - Build type (Debug/Release) specific optimizations -# - Warning levels and error handling -# - Code generation options - -# Set C standard -set(CMAKE_C_STANDARD 11) -set(CMAKE_C_STANDARD_REQUIRED ON) - -# Set C++ standard -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -# Set default build type if not specified -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE) -endif() - -message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") - -# Common compiler flags for all platforms -if(MSVC) - # MSVC-specific compiler flags - add_compile_options( - /W4 # Warning level 4 - /WX- # Don't treat warnings as errors (can be changed to /WX if needed) - /MP # Multi-processor compilation - /EHsc # Standard C++ exception handling - /permissive- # Enforce standards conformance - ) - - # Debug-specific flags - if(CMAKE_BUILD_TYPE STREQUAL "Debug") - add_compile_options( - /Zi # Generate debug info - /Od # Disable optimization - /RTC1 # Runtime error checks - ) - endif() - - # Release-specific flags - if(CMAKE_BUILD_TYPE STREQUAL "Release") - add_compile_options( - /O2 # Optimize for speed - /Oi # Enable intrinsic functions - /GL # Whole program optimization - ) - add_link_options( - /LTCG # Link-time code generation - ) - endif() - -else() - # GCC/Clang compiler flags - add_compile_options( - -Wall - -Wextra - -Wpedantic - ) - - # Debug-specific flags - if(CMAKE_BUILD_TYPE STREQUAL "Debug") - add_compile_options( - -g # Generate debug info - -O0 # No optimization - ) - endif() - - # Release-specific flags - if(CMAKE_BUILD_TYPE STREQUAL "Release") - add_compile_options( - -O3 # Optimize for speed - ) - endif() -endif() - -# Enable Position Independent Code for all targets -set(CMAKE_POSITION_INDEPENDENT_CODE ON) - -message(STATUS "Compiler configuration loaded") - -# ============================================================================ -# Platform Types -# ============================================================================ -# Check for standard headers and define fallback types if needed. -# This ensures consistent type definitions across different platforms -# and compiler implementations. - -# Check for stdbool.h and include it if available -include(CheckIncludeFile) -CHECK_INCLUDE_FILE(stdbool.h HAVE_STDBOOL_H) - -if(HAVE_STDBOOL_H) - add_compile_definitions(HAVE_STDBOOL_H) -else() - # Define bool type if stdbool.h is not available - add_compile_definitions( - bool=int - true=1 - false=0 - ) -endif() - -# Check for other standard headers -CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT_H) -CHECK_INCLUDE_FILE(inttypes.h HAVE_INTTYPES_H) -CHECK_INCLUDE_FILE(stddef.h HAVE_STDDEF_H) - -# Add appropriate definitions based on available headers -if(HAVE_STDINT_H) - add_compile_definitions(HAVE_STDINT_H) -endif() - -if(HAVE_INTTYPES_H) - add_compile_definitions(HAVE_INTTYPES_H) -endif() - -if(HAVE_STDDEF_H) - add_compile_definitions(HAVE_STDDEF_H) -endif() - -message(STATUS "Platform types configuration loaded") +# ============================================================================ +# QcPerf - Combined Build Configuration +# ============================================================================ +# This file centralizes all build configuration for the QcPerf library: +# - Platform detection (OS and architecture) +# - Platform-specific compiler flags and definitions +# - Compiler configuration and optimization settings +# - Platform types and standard header checks +# +# It is designed to support multiple platforms (Windows, Linux) and +# architectures (x86_64, ARM64) with a focus on Windows ARM64 support. +# ============================================================================ + +# ============================================================================ +# Platform Detection +# ============================================================================ +# Detect operating system and architecture to set appropriate build flags +# and definitions. This enables conditional compilation for platform-specific +# code throughout the project. + +# Detect OS +if(WIN32) + set(QCPERF_OS_WINDOWS TRUE) + message(STATUS "Detected Windows platform") +elseif(UNIX) + set(QCPERF_OS_LINUX TRUE) + message(STATUS "Detected Linux platform") +else() + message(WARNING "Unknown platform detected") +endif() + +# Detect architecture +# For Visual Studio, we need to check CMAKE_VS_PLATFORM_NAME +if(MSVC AND CMAKE_VS_PLATFORM_NAME MATCHES "ARM64") + set(QCPERF_ARCH_ARM64 TRUE) + # Override CMAKE_SYSTEM_PROCESSOR for Visual Studio ARM64 builds + set(CMAKE_SYSTEM_PROCESSOR "ARM64") + message(STATUS "Detected ARM64 architecture (Visual Studio)") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64|x86_64") + set(QCPERF_ARCH_X86_64 TRUE) + message(STATUS "Detected x86_64 architecture") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64|arm64") + set(QCPERF_ARCH_ARM64 TRUE) + message(STATUS "Detected ARM64 architecture") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i686|i386") + set(QCPERF_ARCH_X86 TRUE) + message(STATUS "Detected x86 architecture") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "armv7|armhf") + set(QCPERF_ARCH_ARM32 TRUE) + message(STATUS "Detected ARM32 architecture") +else() + message(STATUS "Architecture detection using CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}") + if(DEFINED CMAKE_VS_PLATFORM_NAME) + message(STATUS "Visual Studio platform name: ${CMAKE_VS_PLATFORM_NAME}") + endif() + message(WARNING "Unknown architecture - defaulting to x86_64") + set(QCPERF_ARCH_X86_64 TRUE) +endif() + +# Set combined platform variables for convenience +if(QCPERF_OS_WINDOWS AND QCPERF_ARCH_ARM64) + set(QCPERF_PLATFORM_WINDOWS_ARM64 TRUE) +elseif(QCPERF_OS_WINDOWS AND QCPERF_ARCH_X86_64) + set(QCPERF_PLATFORM_WINDOWS_X86_64 TRUE) +elseif(QCPERF_OS_LINUX AND QCPERF_ARCH_ARM64) + set(QCPERF_PLATFORM_LINUX_ARM64 TRUE) +elseif(QCPERF_OS_LINUX AND QCPERF_ARCH_X86_64) + set(QCPERF_PLATFORM_LINUX_X86_64 TRUE) +endif() + +# Print platform summary +message(STATUS "QcPerf Platform Configuration:") +message(STATUS " OS: ${CMAKE_SYSTEM_NAME}") +message(STATUS " Architecture: ${CMAKE_SYSTEM_PROCESSOR}") +if(CMAKE_CROSSCOMPILING) + message(STATUS " Cross-compiling: YES (host=${CMAKE_HOST_SYSTEM_PROCESSOR} -> target=${CMAKE_SYSTEM_PROCESSOR})") + message(STATUS " C compiler: ${CMAKE_C_COMPILER}") +else() + message(STATUS " Cross-compiling: NO (native build)") +endif() + +# ============================================================================ +# Platform-Specific Configurations +# ============================================================================ +# Apply platform-specific compiler flags, definitions, and optimizations +# based on the detected OS and architecture combinations. + +# Windows-specific configurations +if(QCPERF_OS_WINDOWS) + # Enable Windows-specific definitions + add_compile_definitions(QCPERF_PLATFORM_WINDOWS) + + # Windows-specific compiler flags + if(MSVC) + # Enable multi-processor compilation + add_compile_options(/MP) + + # Warning level + add_compile_options(/W4) + + # Disable specific warnings if needed + # add_compile_options(/wd4100) # Unused parameter + + # Enable additional security features + add_compile_definitions( + _CRT_SECURE_NO_WARNINGS + _SCL_SECURE_NO_WARNINGS + ) + endif() + + # ARM64 specific configurations + if(QCPERF_PLATFORM_WINDOWS_ARM64) + message(STATUS "Configuring for Windows ARM64") + + # Add ARM64-specific compile definitions + add_compile_definitions(WIN32_ARM64) + endif() + + # x86_64 specific configurations + if(QCPERF_PLATFORM_WINDOWS_X86_64) + message(STATUS "Configuring for Windows x86_64") + endif() + + message(STATUS "Windows platform configuration loaded") +endif() + +# ============================================================================ +# Backend Selection +# ============================================================================ +# Determine which backends are supported on the current platform. +# For each OS-specific backend, QCPERF_BACKEND_OS_PREFIX_ is set to the +# OS qualifier (e.g. QCOM_LINUX, WOS) so the compile definition becomes +# QCPERF_ENABLED__. DUMMY has no OS prefix and remains QCPERF_ENABLED_DUMMY. +set(QCPERF_PLATFORM_SUPPORTED_BACKENDS "DUMMY") + +if(QCPERF_PLATFORM_LINUX_ARM64) + set(_OS_PREFIX "QCOM_LINUX") + foreach(_BACKEND CPU NPU) + list(APPEND QCPERF_PLATFORM_SUPPORTED_BACKENDS ${_BACKEND}) + set(QCPERF_BACKEND_OS_PREFIX_${_BACKEND} ${_OS_PREFIX}) + endforeach() +endif() + +if(QCPERF_PLATFORM_WINDOWS_ARM64) + set(_OS_PREFIX "WOS") + foreach(_BACKEND THERMAL POWER) + list(APPEND QCPERF_PLATFORM_SUPPORTED_BACKENDS ${_BACKEND}) + set(QCPERF_BACKEND_OS_PREFIX_${_BACKEND} ${_OS_PREFIX}) + endforeach() +endif() + +# If empty (default), all platform-supported backends are enabled. +set(BACKENDS "" CACHE STRING + "Semicolon-separated list of backends to enable (e.g. \"DUMMY;CPU;NPU\"). \ +If empty, all platform-supported backends are enabled.") + +if(BACKENDS) + # User specified an explicit list — enable only those supported on this platform + foreach(_BACKEND_INPUT ${BACKENDS}) + string(TOUPPER "${_BACKEND_INPUT}" _BACKEND) + if(${_BACKEND} IN_LIST QCPERF_PLATFORM_SUPPORTED_BACKENDS) + if(DEFINED QCPERF_BACKEND_OS_PREFIX_${_BACKEND}) + set(_OS_PREFIX ${QCPERF_BACKEND_OS_PREFIX_${_BACKEND}}) + set(QCPERF_ENABLED_${_OS_PREFIX}_${_BACKEND} ON) + message(STATUS "Backend enabled (user selection): ${_OS_PREFIX}_${_BACKEND}") + else() + set(QCPERF_ENABLED_${_BACKEND} ON) + message(STATUS "Backend enabled (user selection): ${_BACKEND}") + endif() + else() + message(WARNING "Backend '${_BACKEND}' is not supported on this platform — skipping.") + endif() + endforeach() +else() + # Default: enable all platform-supported backends + foreach(_BACKEND ${QCPERF_PLATFORM_SUPPORTED_BACKENDS}) + if(DEFINED QCPERF_BACKEND_OS_PREFIX_${_BACKEND}) + set(_OS_PREFIX ${QCPERF_BACKEND_OS_PREFIX_${_BACKEND}}) + set(QCPERF_ENABLED_${_OS_PREFIX}_${_BACKEND} ON) + message(STATUS "Backend enabled (platform default): ${_OS_PREFIX}_${_BACKEND}") + else() + set(QCPERF_ENABLED_${_BACKEND} ON) + message(STATUS "Backend enabled (platform default): ${_BACKEND}") + endif() + endforeach() +endif() + +# Propagate enabled backends as compile definitions for use in source code. +# This loop is automatic — no changes needed here when adding a new backend; +# just add the backend name to the appropriate platform section above. +foreach(_BACKEND ${QCPERF_PLATFORM_SUPPORTED_BACKENDS}) + if(DEFINED QCPERF_BACKEND_OS_PREFIX_${_BACKEND}) + set(_OS_PREFIX ${QCPERF_BACKEND_OS_PREFIX_${_BACKEND}}) + set(_COMPILE_FLAG QCPERF_ENABLED_${_OS_PREFIX}_${_BACKEND}) + else() + set(_COMPILE_FLAG QCPERF_ENABLED_${_BACKEND}) + endif() + if(${_COMPILE_FLAG}) + add_compile_definitions(${_COMPILE_FLAG}) + endif() +endforeach() + +message(STATUS "") +message(STATUS "Enabled backends: ${QCPERF_PLATFORM_SUPPORTED_BACKENDS}") + +# Linux-specific configurations +if(QCPERF_OS_LINUX) + # Enable Linux-specific definitions + add_compile_definitions(QCPERF_PLATFORM_LINUX) + + # Linux-specific compiler flags + if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) + # GCC-specific flags + add_compile_options( + -Wall + -Wextra + -Wpedantic + -fPIC + ) + + # Enable additional warnings + add_compile_options( + -Wcast-align + -Wunused + -Wconversion + -Wsign-conversion + ) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # Clang-specific flags + add_compile_options( + -Wall + -Wextra + -Wpedantic + -fPIC + ) + endif() + + # ARM64 specific configurations + if(QCPERF_PLATFORM_LINUX_ARM64) + message(STATUS "Configuring for Linux ARM64") + + # Add ARM64-specific compile definitions + add_compile_definitions(LINUX_ARM64) + + if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) + # Enable ARM64 specific optimizations + add_compile_options(-march=armv8-a) + endif() + endif() + + if(QCPERF_PLATFORM_LINUX_X86_64) + message(STATUS "Configuring for Linux x86_64") + + # Add x86_64-specific compile definitions if needed + add_compile_definitions(LINUX_X86_64) + endif() + + set(_OS_M "m") + set(_OS_THREAD "pthread") + + message(STATUS "Linux platform configuration loaded") +endif() + +# ============================================================================ +# Compiler Configuration +# ============================================================================ +# Configure compiler settings that apply across all platforms: +# - C language standard +# - Build type (Debug/Release) specific optimizations +# - Warning levels and error handling +# - Code generation options + +# Set C standard +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) + +# Set C++ standard +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Set default build type if not specified +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE) +endif() + +message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") + +# Common compiler flags for all platforms +if(MSVC) + # MSVC-specific compiler flags + add_compile_options( + /W4 # Warning level 4 + /WX- # Don't treat warnings as errors (can be changed to /WX if needed) + /MP # Multi-processor compilation + /EHsc # Standard C++ exception handling + /permissive- # Enforce standards conformance + ) + + # Debug-specific flags + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + add_compile_options( + /Zi # Generate debug info + /Od # Disable optimization + /RTC1 # Runtime error checks + ) + endif() + + # Release-specific flags + if(CMAKE_BUILD_TYPE STREQUAL "Release") + add_compile_options( + /O2 # Optimize for speed + /Oi # Enable intrinsic functions + /GL # Whole program optimization + ) + add_link_options( + /LTCG # Link-time code generation + ) + endif() + +else() + # GCC/Clang compiler flags + add_compile_options( + -Wall + -Wextra + -Wpedantic + ) + + # Debug-specific flags + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + add_compile_options( + -g # Generate debug info + -O0 # No optimization + ) + endif() + + # Release-specific flags + if(CMAKE_BUILD_TYPE STREQUAL "Release") + add_compile_options( + -O3 # Optimize for speed + ) + endif() +endif() + +# Enable Position Independent Code for all targets +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +message(STATUS "Compiler configuration loaded") + +# ============================================================================ +# Platform Types +# ============================================================================ +# Check for standard headers and define fallback types if needed. +# This ensures consistent type definitions across different platforms +# and compiler implementations. + +# When cross-compiling, skip host-based header probes and assume standard +# C11 headers are present in the cross-toolchain (ARM GNU Toolchain ships +# all standard headers). When building natively, probe the host compiler. +if(NOT CMAKE_CROSSCOMPILING) + include(CheckIncludeFile) + CHECK_INCLUDE_FILE(stdbool.h HAVE_STDBOOL_H) + CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT_H) + CHECK_INCLUDE_FILE(inttypes.h HAVE_INTTYPES_H) + CHECK_INCLUDE_FILE(stddef.h HAVE_STDDEF_H) +else() + # Cross-compiling: ARM GNU Toolchain ships all standard C11 headers + message(STATUS "Cross-compiling: skipping host header checks, assuming standard C11 headers present") + set(HAVE_STDBOOL_H TRUE) + set(HAVE_STDINT_H TRUE) + set(HAVE_INTTYPES_H TRUE) + set(HAVE_STDDEF_H TRUE) +endif() + +if(HAVE_STDBOOL_H) + add_compile_definitions(HAVE_STDBOOL_H) +else() + # Define bool type if stdbool.h is not available + add_compile_definitions( + bool=int + true=1 + false=0 + ) +endif() + +# Add appropriate definitions based on available headers +if(HAVE_STDINT_H) + add_compile_definitions(HAVE_STDINT_H) +endif() + +if(HAVE_INTTYPES_H) + add_compile_definitions(HAVE_INTTYPES_H) +endif() + +if(HAVE_STDDEF_H) + add_compile_definitions(HAVE_STDDEF_H) +endif() + +message(STATUS "Platform types configuration loaded") diff --git a/qcperf/cmake/platforms/Windows.cmake b/qcperf/cmake/platforms/Windows.cmake index 2dc4a5c..e4a171a 100644 --- a/qcperf/cmake/platforms/Windows.cmake +++ b/qcperf/cmake/platforms/Windows.cmake @@ -1,94 +1,94 @@ -# ============================================================================ -# QcPerf - Windows Platform Configuration -# ============================================================================ -# This file contains Windows-specific build configurations for the QcPerf library. -# It sets compiler flags, preprocessor definitions, and library dependencies -# specific to Windows platforms, with special handling for different architectures -# (ARM64, x86_64). -# -# This file is included by BuildConfig.cmake when building on Windows platforms. -# ============================================================================ - -# ============================================================================ -# Windows Platform Definitions -# ============================================================================ -# Enable Windows-specific preprocessor definitions for conditional compilation -add_compile_definitions(QCPERF_PLATFORM_WINDOWS) - -# ============================================================================ -# Windows Compiler Configuration -# ============================================================================ -# Configure compiler flags specific to Microsoft Visual C++ (MSVC) -if(MSVC) - # Enable multi-processor compilation - add_compile_options(/MP) - - # Warning level - add_compile_options(/W4) - - # Disable specific warnings if needed - # add_compile_options(/wd4100) # Unused parameter - - # Enable additional security features - add_compile_definitions( - _CRT_SECURE_NO_WARNINGS - _SCL_SECURE_NO_WARNINGS - ) -endif() - -# ============================================================================ -# Windows ARM64 Configuration -# ============================================================================ -# Special handling for Windows on ARM64 architecture (e.g., Surface Pro X) -if(QCPERF_PLATFORM_WINDOWS_ARM64) - message(STATUS "Configuring for Windows ARM64") - - # Add ARM64-specific compile definitions - add_compile_definitions(WIN32_ARM64) - - - if(MSVC) - # ARM64-specific optimizations - # Note: Visual Studio doesn't support /arch:armv8.0 for ARM64 - # It automatically uses the appropriate architecture - - # Additional ARM64-specific optimizations can be added here - endif() - setcompileoptions(_WIN_ARM64) -endif() - -# ============================================================================ -# Windows x86_64 Configuration -# ============================================================================ -# Configuration for standard 64-bit Intel/AMD platforms -if(QCPERF_PLATFORM_WINDOWS_X86_64) - message(STATUS "Configuring for Windows x86_64") - - # Add x86_64-specific compile definitions if needed - # add_compile_definitions(WIN32_X64) - - if(MSVC) - # Enable x86_64 specific optimizations if needed - # add_compile_options(/arch:AVX2) - endif() - setcompileoptions(_WIN_x86_64) -endif() - -# ============================================================================ -# Windows Library Dependencies -# ============================================================================ -# Define Windows-specific libraries that need to be linked with the project -set(QCPERF_WINDOWS_LIBS "") - -# Add Windows-specific libraries if needed -if(QCPERF_OS_WINDOWS) - list(APPEND QCPERF_WINDOWS_LIBS - # Add Windows-specific libraries here - # Example: ws2_32 (Windows Sockets) - ) -endif() - -set(_OS_M "") -set(_OS_THREAD "") - -message(STATUS "Windows platform configuration loaded") +# ============================================================================ +# QcPerf - Windows Platform Configuration +# ============================================================================ +# This file contains Windows-specific build configurations for the QcPerf library. +# It sets compiler flags, preprocessor definitions, and library dependencies +# specific to Windows platforms, with special handling for different architectures +# (ARM64, x86_64). +# +# This file is included by BuildConfig.cmake when building on Windows platforms. +# ============================================================================ + +# ============================================================================ +# Windows Platform Definitions +# ============================================================================ +# Enable Windows-specific preprocessor definitions for conditional compilation +add_compile_definitions(QCPERF_PLATFORM_WINDOWS) + +# ============================================================================ +# Windows Compiler Configuration +# ============================================================================ +# Configure compiler flags specific to Microsoft Visual C++ (MSVC) +if(MSVC) + # Enable multi-processor compilation + add_compile_options(/MP) + + # Warning level + add_compile_options(/W4) + + # Disable specific warnings if needed + # add_compile_options(/wd4100) # Unused parameter + + # Enable additional security features + add_compile_definitions( + _CRT_SECURE_NO_WARNINGS + _SCL_SECURE_NO_WARNINGS + ) +endif() + +# ============================================================================ +# Windows ARM64 Configuration +# ============================================================================ +# Special handling for Windows on ARM64 architecture (e.g., Surface Pro X) +if(QCPERF_PLATFORM_WINDOWS_ARM64) + message(STATUS "Configuring for Windows ARM64") + + # Add ARM64-specific compile definitions + add_compile_definitions(WIN32_ARM64) + + + if(MSVC) + # ARM64-specific optimizations + # Note: Visual Studio doesn't support /arch:armv8.0 for ARM64 + # It automatically uses the appropriate architecture + + # Additional ARM64-specific optimizations can be added here + endif() + setcompileoptions(_WIN_ARM64) +endif() + +# ============================================================================ +# Windows x86_64 Configuration +# ============================================================================ +# Configuration for standard 64-bit Intel/AMD platforms +if(QCPERF_PLATFORM_WINDOWS_X86_64) + message(STATUS "Configuring for Windows x86_64") + + # Add x86_64-specific compile definitions if needed + # add_compile_definitions(WIN32_X64) + + if(MSVC) + # Enable x86_64 specific optimizations if needed + # add_compile_options(/arch:AVX2) + endif() + setcompileoptions(_WIN_x86_64) +endif() + +# ============================================================================ +# Windows Library Dependencies +# ============================================================================ +# Define Windows-specific libraries that need to be linked with the project +set(QCPERF_WINDOWS_LIBS "") + +# Add Windows-specific libraries if needed +if(QCPERF_OS_WINDOWS) + list(APPEND QCPERF_WINDOWS_LIBS + # Add Windows-specific libraries here + # Example: ws2_32 (Windows Sockets) + ) +endif() + +set(_OS_M "") +set(_OS_THREAD "") + +message(STATUS "Windows platform configuration loaded") diff --git a/qcperf/cmake/toolchains/aarch64-linux-gnu.cmake b/qcperf/cmake/toolchains/aarch64-linux-gnu.cmake new file mode 100644 index 0000000..b550262 --- /dev/null +++ b/qcperf/cmake/toolchains/aarch64-linux-gnu.cmake @@ -0,0 +1,99 @@ +# ============================================================================ +# QcPerf - AArch64 Linux Cross-Compilation Toolchain +# ============================================================================ +# This toolchain file configures CMake to cross-compile for Linux AArch64 +# using the ARM GNU Toolchain (aarch64-none-linux-gnu). +# +# Usage: +# set the environment variable before invoking cmake: +# export AARCH64_TOOLCHAIN_PATH=/path/to/arm-gnu-toolchain +# cmake -S qcperf -B build-aarch64 \ +# --toolchain qcperf/cmake/toolchains/aarch64-linux-gnu.cmake \ +# -DCMAKE_BUILD_TYPE=Release +# cmake --build build-aarch64 +# ============================================================================ + +# ---------------------------------------------------------------------------- +# Target system identification +# ---------------------------------------------------------------------------- +# Tell CMake we are building for Linux on AArch64 (not the host x86_64) +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR aarch64) + +# ---------------------------------------------------------------------------- +# Forward AARCH64_TOOLCHAIN_PATH to try_compile sub-projects +# ---------------------------------------------------------------------------- +# CMake re-evaluates the toolchain file during internal compiler ABI detection +# (try_compile). Without this, AARCH64_TOOLCHAIN_PATH would be undefined in +# those sub-projects and the FATAL_ERROR below would trigger. +list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES AARCH64_TOOLCHAIN_PATH) + +# ---------------------------------------------------------------------------- +# Resolve toolchain bin directory +# Priority: +# 1. Environment variable: AARCH64_TOOLCHAIN_PATH= (default) +# 2. CMake cache variable: -DAARCH64_TOOLCHAIN_PATH= (override) +# ---------------------------------------------------------------------------- +if(DEFINED ENV{AARCH64_TOOLCHAIN_PATH}) + set(_TC_BIN "$ENV{AARCH64_TOOLCHAIN_PATH}/bin") + message(STATUS "AArch64 toolchain path (from environment): $ENV{AARCH64_TOOLCHAIN_PATH}") +elseif(DEFINED AARCH64_TOOLCHAIN_PATH) + set(_TC_BIN "${AARCH64_TOOLCHAIN_PATH}/bin") + message(STATUS "AArch64 toolchain path (from CMake variable): ${AARCH64_TOOLCHAIN_PATH}") +else() + message(FATAL_ERROR + "\n" + " AArch64 cross-compiler toolchain path not specified.\n" + "\n" + " Provide the path to the ARM GNU Toolchain root directory using one of:\n" + "\n" + " Environment variable (recommended):\n" + " export AARCH64_TOOLCHAIN_PATH=/path/to/arm-gnu-toolchain\n" + "\n" + " CMake cache variable (override):\n" + " Uncomment AARCH64_TOOLCHAIN_PATH in qcperf/CMakeUserPresets.json\n" + " or pass: cmake ... -DAARCH64_TOOLCHAIN_PATH=/path/to/arm-gnu-toolchain\n" + "\n" + " Example (ARM GNU Toolchain 15.2):\n" + " export AARCH64_TOOLCHAIN_PATH=/path/to/arm-gnu-toolchain-15.2.rel1-x86_64-aarch64-none-linux-gnu\n" + ) +endif() + +# ---------------------------------------------------------------------------- +# Validate the toolchain +# ---------------------------------------------------------------------------- +if(NOT EXISTS "${_TC_BIN}/aarch64-none-linux-gnu-gcc") + message(FATAL_ERROR + "\n" + " Cross-compiler not found at: ${_TC_BIN}/aarch64-none-linux-gnu-gcc\n" + "\n" + " Verify that AARCH64_TOOLCHAIN_PATH points to the toolchain ROOT directory\n" + " (the directory that contains the 'bin/' subdirectory).\n" + "\n" + " Expected structure:\n" + " /\n" + " bin/\n" + " aarch64-none-linux-gnu-gcc\n" + " aarch64-none-linux-gnu-g++\n" + ) +endif() + +# ---------------------------------------------------------------------------- +# Cross-compiler binaries +# ---------------------------------------------------------------------------- +set(CMAKE_C_COMPILER "${_TC_BIN}/aarch64-none-linux-gnu-gcc") +set(CMAKE_CXX_COMPILER "${_TC_BIN}/aarch64-none-linux-gnu-g++") + +message(STATUS "AArch64 C compiler: ${CMAKE_C_COMPILER}") +message(STATUS "AArch64 C++ compiler: ${CMAKE_CXX_COMPILER}") + +# ---------------------------------------------------------------------------- +# Search path configuration +# ---------------------------------------------------------------------------- +# NEVER: Do not search host machine for build tools (e.g. cmake find_program) +# ONLY: Search only within the toolchain sysroot for libraries and headers +# This prevents accidentally linking against host x86_64 libraries +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) diff --git a/qcperf/core/CMakeLists.txt b/qcperf/core/CMakeLists.txt index a891aee..036ca5f 100644 --- a/qcperf/core/CMakeLists.txt +++ b/qcperf/core/CMakeLists.txt @@ -1,68 +1,92 @@ -# ============================================================================ -# QcPerf Core Library -# ============================================================================ -# This CMakeLists.txt builds the core library of the QcPerf project, which -# provides the main API for performance monitoring and profiling. - -# ============================================================================ -# Library Target -# ============================================================================ -# Create the main QcPerfCore library as a static library -# This library implements the core functionality of the QcPerf API -add_library(QcPerfCore STATIC - src/qcperf.c -) - -# ============================================================================ -# Target Properties -# ============================================================================ -# Set output name and position independent code settings -# - OUTPUT_NAME: Sets the actual filename of the library -# - POSITION_INDEPENDENT_CODE: Disabled as this is a static library -set_target_properties(QcPerfCore PROPERTIES - OUTPUT_NAME "qcperfCore" - POSITION_INDEPENDENT_CODE OFF -) - -# ============================================================================ -# Include Directories -# ============================================================================ -# Configure include paths for the core library: -# - inc/: Public API headers for the core library -# - include/: Generated version information header -# - backends/inc: Backend interface headers -target_include_directories(QcPerfCore - PUBLIC - $ - $ # For generated versionInfo.h - ${CMAKE_SOURCE_DIR}/backends/inc -) - -# ============================================================================ -# Dependencies -# ============================================================================ -# Link against required libraries: -# - QcPerfBackends: Unified backend interface that includes all backends -target_link_libraries(QcPerfCore - PUBLIC - QcPerfBackends -) - -# ============================================================================ -# Compiler Options -# ============================================================================ -# Set compiler-specific options for the core library -# - MSVC (Visual Studio): Use warning level 4, don't treat warnings as errors -# - GCC/Clang: Enable all warnings, extra warnings, and pedantic mode -if(MSVC) - target_compile_options(QcPerfCore PRIVATE - /W4 - /WX- # Don't treat warnings as errors (can be changed to /WX if needed) - ) -else() - target_compile_options(QcPerfCore PRIVATE - -Wall - -Wextra - -Wpedantic - ) -endif() +# ============================================================================ +# QcPerf Core Library +# ============================================================================ +# This CMakeLists.txt builds the core library of the QcPerf project, which +# provides the main API for performance monitoring and profiling. + +# ============================================================================ +# Library Target +# ============================================================================ +# Build as SHARED when BUILD_SHARED=ON is passed, otherwise STATIC (default). +# Usage: +# cmake -DBUILD_SHARED=ON ... -> builds libqcperfCore.so / qcperfCore.dll +# cmake ... -> builds libqcperfCore.a / qcperfCore.lib +if(BUILD_SHARED) + set(QCPERF_CORE_LIB_TYPE SHARED) +else() + set(QCPERF_CORE_LIB_TYPE STATIC) +endif() + +add_library(QcPerfCore ${QCPERF_CORE_LIB_TYPE} + src/qcperf.c +) + +# ============================================================================ +# Target Properties +# ============================================================================ +# Set output name and position independent code settings +# - OUTPUT_NAME: Sets the actual filename of the library +set_target_properties(QcPerfCore PROPERTIES + OUTPUT_NAME "qcperfCore" + POSITION_INDEPENDENT_CODE ${BUILD_SHARED} +) + +# ============================================================================ +# Include Directories +# ============================================================================ +# Configure include paths for the core library: +# - inc/: Public API headers for the core library +# - include/: Generated version information header +# - backends/inc: Backend interface headers +target_include_directories(QcPerfCore + PUBLIC + $ + $ # For generated versionInfo.h + ${CMAKE_SOURCE_DIR}/backends/inc +) + +# ============================================================================ +# Compile Definitions +# ============================================================================ +# Set the correct export/import macro based on the library type: +if(BUILD_SHARED) + target_compile_definitions(QcPerfCore PRIVATE + QCPERF_SHARED_LIBRARY + ) + if(NOT MSVC) + target_compile_options(QcPerfCore PRIVATE -fvisibility=hidden) + endif() +else() + target_compile_definitions(QcPerfCore PUBLIC + QCPERF_STATIC_LIBRARY + ) +endif() + +# ============================================================================ +# Dependencies +# ============================================================================ +# Link against required libraries: +# - QcPerfBackends: Unified backend interface that includes all backends +target_link_libraries(QcPerfCore + PUBLIC + QcPerfBackends +) + +# ============================================================================ +# Compiler Options +# ============================================================================ +# Set compiler-specific options for the core library +# - MSVC (Visual Studio): Use warning level 4, don't treat warnings as errors +# - GCC/Clang: Enable all warnings, extra warnings, and pedantic mode +if(MSVC) + target_compile_options(QcPerfCore PRIVATE + /W4 + /WX- # Don't treat warnings as errors (can be changed to /WX if needed) + ) +else() + target_compile_options(QcPerfCore PRIVATE + -Wall + -Wextra + -Wpedantic + ) +endif() diff --git a/qcperf/core/inc/qcperf.h b/qcperf/core/inc/qcperf.h index 3bcfb60..e707efb 100644 --- a/qcperf/core/inc/qcperf.h +++ b/qcperf/core/inc/qcperf.h @@ -1,241 +1,260 @@ -/* - Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - Redistribution and use in source and binary forms, with or without - modification, are permitted (subject to the limitations in the - disclaimer below) provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Qualcomm Technologies, Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE - GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT - HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/** - * @file qcperf.h - * @brief QCPerf Library Main API Header - * - * This header file defines the main API for the QCPerf (Qualcomm Performance) library. - * The library provides a unified interface for performance monitoring and profiling - * across different backend implementations. - * - */ - -#ifndef QC_PERF_H // QC_PERF_H -#define QC_PERF_H - -#include "qcperf_common.h" -#include "version_info.h" - - -/** - * @brief Initialize the QCPerf library - * - * This function must be called before any other QCPerf API functions. - * It initializes internal data structures and prepares the library for use. - * - * @return QC_PERF_RETURN_CODE_SUCCESS on successful initialization - * @return QC_PERF_RETURN_CODE_ALREADY_INITIALIZED if already initialized - * @return QC_PERF_RETURN_CODE_FAILED on initialization failure - * - * @note This function should only be called once during the application lifecycle - * @see qcperf_deinit() - */ -enum QcPerfReturnCode qcperf_init(void); - -/** - * @brief Get the version information of the QCPerf library - * - * Retrieves the current version information of the QCPerf library. - * - * @param[out] version_info Pointer to a QcPerfVersionInfo structure that will be populated - * with the version information - * - * @return QC_PERF_RETURN_CODE_SUCCESS on success - * @return QC_PERF_RETURN_CODE_NULL_POINTER if version_info is NULL - * - * @see struct QcPerfVersionInfo - */ -enum QcPerfReturnCode qcperf_version(struct QcPerfVersionInfo* version_info); - -/** - * @brief Connect to a specific performance monitoring backend - * - * Establishes a connection to the specified backend and optionally registers - * a message callback function for receiving backend messages. - * - * @param[in] backend_id The identifier of the backend to connect to (e.g., QC_PERF_BACKEND_DUMMY) - * @param[in] message_callback Optional callback function for receiving messages from the backend. - * Can be NULL if message callbacks are not needed. - * - * @return QC_PERF_RETURN_CODE_SUCCESS on successful connection - * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if library not initialized - * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if backend_id is invalid - * @return QC_PERF_RETURN_CODE_FAILED on connection failure - * - * @note The backend must be disconnected using qcperf_disconnect_backend() when no longer needed - * @see qcperf_disconnect_backend() - */ -enum QcPerfReturnCode qcperf_connect_backend(enum QcPerfBackendId backend_id, QcPerfMessageCallback message_callback); - -/** - * @brief Get capabilities information from a connected backend - * - * Retrieves detailed information about the capabilities, metrics, and supported - * sampling/streaming rates of the specified backend. - * - * @param[in] backend_id The identifier of the backend to query - * @param[out] backend_info Pointer to a QcPerfBackendInfo structure that will be populated - * with the backend's capabilities information - * - * @return QC_PERF_RETURN_CODE_SUCCESS on success - * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if library not initialized - * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if backend_id is invalid - * @return QC_PERF_RETURN_CODE_NULL_POINTER if backend_info is NULL - * @return QC_PERF_RETURN_CODE_FAILED on failure - * - * @note The backend must be connected before calling this function - * @see qcperf_connect_backend(), struct QcPerfBackendInfo - */ -enum QcPerfReturnCode qcperf_get_capabilities_info(enum QcPerfBackendId backend_id, struct QcPerfBackendInfo* backend_info); - -/** - * @brief Set the result callback for a connected backend - * - * Registers a callback function that will be invoked when the backend produces - * performance monitoring results. This is the primary mechanism for receiving - * metric data from the backend. - * - * @param[in] backend_id The identifier of the backend - * @param[in] data_callback The callback function to register for receiving results. - * Must not be NULL. - * - * @return QC_PERF_RETURN_CODE_SUCCESS on success - * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if library not initialized - * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if backend_id is invalid - * @return QC_PERF_RETURN_CODE_NULL_POINTER if data_callback is NULL - * @return QC_PERF_RETURN_CODE_FAILED on failure - * - * @note The backend must be connected before calling this function - * @note This callback must be set before starting performance monitoring - * @see qcperf_start(), QcPerfDataCallback, struct QcPerfData - */ -enum QcPerfReturnCode qcperf_set_data_callback(enum QcPerfBackendId backend_id, QcPerfDataCallback data_callback); - -/** - * @brief Start performance monitoring on a backend - * - * Initiates performance monitoring for the specified capability with the given - * sampling and streaming rates. Results will be delivered via the registered - * result callback. - * - * @param[in] backend_id The identifier of the backend - * @param[in] request Pointer to a QcPerfRequest structure containing: - * - capability_id: The capability to monitor - * - streaming_rate: Rate at which data is streamed (in milliseconds) - * - sampling_rate: Rate at which data is sampled (in milliseconds) - * - * @return QC_PERF_RETURN_CODE_SUCCESS on success - * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if library not initialized - * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if backend_id or request parameters are invalid - * @return QC_PERF_RETURN_CODE_NULL_POINTER if request is NULL - * @return QC_PERF_RETURN_CODE_CAPABILITY_NOT_FOUND if the capability is not supported - * @return QC_PERF_RETURN_CODE_FAILED on failure - * - * @note A result callback must be set before calling this function - * @note Use qcperf_stop() to stop the monitoring session - * @see qcperf_stop(), qcperf_set_data_callback(), struct QcPerfRequest - */ -enum QcPerfReturnCode qcperf_start(enum QcPerfBackendId backend_id, struct QcPerfRequest* request); - -/** - * @brief Stop performance monitoring on a backend - * - * Stops an active performance monitoring session for the specified capability. - * - * @param[in] backend_id The identifier of the backend - * @param[in] request Pointer to a QcPerfRequest structure identifying the monitoring - * session to stop (must match the request used in qcperf_start()) - * - * @return QC_PERF_RETURN_CODE_SUCCESS on success - * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if library not initialized - * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if backend_id or request parameters are invalid - * @return QC_PERF_RETURN_CODE_NULL_POINTER if request is NULL - * @return QC_PERF_RETURN_CODE_FAILED on failure - * - * @note This function should be called for each active monitoring session started with qcperf_start() - * @see qcperf_start(), struct QcPerfRequest - */ -enum QcPerfReturnCode qcperf_stop(enum QcPerfBackendId backend_id, struct QcPerfRequest* request); - -/** - * @brief Disconnect from a backend - * - * Closes the connection to the specified backend and releases associated resources. - * All active monitoring sessions on this backend will be stopped. - * - * @param[in] backend_id The identifier of the backend to disconnect from - * - * @return QC_PERF_RETURN_CODE_SUCCESS on success - * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if library not initialized - * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if backend_id is invalid - * @return QC_PERF_RETURN_CODE_FAILED on failure - * - * @note All monitoring sessions should be stopped before disconnecting - * @see qcperf_connect_backend(), qcperf_stop() - */ -enum QcPerfReturnCode qcperf_disconnect_backend(enum QcPerfBackendId backend_id); - -/** - * @brief Deinitialize the QCPerf library - * - * Cleans up all resources used by the QCPerf library. This function should be - * called when the library is no longer needed, typically at application shutdown. - * - * @return QC_PERF_RETURN_CODE_SUCCESS on success - * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if library not initialized - * @return QC_PERF_RETURN_CODE_FAILED on failure - * - * @note All backends should be disconnected before calling this function - * @note After calling this function, qcperf_init() must be called again to use the library - * @see qcperf_init(), qcperf_disconnect_backend() - */ -enum QcPerfReturnCode qcperf_deinit(void); - -/** - * @brief Get detailed information about an error code - * - * Retrieves human-readable information about a specific error code, including - * the error type (info/warning/error) and a descriptive message. - * - * @param[in] error_code The error code to query - * @param[out] error_info Pointer to a QcPerfReturnCodeInfo structure that will be populated - * with detailed error information - * - * @return QC_PERF_RETURN_CODE_SUCCESS on success - * @return QC_PERF_RETURN_CODE_NULL_POINTER if error_info is NULL - * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if error_code is invalid - * @return QC_PERF_RETURN_CODE_FAILED on failure - * - * @note This function can be called even if the library is not initialized - * @see enum QcPerfReturnCode, struct QcPerfReturnCodeInfo - */ -enum QcPerfReturnCode qcperf_get_error_info(enum QcPerfReturnCode error_code, struct QcPerfReturnCodeInfo* error_info); - -#endif // QC_PERF_H +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file qcperf.h + * @brief QCPerf Library Main API Header + * + * This header file defines the main API for the QCPerf (Qualcomm Performance) library. + * The library provides a unified interface for performance monitoring and profiling + * across different backend implementations. + * + */ + +#ifndef QC_PERF_H // QC_PERF_H +#define QC_PERF_H + +#include "qcperf_common.h" +#include "version_info.h" + +#ifdef __cplusplus +#define QCPERF_EXTERN_C extern "C" +#else +#define QCPERF_EXTERN_C +#endif + +#if defined(QCPERF_STATIC_LIBRARY) +# define QCPERF_EXPORT QCPERF_EXTERN_C +#else +# if defined(_WIN32) +# if defined(QCPERF_SHARED_LIBRARY) +# define QCPERF_EXPORT QCPERF_EXTERN_C __declspec(dllexport) +# else +# define QCPERF_EXPORT QCPERF_EXTERN_C __declspec(dllimport) +# endif +# else +# define QCPERF_EXPORT QCPERF_EXTERN_C __attribute__((visibility ("default"))) +# endif +#endif + +/** + * @brief Initialize the QCPerf library + * + * This function must be called before any other QCPerf API functions. + * It initializes internal data structures and prepares the library for use. + * + * @return QC_PERF_RETURN_CODE_SUCCESS on successful initialization + * @return QC_PERF_RETURN_CODE_ALREADY_INITIALIZED if already initialized + * @return QC_PERF_RETURN_CODE_FAILED on initialization failure + * + * @note This function should only be called once during the application lifecycle + * @see qcperf_deinit() + */ +QCPERF_EXPORT enum QcPerfReturnCode qcperf_init(void); + +/** + * @brief Get the version information of the QCPerf library + * + * Retrieves the current version information of the QCPerf library. + * + * @param[out] version_info Pointer to a QcPerfVersionInfo structure that will be populated + * with the version information + * + * @return QC_PERF_RETURN_CODE_SUCCESS on success + * @return QC_PERF_RETURN_CODE_NULL_POINTER if version_info is NULL + * + * @see struct QcPerfVersionInfo + */ +QCPERF_EXPORT enum QcPerfReturnCode qcperf_version(struct QcPerfVersionInfo* version_info); + +/** + * @brief Connect to a specific performance monitoring backend + * + * Establishes a connection to the specified backend and optionally registers + * a message callback function for receiving backend messages. + * + * @param[in] backend_id The identifier of the backend to connect to (e.g., QC_PERF_BACKEND_DUMMY) + * @param[in] message_callback Optional callback function for receiving messages from the backend. + * Can be NULL if message callbacks are not needed. + * + * @return QC_PERF_RETURN_CODE_SUCCESS on successful connection + * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if library not initialized + * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if backend_id is invalid + * @return QC_PERF_RETURN_CODE_FAILED on connection failure + * + * @note The backend must be disconnected using qcperf_disconnect_backend() when no longer needed + * @see qcperf_disconnect_backend() + */ +QCPERF_EXPORT enum QcPerfReturnCode qcperf_connect_backend(enum QcPerfBackendId backend_id, QcPerfMessageCallback message_callback); + +/** + * @brief Get capabilities information from a connected backend + * + * Retrieves detailed information about the capabilities, metrics, and supported + * sampling/streaming rates of the specified backend. + * + * @param[in] backend_id The identifier of the backend to query + * @param[out] backend_info Pointer to a QcPerfBackendInfo structure that will be populated + * with the backend's capabilities information + * + * @return QC_PERF_RETURN_CODE_SUCCESS on success + * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if library not initialized + * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if backend_id is invalid + * @return QC_PERF_RETURN_CODE_NULL_POINTER if backend_info is NULL + * @return QC_PERF_RETURN_CODE_FAILED on failure + * + * @note The backend must be connected before calling this function + * @see qcperf_connect_backend(), struct QcPerfBackendInfo + */ +QCPERF_EXPORT enum QcPerfReturnCode qcperf_get_capabilities_info(enum QcPerfBackendId backend_id, struct QcPerfBackendInfo* backend_info); + +/** + * @brief Set the result callback for a connected backend + * + * Registers a callback function that will be invoked when the backend produces + * performance monitoring results. This is the primary mechanism for receiving + * metric data from the backend. + * + * @param[in] backend_id The identifier of the backend + * @param[in] data_callback The callback function to register for receiving results. + * Must not be NULL. + * + * @return QC_PERF_RETURN_CODE_SUCCESS on success + * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if library not initialized + * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if backend_id is invalid + * @return QC_PERF_RETURN_CODE_NULL_POINTER if data_callback is NULL + * @return QC_PERF_RETURN_CODE_FAILED on failure + * + * @note The backend must be connected before calling this function + * @note This callback must be set before starting performance monitoring + * @see qcperf_start(), QcPerfDataCallback, struct QcPerfData + */ +QCPERF_EXPORT enum QcPerfReturnCode qcperf_set_data_callback(enum QcPerfBackendId backend_id, QcPerfDataCallback data_callback); + +/** + * @brief Start performance monitoring on a backend + * + * Initiates performance monitoring for the specified capability with the given + * sampling and streaming rates. Results will be delivered via the registered + * result callback. + * + * @param[in] backend_id The identifier of the backend + * @param[in] request Pointer to a QcPerfRequest structure containing: + * - capability_id: The capability to monitor + * - streaming_rate: Rate at which data is streamed (in milliseconds) + * - sampling_rate: Rate at which data is sampled (in milliseconds) + * + * @return QC_PERF_RETURN_CODE_SUCCESS on success + * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if library not initialized + * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if backend_id or request parameters are invalid + * @return QC_PERF_RETURN_CODE_NULL_POINTER if request is NULL + * @return QC_PERF_RETURN_CODE_CAPABILITY_NOT_FOUND if the capability is not supported + * @return QC_PERF_RETURN_CODE_FAILED on failure + * + * @note A result callback must be set before calling this function + * @note Use qcperf_stop() to stop the monitoring session + * @see qcperf_stop(), qcperf_set_data_callback(), struct QcPerfRequest + */ +QCPERF_EXPORT enum QcPerfReturnCode qcperf_start(enum QcPerfBackendId backend_id, struct QcPerfRequest* request); + +/** + * @brief Stop performance monitoring on a backend + * + * Stops an active performance monitoring session for the specified capability. + * + * @param[in] backend_id The identifier of the backend + * @param[in] request Pointer to a QcPerfRequest structure identifying the monitoring + * session to stop (must match the request used in qcperf_start()) + * + * @return QC_PERF_RETURN_CODE_SUCCESS on success + * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if library not initialized + * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if backend_id or request parameters are invalid + * @return QC_PERF_RETURN_CODE_NULL_POINTER if request is NULL + * @return QC_PERF_RETURN_CODE_FAILED on failure + * + * @note This function should be called for each active monitoring session started with qcperf_start() + * @see qcperf_start(), struct QcPerfRequest + */ +QCPERF_EXPORT enum QcPerfReturnCode qcperf_stop(enum QcPerfBackendId backend_id, struct QcPerfRequest* request); + +/** + * @brief Disconnect from a backend + * + * Closes the connection to the specified backend and releases associated resources. + * All active monitoring sessions on this backend will be stopped. + * + * @param[in] backend_id The identifier of the backend to disconnect from + * + * @return QC_PERF_RETURN_CODE_SUCCESS on success + * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if library not initialized + * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if backend_id is invalid + * @return QC_PERF_RETURN_CODE_FAILED on failure + * + * @note All monitoring sessions should be stopped before disconnecting + * @see qcperf_connect_backend(), qcperf_stop() + */ +QCPERF_EXPORT enum QcPerfReturnCode qcperf_disconnect_backend(enum QcPerfBackendId backend_id); + +/** + * @brief Deinitialize the QCPerf library + * + * Cleans up all resources used by the QCPerf library. This function should be + * called when the library is no longer needed, typically at application shutdown. + * + * @return QC_PERF_RETURN_CODE_SUCCESS on success + * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if library not initialized + * @return QC_PERF_RETURN_CODE_FAILED on failure + * + * @note All backends should be disconnected before calling this function + * @note After calling this function, qcperf_init() must be called again to use the library + * @see qcperf_init(), qcperf_disconnect_backend() + */ +QCPERF_EXPORT enum QcPerfReturnCode qcperf_deinit(void); + +/** + * @brief Get detailed information about an error code + * + * Retrieves human-readable information about a specific error code, including + * the error type (info/warning/error) and a descriptive message. + * + * @param[in] error_code The error code to query + * @param[out] error_info Pointer to a QcPerfReturnCodeInfo structure that will be populated + * with detailed error information + * + * @return QC_PERF_RETURN_CODE_SUCCESS on success + * @return QC_PERF_RETURN_CODE_NULL_POINTER if error_info is NULL + * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if error_code is invalid + * @return QC_PERF_RETURN_CODE_FAILED on failure + * + * @note This function can be called even if the library is not initialized + * @see enum QcPerfReturnCode, struct QcPerfReturnCodeInfo + */ +QCPERF_EXPORT enum QcPerfReturnCode qcperf_get_error_info(enum QcPerfReturnCode error_code, struct QcPerfReturnCodeInfo* error_info); + +#endif // QC_PERF_H diff --git a/qcperf/core/inc/qcperf_common.h b/qcperf/core/inc/qcperf_common.h index b78e3e8..5139ec7 100644 --- a/qcperf/core/inc/qcperf_common.h +++ b/qcperf/core/inc/qcperf_common.h @@ -1,333 +1,333 @@ -/* - Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - Redistribution and use in source and binary forms, with or without - modification, are permitted (subject to the limitations in the - disclaimer below) provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Qualcomm Technologies, Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE - GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT - HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/** - * @file qcperf_common.h - * @brief Common definitions and data structures for QcPerf library - * - * This header file contains common type definitions, enumerations, and data structures - * used throughout the QcPerf performance monitoring library. It defines the core data - * types, return codes, callback function signatures, and structures for handling - * performance metrics and backend communication. - */ - -#ifndef QC_PERF_COMMON_H // QC_PERF_COMMON_H -#define QC_PERF_COMMON_H - -#include -#include -#include -#include - -#include "qcperf_backend_enum.h" -/** - * @def MAX_METRICS_PER_BACKEND - * @brief Maximum number of metrics supported per backend - * - * Defines the upper limit for the number of performance metrics that can be - * registered and tracked by a single backend implementation. - */ - -#define MAX_METRICS_PER_BACKEND 256 -#define ERROR_STRING_MAX_LEN 256 - -/** - * @def METRIC_NAME_MAX_LEN - * @brief Maximum length of metric name string - * - * Defines the maximum buffer size for storing metric name strings. - */ -#define METRIC_NAME_MAX_LEN 64 - -/** - * @def MAX_SAMPLING_STREAMING_RATES_LEN - * @brief Maximum number of sampling and streaming rates supported - * - * Defines the maximum number of different sampling and streaming rates - * that can be supported by a capability. - */ -#define MAX_SAMPLING_STREAMING_RATES_LEN 32 - -/** - * @def RETURN_CODE_INFO_STRING_MAX_LEN - * @brief Maximum length of return code information string - * - * Specifies the maximum buffer size for storing descriptive information - * associated with return codes. - */ -#define RETURN_CODE_INFO_STRING_MAX_LEN 256 - -/** - * @def CAPABILITY_NAME_MAX_LEN - * @brief Maximum length of capability name string - * - * Defines the maximum buffer size for storing capability name string. - */ -#define CAPABILITY_NAME_MAX_LEN 64 - -/** - * @def METRIC_DESC_MAX_LEN - * @brief Maximum length of metric description string - * - * Defines the maximum buffer size for storing metric description strings. - */ -#define MAX_METRIC_DESCRIPTION_LEN 256 - -/** - * @def METRIC_UNIT_MAX_LEN - * @brief Maximum length of metric unit string - * - * Defines the maximum buffer size for storing metric unit strings. - */ -#define MAX_METRIC_UNIT_LEN 16 - -#define ERROR_STRING_MAX_LEN 256 - -struct QcPerfData; -struct QcPerfMessage; - -/** - * @enum QcPerfReturnCode - * @brief Return codes for QcPerf API functions - * - * Enumeration of all possible return codes that can be returned by QcPerf - * library functions. These codes indicate the success or failure status of - * API operations. - */ -enum QcPerfReturnCode { - QC_PERF_RETURN_CODE_SUCCESS = 0, /**< Operation completed successfully */ - QC_PERF_RETURN_CODE_FAILED, /**< Operation failed with unspecified error */ - QC_PERF_RETURN_CODE_NOT_SUPPORTED, /**< Requested operation is not supported */ - QC_PERF_RETURN_CODE_ALREADY_INITIALIZED, /**< Component is already initialized */ - QC_PERF_RETURN_CODE_INVALID_HANDLE, /**< Invalid handle provided */ - QC_PERF_RETURN_CODE_INVALID_ARGUMENTS, /**< Invalid arguments passed to function */ - QC_PERF_RETURN_CODE_NOT_INITIALIZED, /**< Component is not initialized */ - QC_PERF_RETURN_CODE_CAPABILITY_NOT_FOUND, /**< Requested capability not found */ - QC_PERF_RETURN_CODE_INVALID_BUFFER_SIZE, /**< Buffer size is invalid or insufficient */ - QC_PERF_RETURN_CODE_NULL_POINTER, /**< Null pointer encountered */ - QC_PERF_RETURN_CODE_CALLOC_FAILED, /**< Memory allocation failed */ - QC_PERF_RETURN_CODE_BACKEND_ALREADY_CONNECTED, /**< Backend is already connected */ - QC_PERF_RETURN_CODE_INVALID_BACKEND_ID, /**< Invalid backend identifier */ - QC_PERF_RETURN_CODE_BACKEND_NOT_CONNECTED, /**< Backend is not connected */ - QC_PERF_RETURN_CODE_CALLBACK_ALREADY_SET, /**< Callback already set */ - QC_PERF_RETURN_CODE_NATIVE_LIBRARY_FAILED, /**< Native library call failed */ -}; - -/** - * @typedef QcPerfMessageCallback - * @brief Callback function type for handling message notifications - * - * This callback is invoked to deliver informational, warning, or error messages - * to the application during QcPerf operations. - * - * @param message Pointer to the message string - * @param message_length Length of the message in bytes - * @return QcPerfReturnCode indicating the callback execution status - */ -typedef enum QcPerfReturnCode (*QcPerfMessageCallback)(struct QcPerfMessage* message); - -/** - * @typedef QcPerfDataCallback - * @brief Callback function type for handling performance metric results - * - * This callback is invoked to deliver performance metric data collected by - * the backend to the application. It is called periodically based on the - * configured streaming rate. - * - * @param data Pointer to QcPerfData structure containing metric data - * @return QcPerfReturnCode indicating the callback execution status - */ -typedef enum QcPerfReturnCode (*QcPerfDataCallback)(struct QcPerfData* data); - -/** - * @enum QcPerfMessageLevel - * @brief Message severity levels for backend communication - * - * Defines the severity levels for messages sent from backends to applications. - * These levels help applications prioritize and filter messages based on - * their importance. - */ -enum QcPerfMessageLevel { - QC_PERF_MESSAGE_LEVEL_DEBUG = 0, /**< Debug message */ - QC_PERF_MESSAGE_LEVEL_INFO, /**< Informational message */ - QC_PERF_MESSAGE_LEVEL_WARNING, /**< Warning condition */ - QC_PERF_MESSAGE_LEVEL_ERROR, /**< Error condition */ -}; - -/** - * @enum QcPerfDataType - * @brief Data types supported for performance metrics - * - * Enumeration of data types that can be used to represent performance metric - * values. This allows metrics to be expressed in various formats depending on - * their nature. - */ -enum QcPerfDataType { - QC_PERF_DATA_TYPE_BOOL = 0, /**< Boolean value (true/false) */ - QC_PERF_DATA_TYPE_UINT64, /**< Unsigned 64-bit integer */ - QC_PERF_DATA_TYPE_INT64, /**< Signed 64-bit integer */ - QC_PERF_DATA_TYPE_DOUBLE, /**< Double-precision floating point */ - QC_PERF_DATA_TYPE_STRING, /**< String value */ -}; - -/** - * @struct QcPerfReturnCodeInfo - * @brief Detailed information about a return code - * - * Structure containing comprehensive information about an operation's return - * status, including the return code, its severity type, and a descriptive message. - */ -struct QcPerfReturnCodeInfo { - enum QcPerfReturnCode return_code; /**< The return code value */ - uint8_t info_str[RETURN_CODE_INFO_STRING_MAX_LEN]; /**< Descriptive information string */ - size_t info_str_len; /**< Length of the information string */ -}; - -/** - * @struct QcPerfRequest - * @brief Request structure for performance monitoring configuration - * - * Defines the parameters for requesting performance data collection from a - * specific capability, including the desired sampling and streaming rates. - */ -struct QcPerfRequest { - uint8_t capability_id; /**< Unique identifier for the capability to monitor */ - uint16_t streaming_rate; /**< Rate at which data is streamed to callback (in milliseconds) */ - uint16_t sampling_rate; /**< Rate at which backend samples the metric (in milliseconds) */ -}; - -/** - * @struct QcPerfGenericType - * @brief Generic container for metric values of different types - * - * A union-like structure that can hold metric values of various data types. - * The data_type field indicates which value field is valid. - */ -struct QcPerfGenericType { - enum QcPerfDataType data_type; /**< Type of data stored in this structure */ - bool bool_value; /**< Boolean value (valid when data_type is QC_PERF_DATA_TYPE_BOOL) */ - uint64_t uint64_value; /**< Unsigned 64-bit integer (valid when data_type is QC_PERF_DATA_TYPE_UINT64) */ - int64_t int64_value; /**< Signed 64-bit integer (valid when data_type is QC_PERF_DATA_TYPE_INT64) */ - double double_value; /**< Double-precision float (valid when data_type is QC_PERF_DATA_TYPE_DOUBLE) */ - char* string_value; /**< String value (valid when data_type is QC_PERF_DATA_TYPE_STRING) */ - size_t string_value_len; -}; - -/** - * @struct QcPerfMessage - * @brief Message structure for communication from backends - * - * Contains a message string and metadata about the message, including - * its length and severity level. Used for delivering informational, - * warning, or error messages from backends to applications. - */ -struct QcPerfMessage { - uint8_t backend_id; /**< Unique identifier for this backend */ - uint8_t capability_id; /**< Unique identifier for the capability message is intented to*/ - const char* message; /**< Pointer to the message text */ - size_t message_length; /**< Length of the message in bytes */ - enum QcPerfMessageLevel message_level; /**< Severity level of the message */ -}; - -/** - * @struct QcPerfMetricResponse - * @brief Response structure for a single performance metric - * - * Contains the identifier and value of a single performance metric collected - * by the backend. - */ -struct QcPerfMetricResponse { - uint64_t timestamp; /**< Timestamp when metrics were collected */ - uint16_t metric_id; /**< Unique identifier for the metric */ - struct QcPerfGenericType metric_value; /**< Value of the metric */ -}; - -/** - * @struct QcPerfData - * @brief Complete data structure for performance data collection - * - * Contains all performance metrics collected for a capability at a specific - * timestamp, along with status information. - */ -struct QcPerfData { - uint8_t backend_id; /**< Unique identifier for this backend */ - uint8_t capabilityId; /**< Capability identifier for this data */ - struct QcPerfMetricResponse* metric_response; /**< Array of metric responses */ - uint32_t metric_response_len; /**< Number of metrics in the data array */ -}; - -/** - * @struct QcPerfCapabilityInfo - * @brief Information about a performance monitoring capability - * - * Describes a single capability provided by a backend, including its identifier, - * human-readable name, supported metrics, and available sampling/streaming rates. - */ -struct QcPerfCapabilityInfo { - uint8_t capability_id; /**< Unique identifier for the capability */ - char capability_name[CAPABILITY_NAME_MAX_LEN]; /**< Human-readable name of the capability */ - size_t capability_name_len; - struct QcPerfMetricInfo* metric_ids_list; /**< Array of metrics supported by this capability */ - uint8_t metric_ids_list_len; /**< Number of metrics in the metric_ids_list array */ - uint16_t streaming_rate[MAX_SAMPLING_STREAMING_RATES_LEN]; /**< Array of supported streaming rates in milliseconds */ - uint8_t streaming_rate_len; /**< Number of valid streaming rates in the streaming_rate array */ - uint16_t sampling_rate[MAX_SAMPLING_STREAMING_RATES_LEN]; /**< Array of supported sampling rates in milliseconds */ - uint8_t sampling_rate_len; /**< Number of valid sampling rates in the sampling_rate array */ -}; - -/** - * @struct QcPerfMetricInfo - * @brief Detailed information about a performance metric - * - * Provides comprehensive metadata about a metric, including its identifier, - * name, unit of measurement, and description. - */ -struct QcPerfMetricInfo { - uint16_t metric_id; /**< Unique identifier for the metric */ - char metric_name[METRIC_NAME_MAX_LEN]; /**< Human-readable name of the metric */ - size_t metric_name_len; - char metric_description[MAX_METRIC_DESCRIPTION_LEN]; /**< Detailed description of the metric */ - size_t metric_description_len; - char metric_unit[MAX_METRIC_UNIT_LEN]; /**< Unit of measurement (e.g., "MHz", "°C", "%") */ - size_t metric_unit_len; -}; - -/** - * @struct QcPerfBackendInfo - * @brief Complete information about a performance monitoring backend - * - * Contains all metadata about a backend, including its capabilities, supported - * metrics, and available sampling/streaming rates. - */ -struct QcPerfBackendInfo { - uint8_t backend_id; /**< Unique identifier for this backend */ - struct QcPerfCapabilityInfo* capabilities_list; /**< Array of capabilities provided by this backend */ - uint8_t capabilities_list_length; /**< Number of capabilities in the array */ -}; -#endif // QC_PERF_COMMON_H +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file qcperf_common.h + * @brief Common definitions and data structures for QcPerf library + * + * This header file contains common type definitions, enumerations, and data structures + * used throughout the QcPerf performance monitoring library. It defines the core data + * types, return codes, callback function signatures, and structures for handling + * performance metrics and backend communication. + */ + +#ifndef QC_PERF_COMMON_H // QC_PERF_COMMON_H +#define QC_PERF_COMMON_H + +#include +#include +#include +#include + +#include "qcperf_backend_enum.h" +/** + * @def MAX_METRICS_PER_BACKEND + * @brief Maximum number of metrics supported per backend + * + * Defines the upper limit for the number of performance metrics that can be + * registered and tracked by a single backend implementation. + */ + +#define MAX_METRICS_PER_BACKEND 256 +#define ERROR_STRING_MAX_LEN 256 + +/** + * @def METRIC_NAME_MAX_LEN + * @brief Maximum length of metric name string + * + * Defines the maximum buffer size for storing metric name strings. + */ +#define METRIC_NAME_MAX_LEN 64 + +/** + * @def MAX_SAMPLING_STREAMING_RATES_LEN + * @brief Maximum number of sampling and streaming rates supported + * + * Defines the maximum number of different sampling and streaming rates + * that can be supported by a capability. + */ +#define MAX_SAMPLING_STREAMING_RATES_LEN 32 + +/** + * @def RETURN_CODE_INFO_STRING_MAX_LEN + * @brief Maximum length of return code information string + * + * Specifies the maximum buffer size for storing descriptive information + * associated with return codes. + */ +#define RETURN_CODE_INFO_STRING_MAX_LEN 256 + +/** + * @def CAPABILITY_NAME_MAX_LEN + * @brief Maximum length of capability name string + * + * Defines the maximum buffer size for storing capability name string. + */ +#define CAPABILITY_NAME_MAX_LEN 64 + +/** + * @def METRIC_DESC_MAX_LEN + * @brief Maximum length of metric description string + * + * Defines the maximum buffer size for storing metric description strings. + */ +#define MAX_METRIC_DESCRIPTION_LEN 256 + +/** + * @def METRIC_UNIT_MAX_LEN + * @brief Maximum length of metric unit string + * + * Defines the maximum buffer size for storing metric unit strings. + */ +#define MAX_METRIC_UNIT_LEN 16 + +#define ERROR_STRING_MAX_LEN 256 + +struct QcPerfData; +struct QcPerfMessage; + +/** + * @enum QcPerfReturnCode + * @brief Return codes for QcPerf API functions + * + * Enumeration of all possible return codes that can be returned by QcPerf + * library functions. These codes indicate the success or failure status of + * API operations. + */ +enum QcPerfReturnCode { + QC_PERF_RETURN_CODE_SUCCESS = 0, /**< Operation completed successfully */ + QC_PERF_RETURN_CODE_FAILED, /**< Operation failed with unspecified error */ + QC_PERF_RETURN_CODE_NOT_SUPPORTED, /**< Requested operation is not supported */ + QC_PERF_RETURN_CODE_ALREADY_INITIALIZED, /**< Component is already initialized */ + QC_PERF_RETURN_CODE_INVALID_HANDLE, /**< Invalid handle provided */ + QC_PERF_RETURN_CODE_INVALID_ARGUMENTS, /**< Invalid arguments passed to function */ + QC_PERF_RETURN_CODE_NOT_INITIALIZED, /**< Component is not initialized */ + QC_PERF_RETURN_CODE_CAPABILITY_NOT_FOUND, /**< Requested capability not found */ + QC_PERF_RETURN_CODE_INVALID_BUFFER_SIZE, /**< Buffer size is invalid or insufficient */ + QC_PERF_RETURN_CODE_NULL_POINTER, /**< Null pointer encountered */ + QC_PERF_RETURN_CODE_CALLOC_FAILED, /**< Memory allocation failed */ + QC_PERF_RETURN_CODE_BACKEND_ALREADY_CONNECTED, /**< Backend is already connected */ + QC_PERF_RETURN_CODE_INVALID_BACKEND_ID, /**< Invalid backend identifier */ + QC_PERF_RETURN_CODE_BACKEND_NOT_CONNECTED, /**< Backend is not connected */ + QC_PERF_RETURN_CODE_CALLBACK_ALREADY_SET, /**< Callback already set */ + QC_PERF_RETURN_CODE_NATIVE_LIBRARY_FAILED, /**< Native library call failed */ +}; + +/** + * @typedef QcPerfMessageCallback + * @brief Callback function type for handling message notifications + * + * This callback is invoked to deliver informational, warning, or error messages + * to the application during QcPerf operations. + * + * @param message Pointer to the message string + * @param message_length Length of the message in bytes + * @return QcPerfReturnCode indicating the callback execution status + */ +typedef enum QcPerfReturnCode (*QcPerfMessageCallback)(struct QcPerfMessage* message); + +/** + * @typedef QcPerfDataCallback + * @brief Callback function type for handling performance metric results + * + * This callback is invoked to deliver performance metric data collected by + * the backend to the application. It is called periodically based on the + * configured streaming rate. + * + * @param data Pointer to QcPerfData structure containing metric data + * @return QcPerfReturnCode indicating the callback execution status + */ +typedef enum QcPerfReturnCode (*QcPerfDataCallback)(struct QcPerfData* data); + +/** + * @enum QcPerfMessageLevel + * @brief Message severity levels for backend communication + * + * Defines the severity levels for messages sent from backends to applications. + * These levels help applications prioritize and filter messages based on + * their importance. + */ +enum QcPerfMessageLevel { + QC_PERF_MESSAGE_LEVEL_DEBUG = 0, /**< Debug message */ + QC_PERF_MESSAGE_LEVEL_INFO, /**< Informational message */ + QC_PERF_MESSAGE_LEVEL_WARNING, /**< Warning condition */ + QC_PERF_MESSAGE_LEVEL_ERROR, /**< Error condition */ +}; + +/** + * @enum QcPerfDataType + * @brief Data types supported for performance metrics + * + * Enumeration of data types that can be used to represent performance metric + * values. This allows metrics to be expressed in various formats depending on + * their nature. + */ +enum QcPerfDataType { + QC_PERF_DATA_TYPE_BOOL = 0, /**< Boolean value (true/false) */ + QC_PERF_DATA_TYPE_UINT64, /**< Unsigned 64-bit integer */ + QC_PERF_DATA_TYPE_INT64, /**< Signed 64-bit integer */ + QC_PERF_DATA_TYPE_DOUBLE, /**< Double-precision floating point */ + QC_PERF_DATA_TYPE_STRING, /**< String value */ +}; + +/** + * @struct QcPerfReturnCodeInfo + * @brief Detailed information about a return code + * + * Structure containing comprehensive information about an operation's return + * status, including the return code, its severity type, and a descriptive message. + */ +struct QcPerfReturnCodeInfo { + enum QcPerfReturnCode return_code; /**< The return code value */ + uint8_t info_str[RETURN_CODE_INFO_STRING_MAX_LEN]; /**< Descriptive information string */ + size_t info_str_len; /**< Length of the information string */ +}; + +/** + * @struct QcPerfRequest + * @brief Request structure for performance monitoring configuration + * + * Defines the parameters for requesting performance data collection from a + * specific capability, including the desired sampling and streaming rates. + */ +struct QcPerfRequest { + uint8_t capability_id; /**< Unique identifier for the capability to monitor */ + uint16_t streaming_rate; /**< Rate at which data is streamed to callback (in milliseconds) */ + uint16_t sampling_rate; /**< Rate at which backend samples the metric (in milliseconds) */ +}; + +/** + * @struct QcPerfGenericType + * @brief Generic container for metric values of different types + * + * A union-like structure that can hold metric values of various data types. + * The data_type field indicates which value field is valid. + */ +struct QcPerfGenericType { + enum QcPerfDataType data_type; /**< Type of data stored in this structure */ + bool bool_value; /**< Boolean value (valid when data_type is QC_PERF_DATA_TYPE_BOOL) */ + uint64_t uint64_value; /**< Unsigned 64-bit integer (valid when data_type is QC_PERF_DATA_TYPE_UINT64) */ + int64_t int64_value; /**< Signed 64-bit integer (valid when data_type is QC_PERF_DATA_TYPE_INT64) */ + double double_value; /**< Double-precision float (valid when data_type is QC_PERF_DATA_TYPE_DOUBLE) */ + char* string_value; /**< String value (valid when data_type is QC_PERF_DATA_TYPE_STRING) */ + size_t string_value_len; +}; + +/** + * @struct QcPerfMessage + * @brief Message structure for communication from backends + * + * Contains a message string and metadata about the message, including + * its length and severity level. Used for delivering informational, + * warning, or error messages from backends to applications. + */ +struct QcPerfMessage { + uint8_t backend_id; /**< Unique identifier for this backend */ + uint8_t capability_id; /**< Unique identifier for the capability message is intented to*/ + const char* message; /**< Pointer to the message text */ + size_t message_length; /**< Length of the message in bytes */ + enum QcPerfMessageLevel message_level; /**< Severity level of the message */ +}; + +/** + * @struct QcPerfMetricResponse + * @brief Response structure for a single performance metric + * + * Contains the identifier and value of a single performance metric collected + * by the backend. + */ +struct QcPerfMetricResponse { + uint64_t timestamp; /**< Timestamp when metrics were collected */ + uint16_t metric_id; /**< Unique identifier for the metric */ + struct QcPerfGenericType metric_value; /**< Value of the metric */ +}; + +/** + * @struct QcPerfData + * @brief Complete data structure for performance data collection + * + * Contains all performance metrics collected for a capability at a specific + * timestamp, along with status information. + */ +struct QcPerfData { + uint8_t backend_id; /**< Unique identifier for this backend */ + uint8_t capabilityId; /**< Capability identifier for this data */ + struct QcPerfMetricResponse* metric_response; /**< Array of metric responses */ + uint32_t metric_response_len; /**< Number of metrics in the data array */ +}; + +/** + * @struct QcPerfCapabilityInfo + * @brief Information about a performance monitoring capability + * + * Describes a single capability provided by a backend, including its identifier, + * human-readable name, supported metrics, and available sampling/streaming rates. + */ +struct QcPerfCapabilityInfo { + uint8_t capability_id; /**< Unique identifier for the capability */ + char capability_name[CAPABILITY_NAME_MAX_LEN]; /**< Human-readable name of the capability */ + size_t capability_name_len; + struct QcPerfMetricInfo* metric_ids_list; /**< Array of metrics supported by this capability */ + uint8_t metric_ids_list_len; /**< Number of metrics in the metric_ids_list array */ + uint16_t streaming_rate[MAX_SAMPLING_STREAMING_RATES_LEN]; /**< Array of supported streaming rates in milliseconds */ + uint8_t streaming_rate_len; /**< Number of valid streaming rates in the streaming_rate array */ + uint16_t sampling_rate[MAX_SAMPLING_STREAMING_RATES_LEN]; /**< Array of supported sampling rates in milliseconds */ + uint8_t sampling_rate_len; /**< Number of valid sampling rates in the sampling_rate array */ +}; + +/** + * @struct QcPerfMetricInfo + * @brief Detailed information about a performance metric + * + * Provides comprehensive metadata about a metric, including its identifier, + * name, unit of measurement, and description. + */ +struct QcPerfMetricInfo { + uint16_t metric_id; /**< Unique identifier for the metric */ + char metric_name[METRIC_NAME_MAX_LEN]; /**< Human-readable name of the metric */ + size_t metric_name_len; + char metric_description[MAX_METRIC_DESCRIPTION_LEN]; /**< Detailed description of the metric */ + size_t metric_description_len; + char metric_unit[MAX_METRIC_UNIT_LEN]; /**< Unit of measurement (e.g., "MHz", "°C", "%") */ + size_t metric_unit_len; +}; + +/** + * @struct QcPerfBackendInfo + * @brief Complete information about a performance monitoring backend + * + * Contains all metadata about a backend, including its capabilities, supported + * metrics, and available sampling/streaming rates. + */ +struct QcPerfBackendInfo { + uint8_t backend_id; /**< Unique identifier for this backend */ + struct QcPerfCapabilityInfo* capabilities_list; /**< Array of capabilities provided by this backend */ + uint8_t capabilities_list_length; /**< Number of capabilities in the array */ +}; +#endif // QC_PERF_COMMON_H diff --git a/qcperf/core/src/qcperf.c b/qcperf/core/src/qcperf.c index fabab9f..b5f15a4 100644 --- a/qcperf/core/src/qcperf.c +++ b/qcperf/core/src/qcperf.c @@ -1,381 +1,384 @@ -/* - Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - Redistribution and use in source and binary forms, with or without - modification, are permitted (subject to the limitations in the - disclaimer below) provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Qualcomm Technologies, Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE - GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT - HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/** - * @file qcperf.c - * @brief Implementation of the QcPerf library main API - * @author Skand Gupta (skangupt@qti.qualcomm.com) - * - * This file implements the public API functions defined in qcperf.h, providing - * the core functionality of the QcPerf library. It manages backend connections, - * handles performance monitoring requests, and coordinates data collection and - * delivery between backends and applications. - * - * The implementation follows a modular design where each backend is represented - * by a set of function pointers that are initialized during backend connection. - * This allows for a flexible and extensible architecture where new backends can - * be added without modifying the core library code. - */ - -#include -#include -#include - -#include "qcperf.h" -#include "qcperf_common.h" -#include "qcperf_backends.h" -#include "internal/qcperf_backend_interface.h" -#include "version_info.h" - -// Private function declarations for backend-specific implementation of public API -static enum QcPerfReturnCode qcperf_reset_backend_private(enum QcPerfBackendId backend_id); -static enum QcPerfReturnCode qcperf_verify_backend_private(enum QcPerfBackendId backend_id); -static enum QcPerfReturnCode qcperf_set_message_callback(enum QcPerfBackendId backend_id, QcPerfMessageCallback message_callback); - -/** - * @brief Global array of backend interface structures - * - * This array stores the function pointers for each backend's implementation - * of the QcPerf interface. It is allocated during qcperf_init() and freed - * during qcperf_deinit(). - */ -static struct QcPerfBackendPrivate* g_qcperf_backend_info = NULL; - -/** - * @brief Connection status for each backend - * - * This array tracks which backends are currently connected. - * Each element corresponds to a backend ID, where true indicates - * the backend is connected and false indicates it is not. - */ -bool g_backends_connected[QC_PERF_BACKEND_MAX] = {0}; // [0] = first backend, [1] = second backend, etc. - -enum QcPerfReturnCode qcperf_init(void) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; - if (NULL != g_qcperf_backend_info) { - return_code = QC_PERF_RETURN_CODE_ALREADY_INITIALIZED; - } else { - g_qcperf_backend_info = (struct QcPerfBackendPrivate*)calloc(QC_PERF_BACKEND_MAX, sizeof(struct QcPerfBackendPrivate)); - if (NULL != g_qcperf_backend_info) { - return_code = QC_PERF_RETURN_CODE_SUCCESS; - } else { - return_code = QC_PERF_RETURN_CODE_CALLOC_FAILED; - } - } - return return_code; -} - -enum QcPerfReturnCode qcperf_version(struct QcPerfVersionInfo* version_info) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; - - if (NULL == version_info) { - return_code = QC_PERF_RETURN_CODE_NULL_POINTER; - } else { - version_info->major = LIBQCPERF_VERSION_MAJOR; - version_info->minor = LIBQCPERF_VERSION_MINOR; - version_info->patch = LIBQCPERF_VERSION_PATCH; - version_info->build = LIBQCPERF_VERSION_BUILD; - } - - return return_code; -} - -enum QcPerfReturnCode qcperf_connect_backend(enum QcPerfBackendId backend_id, QcPerfMessageCallback message_callback) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; - if (NULL == g_qcperf_backend_info) { - return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; - } else if (0 > backend_id || QC_PERF_BACKEND_MAX <= backend_id) { - return_code = QC_PERF_RETURN_CODE_INVALID_BACKEND_ID; - } else if (true == g_backends_connected[backend_id]) { - return_code = QC_PERF_RETURN_CODE_BACKEND_ALREADY_CONNECTED; - } else { - return_code = backend_init_fns[backend_id](&g_qcperf_backend_info[backend_id]); // Call the backend creation function for the specified backend - if (QC_PERF_RETURN_CODE_SUCCESS == return_code) { - return_code = qcperf_verify_backend_private(backend_id); - if (QC_PERF_RETURN_CODE_SUCCESS == return_code) { - g_backends_connected[backend_id] = true; - if (message_callback != NULL) { - return_code = qcperf_set_message_callback(backend_id, message_callback); // Best case if nessage callback is passed - } - return_code = g_qcperf_backend_info[backend_id].qcperf_backend_init(); - if (QC_PERF_RETURN_CODE_SUCCESS == return_code) { - return_code = QC_PERF_RETURN_CODE_SUCCESS; - } else { - qcperf_disconnect_backend(backend_id); - } - } - } - } - return return_code; -} - -enum QcPerfReturnCode qcperf_get_capabilities_info(enum QcPerfBackendId backend_id, struct QcPerfBackendInfo* backend_info) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; - if (NULL == g_qcperf_backend_info) { - return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; - } else if (0 > backend_id || QC_PERF_BACKEND_MAX < backend_id || NULL == backend_info) { - return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; - } else if (false == g_backends_connected[backend_id]) { - return_code = QC_PERF_RETURN_CODE_BACKEND_NOT_CONNECTED; - } else { - return_code = g_qcperf_backend_info[backend_id].qcperf_backend_info(backend_info); // Call the backend get capabilities function for the specified backend - } - return return_code; -} - -enum QcPerfReturnCode qcperf_set_data_callback(enum QcPerfBackendId backend_id, QcPerfDataCallback data_callback) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; - if (NULL == g_qcperf_backend_info) { - return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; - } else if (0 > backend_id || QC_PERF_BACKEND_MAX < backend_id || NULL == data_callback) { - return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; - } else if (false == g_backends_connected[backend_id]) { - return_code = QC_PERF_RETURN_CODE_BACKEND_NOT_CONNECTED; - } else { - return_code = g_qcperf_backend_info[backend_id].set_data_callback(data_callback); - } - return return_code; -} - -enum QcPerfReturnCode qcperf_start(enum QcPerfBackendId backend_id, struct QcPerfRequest* request) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; - if (NULL == g_qcperf_backend_info) { - return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; - } else if (0 > backend_id || QC_PERF_BACKEND_MAX < backend_id || NULL == request) { - return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; - } else if (false == g_backends_connected[backend_id]) { - return_code = QC_PERF_RETURN_CODE_BACKEND_NOT_CONNECTED; - } else { - return_code = g_qcperf_backend_info[backend_id].qcperf_backend_start(request); - } - return return_code; -} - -enum QcPerfReturnCode qcperf_stop(enum QcPerfBackendId backend_id, struct QcPerfRequest* request) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; - if (NULL == g_qcperf_backend_info) { - return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; - } else if (0 > backend_id || QC_PERF_BACKEND_MAX < backend_id || NULL == request) { - return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; - } else if (false == g_backends_connected[backend_id]) { - return_code = QC_PERF_RETURN_CODE_BACKEND_NOT_CONNECTED; - } else { - return_code = g_qcperf_backend_info[backend_id].qcperf_backend_stop(request); - } - return return_code; -} - -enum QcPerfReturnCode qcperf_disconnect_backend(enum QcPerfBackendId backend_id) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; - if (NULL == g_qcperf_backend_info) { - return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; - } else if (0 > backend_id || QC_PERF_BACKEND_MAX < backend_id) { - return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; - } else if (false == g_backends_connected[backend_id]) { - return_code = QC_PERF_RETURN_CODE_BACKEND_NOT_CONNECTED; - } else { - g_backends_connected[backend_id] = false; - return_code = qcperf_reset_backend_private(backend_id); - } - return return_code; -} - -enum QcPerfReturnCode qcperf_deinit(void) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; - if (NULL == g_qcperf_backend_info) { - return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; - } else { - // check for any active backends and disconnect them if needed - for (enum QcPerfBackendId backend_id = 0; backend_id < QC_PERF_BACKEND_MAX; backend_id++) { - if (true == g_backends_connected[backend_id]) { - return_code = qcperf_disconnect_backend(backend_id); - if (QC_PERF_RETURN_CODE_SUCCESS == return_code) { - qcperf_reset_backend_private(backend_id); - g_backends_connected[backend_id] = false; - } - } - } - free(g_qcperf_backend_info); - g_qcperf_backend_info = NULL; - return_code = QC_PERF_RETURN_CODE_SUCCESS; - } - return return_code; -} - -enum QcPerfReturnCode qcperf_get_error_info(enum QcPerfReturnCode return_code, struct QcPerfReturnCodeInfo* return_info) { - enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_FAILED; - if (NULL == return_info) { - ret = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; - } else { - return_info->return_code = return_code; - switch (return_code) { - case QC_PERF_RETURN_CODE_SUCCESS: - return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Operation completed successfully"); - break; - case QC_PERF_RETURN_CODE_FAILED: - return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Requested API call failed due to an internal error"); - break; - case QC_PERF_RETURN_CODE_NOT_SUPPORTED: - return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "The requested operation is not supported by this backend"); - break; - case QC_PERF_RETURN_CODE_ALREADY_INITIALIZED: - return_info->info_str_len = - (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "QCPerf library is already initialized, call qcperf_deinit before reinitializing"); - break; - case QC_PERF_RETURN_CODE_INVALID_HANDLE: - return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Invalid handle provided to the function, please provide a valid handle"); - break; - case QC_PERF_RETURN_CODE_INVALID_ARGUMENTS: - return_info->info_str_len = - (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Invalid arguments provided to the function, please check function parameters"); - break; - case QC_PERF_RETURN_CODE_NOT_INITIALIZED: - return_info->info_str_len = - (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "QCPerf library is not initialized, call qcperf_init before using other functions"); - break; - case QC_PERF_RETURN_CODE_CAPABILITY_NOT_FOUND: - return_info->info_str_len = - (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "The requested capability was not found in the backend, check available capabilities"); - break; - case QC_PERF_RETURN_CODE_INVALID_BUFFER_SIZE: - return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "The provided buffer size is invalid or insufficient for the operation"); - break; - case QC_PERF_RETURN_CODE_NULL_POINTER: - return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "A null pointer was provided where a valid pointer is required"); - break; - case QC_PERF_RETURN_CODE_CALLOC_FAILED: - return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Memory allocation failed during operation, check system resources"); - break; - case QC_PERF_RETURN_CODE_BACKEND_ALREADY_CONNECTED: - return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Backend is already connected, disconnect first before reconnecting"); - break; - case QC_PERF_RETURN_CODE_INVALID_BACKEND_ID: - return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Invalid backend identifier provided, check available backends"); - break; - case QC_PERF_RETURN_CODE_BACKEND_NOT_CONNECTED: - return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Backend is not connected, connect the backend before using this function"); - break; - case QC_PERF_RETURN_CODE_CALLBACK_ALREADY_SET: - return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Callback function is already set for this backend"); - break; - case QC_PERF_RETURN_CODE_NATIVE_LIBRARY_FAILED: - return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Native library call failed during operation"); - break; - default: - return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Unknown error code encountered"); - break; - } - ret = QC_PERF_RETURN_CODE_SUCCESS; - } - return ret; -} - -/** - * @brief Set or update the message callback for a connected backend - * - * Registers or updates the callback function that will be invoked when the backend - * sends messages (e.g., status updates, warnings, or informational messages). - * - * @param[in] backend_id The identifier of the backend - * @param[in] message_callback The callback function to register. Can be NULL to unregister - * the current callback. - * - * @return QC_PERF_RETURN_CODE_SUCCESS on success - * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if library not initialized - * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if backend_id is invalid - * @return QC_PERF_RETURN_CODE_FAILED on failure - * - * @note The backend must be connected before calling this function - * @see qcperf_connect_backend(), QcPerfMessageCallback - */ -static enum QcPerfReturnCode qcperf_set_message_callback(enum QcPerfBackendId backend_id, QcPerfMessageCallback message_callback) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; - if (NULL == g_qcperf_backend_info) { - return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; - } else if (0 > backend_id || QC_PERF_BACKEND_MAX < backend_id || NULL == message_callback) { - return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; - } else if (false == g_backends_connected[backend_id]) { - return_code = QC_PERF_RETURN_CODE_BACKEND_NOT_CONNECTED; - } else { - return_code = g_qcperf_backend_info[backend_id].set_message_callback(message_callback); - } - return return_code; -} - -/** - * @brief Reset a backend's function pointers to NULL - * - * This function resets all function pointers for a specific backend to NULL, - * effectively clearing its interface. Used during backend disconnection and - * library deinitialization to ensure clean state. - * - * @param[in] backend_id The identifier of the backend to reset - * @return QC_PERF_RETURN_CODE_SUCCESS on successful reset - * @return QC_PERF_RETURN_CODE_NULL_POINTER if backend info is NULL - */ -static enum QcPerfReturnCode qcperf_reset_backend_private(enum QcPerfBackendId backend_id) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_NULL_POINTER; - if (0 > backend_id || QC_PERF_BACKEND_MAX < backend_id) { - return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; - } - if (NULL != g_qcperf_backend_info) { - g_qcperf_backend_info[backend_id].qcperf_backend_init = NULL; - g_qcperf_backend_info[backend_id].qcperf_backend_start = NULL; - g_qcperf_backend_info[backend_id].qcperf_backend_stop = NULL; - g_qcperf_backend_info[backend_id].qcperf_backend_deinit = NULL; - g_qcperf_backend_info[backend_id].qcperf_backend_info = NULL; - g_qcperf_backend_info[backend_id].set_message_callback = NULL; - g_qcperf_backend_info[backend_id].set_data_callback = NULL; - return_code = QC_PERF_RETURN_CODE_SUCCESS; - } - return return_code; -} - -/** - * @brief Verify that all required function pointers are set for a backend - * - * This function checks that all function pointers in a backend's interface - * structure are non-NULL, ensuring the backend is fully initialized and ready to use. - * - * @param[in] backend_id The identifier of the backend to verify - * @return QC_PERF_RETURN_CODE_SUCCESS if all function pointers are set - * @return QC_PERF_RETURN_CODE_NULL_POINTER if any function pointer is NULL - */ -static enum QcPerfReturnCode qcperf_verify_backend_private(enum QcPerfBackendId backend_id) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_NULL_POINTER; - if (NULL != g_qcperf_backend_info) { - if ((NULL != g_qcperf_backend_info[backend_id].qcperf_backend_init) && (NULL != g_qcperf_backend_info[backend_id].qcperf_backend_start) && - (NULL != g_qcperf_backend_info[backend_id].qcperf_backend_stop) && (NULL != g_qcperf_backend_info[backend_id].qcperf_backend_deinit) && - (NULL != g_qcperf_backend_info[backend_id].qcperf_backend_info) && (NULL != g_qcperf_backend_info[backend_id].set_message_callback) && - (NULL != g_qcperf_backend_info[backend_id].set_data_callback)) { - return_code = QC_PERF_RETURN_CODE_SUCCESS; - } - } - return return_code; -} +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file qcperf.c + * @brief Implementation of the QcPerf library main API + * @author Skand Gupta (skangupt@qti.qualcomm.com) + * + * This file implements the public API functions defined in qcperf.h, providing + * the core functionality of the QcPerf library. It manages backend connections, + * handles performance monitoring requests, and coordinates data collection and + * delivery between backends and applications. + * + * The implementation follows a modular design where each backend is represented + * by a set of function pointers that are initialized during backend connection. + * This allows for a flexible and extensible architecture where new backends can + * be added without modifying the core library code. + */ + +#include +#include +#include + +#include "qcperf.h" +#include "qcperf_common.h" +#include "qcperf_backends.h" +#include "internal/qcperf_backend_interface.h" +#include "version_info.h" + +// Private function declarations for backend-specific implementation of public API +static enum QcPerfReturnCode qcperf_reset_backend_private(enum QcPerfBackendId backend_id); +static enum QcPerfReturnCode qcperf_verify_backend_private(enum QcPerfBackendId backend_id); +static enum QcPerfReturnCode qcperf_set_message_callback(enum QcPerfBackendId backend_id, QcPerfMessageCallback message_callback); + +/** + * @brief Global array of backend interface structures + * + * This array stores the function pointers for each backend's implementation + * of the QcPerf interface. It is allocated during qcperf_init() and freed + * during qcperf_deinit(). + */ +static struct QcPerfBackendPrivate* g_qcperf_backend_info = NULL; + +/** + * @brief Connection status for each backend + * + * This array tracks which backends are currently connected. + * Each element corresponds to a backend ID, where true indicates + * the backend is connected and false indicates it is not. + */ +bool g_backends_connected[QC_PERF_BACKEND_MAX] = {0}; // [0] = first backend, [1] = second backend, etc. + +enum QcPerfReturnCode qcperf_init(void) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; + if (NULL != g_qcperf_backend_info) { + return_code = QC_PERF_RETURN_CODE_ALREADY_INITIALIZED; + } else { + g_qcperf_backend_info = (struct QcPerfBackendPrivate*)calloc(QC_PERF_BACKEND_MAX, sizeof(struct QcPerfBackendPrivate)); + if (NULL != g_qcperf_backend_info) { + return_code = QC_PERF_RETURN_CODE_SUCCESS; + } else { + return_code = QC_PERF_RETURN_CODE_CALLOC_FAILED; + } + } + return return_code; +} + +enum QcPerfReturnCode qcperf_version(struct QcPerfVersionInfo* version_info) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; + + if (NULL == version_info) { + return_code = QC_PERF_RETURN_CODE_NULL_POINTER; + } else { + version_info->major = LIBQCPERF_VERSION_MAJOR; + version_info->minor = LIBQCPERF_VERSION_MINOR; + version_info->patch = LIBQCPERF_VERSION_PATCH; + version_info->build = LIBQCPERF_VERSION_BUILD; + } + + return return_code; +} + +enum QcPerfReturnCode qcperf_connect_backend(enum QcPerfBackendId backend_id, QcPerfMessageCallback message_callback) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; + if (NULL == g_qcperf_backend_info) { + return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; + } else if (0 > backend_id || QC_PERF_BACKEND_MAX <= backend_id) { + return_code = QC_PERF_RETURN_CODE_INVALID_BACKEND_ID; + } else if (true == g_backends_connected[backend_id]) { + return_code = QC_PERF_RETURN_CODE_BACKEND_ALREADY_CONNECTED; + } else if (NULL == backend_init_fns[backend_id]) { + return_code = QC_PERF_RETURN_CODE_INVALID_BACKEND_ID; + } else { + return_code = backend_init_fns[backend_id](&g_qcperf_backend_info[backend_id]); // Call the backend creation function for the specified backend + if (QC_PERF_RETURN_CODE_SUCCESS == return_code) { + return_code = qcperf_verify_backend_private(backend_id); + if (QC_PERF_RETURN_CODE_SUCCESS == return_code) { + g_backends_connected[backend_id] = true; + if (message_callback != NULL) { + return_code = qcperf_set_message_callback(backend_id, message_callback); // Best case if nessage callback is passed + } + return_code = g_qcperf_backend_info[backend_id].qcperf_backend_init(); + if (QC_PERF_RETURN_CODE_SUCCESS == return_code) { + return_code = QC_PERF_RETURN_CODE_SUCCESS; + } else { + qcperf_disconnect_backend(backend_id); + } + } + } + } + return return_code; +} + +enum QcPerfReturnCode qcperf_get_capabilities_info(enum QcPerfBackendId backend_id, struct QcPerfBackendInfo* backend_info) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; + if (NULL == g_qcperf_backend_info) { + return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; + } else if (0 > backend_id || QC_PERF_BACKEND_MAX < backend_id || NULL == backend_info) { + return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; + } else if (false == g_backends_connected[backend_id]) { + return_code = QC_PERF_RETURN_CODE_BACKEND_NOT_CONNECTED; + } else { + return_code = g_qcperf_backend_info[backend_id].qcperf_backend_info(backend_info); // Call the backend get capabilities function for the specified backend + } + return return_code; +} + +enum QcPerfReturnCode qcperf_set_data_callback(enum QcPerfBackendId backend_id, QcPerfDataCallback data_callback) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; + if (NULL == g_qcperf_backend_info) { + return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; + } else if (0 > backend_id || QC_PERF_BACKEND_MAX < backend_id || NULL == data_callback) { + return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; + } else if (false == g_backends_connected[backend_id]) { + return_code = QC_PERF_RETURN_CODE_BACKEND_NOT_CONNECTED; + } else { + return_code = g_qcperf_backend_info[backend_id].set_data_callback(data_callback); + } + return return_code; +} + +enum QcPerfReturnCode qcperf_start(enum QcPerfBackendId backend_id, struct QcPerfRequest* request) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; + if (NULL == g_qcperf_backend_info) { + return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; + } else if (0 > backend_id || QC_PERF_BACKEND_MAX < backend_id || NULL == request) { + return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; + } else if (false == g_backends_connected[backend_id]) { + return_code = QC_PERF_RETURN_CODE_BACKEND_NOT_CONNECTED; + } else { + return_code = g_qcperf_backend_info[backend_id].qcperf_backend_start(request); + } + return return_code; +} + +enum QcPerfReturnCode qcperf_stop(enum QcPerfBackendId backend_id, struct QcPerfRequest* request) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; + if (NULL == g_qcperf_backend_info) { + return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; + } else if (0 > backend_id || QC_PERF_BACKEND_MAX < backend_id || NULL == request) { + return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; + } else if (false == g_backends_connected[backend_id]) { + return_code = QC_PERF_RETURN_CODE_BACKEND_NOT_CONNECTED; + } else { + return_code = g_qcperf_backend_info[backend_id].qcperf_backend_stop(request); + } + return return_code; +} + +enum QcPerfReturnCode qcperf_disconnect_backend(enum QcPerfBackendId backend_id) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; + if (NULL == g_qcperf_backend_info) { + return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; + } else if (0 > backend_id || QC_PERF_BACKEND_MAX < backend_id) { + return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; + } else if (false == g_backends_connected[backend_id]) { + return_code = QC_PERF_RETURN_CODE_BACKEND_NOT_CONNECTED; + } else { + g_backends_connected[backend_id] = false; + return_code = qcperf_reset_backend_private(backend_id); + } + return return_code; +} + +enum QcPerfReturnCode qcperf_deinit(void) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; + if (NULL == g_qcperf_backend_info) { + return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; + } else { + // check for any active backends and disconnect them if needed + for (enum QcPerfBackendId backend_id = 0; backend_id < QC_PERF_BACKEND_MAX; backend_id++) { + if (true == g_backends_connected[backend_id]) { + return_code = qcperf_disconnect_backend(backend_id); + if (QC_PERF_RETURN_CODE_SUCCESS == return_code) { + qcperf_reset_backend_private(backend_id); + g_backends_connected[backend_id] = false; + } + } + } + free(g_qcperf_backend_info); + g_qcperf_backend_info = NULL; + return_code = QC_PERF_RETURN_CODE_SUCCESS; + } + return return_code; +} + +enum QcPerfReturnCode qcperf_get_error_info(enum QcPerfReturnCode return_code, struct QcPerfReturnCodeInfo* return_info) { + enum QcPerfReturnCode ret = QC_PERF_RETURN_CODE_FAILED; + if (NULL == return_info) { + ret = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; + } else { + return_info->return_code = return_code; + switch (return_code) { + case QC_PERF_RETURN_CODE_SUCCESS: + return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Operation completed successfully"); + break; + case QC_PERF_RETURN_CODE_FAILED: + return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Requested API call failed due to an internal error"); + break; + case QC_PERF_RETURN_CODE_NOT_SUPPORTED: + return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "The requested operation is not supported by this backend"); + break; + case QC_PERF_RETURN_CODE_ALREADY_INITIALIZED: + return_info->info_str_len = + (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "QCPerf library is already initialized, call qcperf_deinit before reinitializing"); + break; + case QC_PERF_RETURN_CODE_INVALID_HANDLE: + return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Invalid handle provided to the function, please provide a valid handle"); + break; + case QC_PERF_RETURN_CODE_INVALID_ARGUMENTS: + return_info->info_str_len = + (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Invalid arguments provided to the function, please check function parameters"); + break; + case QC_PERF_RETURN_CODE_NOT_INITIALIZED: + return_info->info_str_len = + (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "QCPerf library is not initialized, call qcperf_init before using other functions"); + break; + case QC_PERF_RETURN_CODE_CAPABILITY_NOT_FOUND: + return_info->info_str_len = + (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "The requested capability was not found in the backend, check available capabilities"); + break; + case QC_PERF_RETURN_CODE_INVALID_BUFFER_SIZE: + return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "The provided buffer size is invalid or insufficient for the operation"); + break; + case QC_PERF_RETURN_CODE_NULL_POINTER: + return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "A null pointer was provided where a valid pointer is required"); + break; + case QC_PERF_RETURN_CODE_CALLOC_FAILED: + return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Memory allocation failed during operation, check system resources"); + break; + case QC_PERF_RETURN_CODE_BACKEND_ALREADY_CONNECTED: + return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Backend is already connected, disconnect first before reconnecting"); + break; + case QC_PERF_RETURN_CODE_INVALID_BACKEND_ID: + return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Invalid backend identifier provided, check available backends"); + break; + case QC_PERF_RETURN_CODE_BACKEND_NOT_CONNECTED: + return_info->info_str_len = + (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Backend is not connected, connect the backend before using this function"); + break; + case QC_PERF_RETURN_CODE_CALLBACK_ALREADY_SET: + return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Callback function is already set for this backend"); + break; + case QC_PERF_RETURN_CODE_NATIVE_LIBRARY_FAILED: + return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Native library call failed during operation"); + break; + default: + return_info->info_str_len = (size_t)snprintf((char*)return_info->info_str, RETURN_CODE_INFO_STRING_MAX_LEN, "%s", "Unknown error code encountered"); + break; + } + ret = QC_PERF_RETURN_CODE_SUCCESS; + } + return ret; +} + +/** + * @brief Set or update the message callback for a connected backend + * + * Registers or updates the callback function that will be invoked when the backend + * sends messages (e.g., status updates, warnings, or informational messages). + * + * @param[in] backend_id The identifier of the backend + * @param[in] message_callback The callback function to register. Can be NULL to unregister + * the current callback. + * + * @return QC_PERF_RETURN_CODE_SUCCESS on success + * @return QC_PERF_RETURN_CODE_NOT_INITIALIZED if library not initialized + * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if backend_id is invalid + * @return QC_PERF_RETURN_CODE_FAILED on failure + * + * @note The backend must be connected before calling this function + * @see qcperf_connect_backend(), QcPerfMessageCallback + */ +static enum QcPerfReturnCode qcperf_set_message_callback(enum QcPerfBackendId backend_id, QcPerfMessageCallback message_callback) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; + if (NULL == g_qcperf_backend_info) { + return_code = QC_PERF_RETURN_CODE_NOT_INITIALIZED; + } else if (0 > backend_id || QC_PERF_BACKEND_MAX < backend_id || NULL == message_callback) { + return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; + } else if (false == g_backends_connected[backend_id]) { + return_code = QC_PERF_RETURN_CODE_BACKEND_NOT_CONNECTED; + } else { + return_code = g_qcperf_backend_info[backend_id].set_message_callback(message_callback); + } + return return_code; +} + +/** + * @brief Reset a backend's function pointers to NULL + * + * This function resets all function pointers for a specific backend to NULL, + * effectively clearing its interface. Used during backend disconnection and + * library deinitialization to ensure clean state. + * + * @param[in] backend_id The identifier of the backend to reset + * @return QC_PERF_RETURN_CODE_SUCCESS on successful reset + * @return QC_PERF_RETURN_CODE_NULL_POINTER if backend info is NULL + */ +static enum QcPerfReturnCode qcperf_reset_backend_private(enum QcPerfBackendId backend_id) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_NULL_POINTER; + if (0 > backend_id || QC_PERF_BACKEND_MAX < backend_id) { + return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; + } + if (NULL != g_qcperf_backend_info) { + g_qcperf_backend_info[backend_id].qcperf_backend_init = NULL; + g_qcperf_backend_info[backend_id].qcperf_backend_start = NULL; + g_qcperf_backend_info[backend_id].qcperf_backend_stop = NULL; + g_qcperf_backend_info[backend_id].qcperf_backend_deinit = NULL; + g_qcperf_backend_info[backend_id].qcperf_backend_info = NULL; + g_qcperf_backend_info[backend_id].set_message_callback = NULL; + g_qcperf_backend_info[backend_id].set_data_callback = NULL; + return_code = QC_PERF_RETURN_CODE_SUCCESS; + } + return return_code; +} + +/** + * @brief Verify that all required function pointers are set for a backend + * + * This function checks that all function pointers in a backend's interface + * structure are non-NULL, ensuring the backend is fully initialized and ready to use. + * + * @param[in] backend_id The identifier of the backend to verify + * @return QC_PERF_RETURN_CODE_SUCCESS if all function pointers are set + * @return QC_PERF_RETURN_CODE_NULL_POINTER if any function pointer is NULL + */ +static enum QcPerfReturnCode qcperf_verify_backend_private(enum QcPerfBackendId backend_id) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_NULL_POINTER; + if (NULL != g_qcperf_backend_info) { + if ((NULL != g_qcperf_backend_info[backend_id].qcperf_backend_init) && (NULL != g_qcperf_backend_info[backend_id].qcperf_backend_start) && + (NULL != g_qcperf_backend_info[backend_id].qcperf_backend_stop) && (NULL != g_qcperf_backend_info[backend_id].qcperf_backend_deinit) && + (NULL != g_qcperf_backend_info[backend_id].qcperf_backend_info) && (NULL != g_qcperf_backend_info[backend_id].set_message_callback) && + (NULL != g_qcperf_backend_info[backend_id].set_data_callback)) { + return_code = QC_PERF_RETURN_CODE_SUCCESS; + } + } + return return_code; +} diff --git a/qcperf/test_app/CMakeLists.txt b/qcperf/test_app/CMakeLists.txt index 44d0583..ecb4c21 100644 --- a/qcperf/test_app/CMakeLists.txt +++ b/qcperf/test_app/CMakeLists.txt @@ -1,36 +1,41 @@ -# Create the main QcPerfCoreTest library -add_executable(QcPerfCoreTest - src/qcperf_core_test.c -) - -# Set target properties -set_target_properties(QcPerfCoreTest PROPERTIES - OUTPUT_NAME "QcPerfCoreTest" - POSITION_INDEPENDENT_CODE OFF -) - -# Include directories for the core library -target_include_directories(QcPerfCoreTest - PUBLIC - ${CMAKE_SOURCE_DIR}/core/inc -) - -# Link dependencies -target_link_libraries(QcPerfCoreTest - PUBLIC - QcPerfCore -) - -# Compiler-specific options for the core library -if(MSVC) - target_compile_options(QcPerfCoreTest PRIVATE - /W4 - /WX- # Don't treat warnings as errors (can be changed to /WX if needed) - ) -else() - target_compile_options(QcPerfCoreTest PRIVATE - -Wall - -Wextra - -Wpedantic - ) -endif() +# Create the main QcPerfCoreTest library +add_executable(QcPerfCoreTest + src/qcperf_core_test.c +) + +# Set target properties +set_target_properties(QcPerfCoreTest PROPERTIES + OUTPUT_NAME "QcPerfCoreTest" + POSITION_INDEPENDENT_CODE OFF +) + +# Include directories for the core library +target_include_directories(QcPerfCoreTest + PUBLIC + ${CMAKE_SOURCE_DIR}/core/inc +) + +# Link dependencies +target_link_libraries(QcPerfCoreTest + PUBLIC + QcPerfCore +) +if(NOT BUILD_SHARED AND QCPERF_LINUX_ARM64 AND QCPERF_ENABLED_QCOM_LINUX_NPU) + target_link_libraries(QcPerfCoreTest PRIVATE + cdsprpc + ) +endif() + +# Compiler-specific options for the core library +if(MSVC) + target_compile_options(QcPerfCoreTest PRIVATE + /W4 + /WX- # Don't treat warnings as errors (can be changed to /WX if needed) + ) +else() + target_compile_options(QcPerfCoreTest PRIVATE + -Wall + -Wextra + -Wpedantic + ) +endif() diff --git a/qcperf/test_app/src/qcperf_core_test.c b/qcperf/test_app/src/qcperf_core_test.c index a5e7df9..7afaabb 100644 --- a/qcperf/test_app/src/qcperf_core_test.c +++ b/qcperf/test_app/src/qcperf_core_test.c @@ -1,749 +1,775 @@ -/* - Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - Redistribution and use in source and binary forms, with or without - modification, are permitted (subject to the limitations in the - disclaimer below) provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Qualcomm Technologies, Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE - GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT - HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/** - * @file qcperf_core_test.c - * @brief Test application for the QcPerf library core functionality - * @author Skand Gupta (skangupt@qti.qualcomm.com) - * - * This file implements a comprehensive test application that exercises the core - * functionality of the QcPerf library. It validates the complete workflow from - * initialization to cleanup, including backend connection, capability discovery, - * data collection, and proper resource management. - * - * The test application performs the following operations: - * 1. Library initialization with qcperf_init() - * 2. Backend connection with qcperf_connect_backend() - * 3. Capability discovery with qcperf_get_capabilities_info() - * 4. Deep copying of backend information for verbose printing - * 5. Callback registration for messages and data - * 6. Performance monitoring with qcperf_start() and qcperf_stop() - * 7. Backend disconnection with qcperf_disconnect_backend() - * 8. Library deinitialization with qcperf_deinit() - * 9. Proper cleanup of all allocated resources - * - * The test uses the dummy backend to verify the library's functionality - * without requiring actual hardware performance monitoring. This ensures - * that the core API functions correctly in a controlled environment. - */ - -#include -#include -#include -#ifdef _WIN32 -#include // This includes winnt.h internally -#else -#include -#endif - -#include "qcperf.h" -#include "qcperf_common.h" - -/** - * @def RETURN_SUCCESS - * @brief Return code indicating successful test execution - * - * This value is returned by main() when all test operations complete successfully. - */ -#define RETURN_SUCCESS 0 - -/** - * @def RETURN_FAILED - * @brief Return code indicating test failure - * - * This value is returned by main() when any test operation fails. - */ -#define RETURN_FAILED -1 - -/** - * @brief Flag to control verbose printing of metric values - * - * When set to true, additional information about metrics will be printed, - * including metric names, descriptions, and units. This requires creating - * a deep copy of the backend information structure. - * - * When set to false, only essential information will be printed (metric IDs - * and values), which is more efficient but less informative. - */ -volatile bool g_is_verbose_print = false; - -/** - * @brief Flag to control verbose printing of error information - * - * When set to true, detailed error information will be retrieved using - * qcperf_get_error_info() and printed, including error codes and descriptive messages. - * - * When set to false, only a newline will be printed after error messages, - * resulting in more concise output but less diagnostic information. - */ -bool g_is_error_verbose = true; - -volatile struct QcPerfBackendInfo* g_backend_info = NULL; - -/** - * @brief Print a metric value based on its data type - * - * This function prints a metric value from a QcPerfGenericType structure - * to stdout, formatting the output based on the data type. It handles all - * supported data types (boolean, integer, floating-point, and string values) - * with appropriate formatting for each type. - * - * @param[in] metric_value Pointer to the QcPerfGenericType structure containing the value - * - * @note If metric_value is NULL, "NULL" will be printed. - * @note For string values, if the string pointer is NULL, "(null)" will be printed. - * @note For unknown data types, "Unknown type X" will be printed, where X is the data type value. - */ -void print_metric_value(const struct QcPerfGenericType* metric_value) { - if (NULL == metric_value) { - printf("NULL\n"); - } else { - switch (metric_value->data_type) { - case QC_PERF_DATA_TYPE_BOOL: - if (metric_value->bool_value) { - printf("true"); - } else { - printf("false"); - } - break; - case QC_PERF_DATA_TYPE_UINT64: - printf("%llu", (unsigned long long)metric_value->uint64_value); - break; - case QC_PERF_DATA_TYPE_INT64: - printf("%lld", (long long)metric_value->int64_value); - break; - case QC_PERF_DATA_TYPE_DOUBLE: - printf("%f", metric_value->double_value); - break; - case QC_PERF_DATA_TYPE_STRING: - if (NULL != metric_value->string_value) { - printf("%.*s", (int)metric_value->string_value_len, (char*)metric_value->string_value); - } else { - printf("(null)"); - } - break; - default: - printf("Unknown type %d", metric_value->data_type); - break; - } - } -} - -/** - * @brief Print detailed error information for a return code - * - * This function retrieves and prints detailed error information for a given - * return code using qcperf_get_error_info(). The verbosity of the output - * is controlled by the g_is_error_verbose flag. - * - * @param[in] return_code The return code to get information for - * - * @note If g_is_error_verbose is true, detailed error information will be printed. - * @note If g_is_error_verbose is false, only a newline will be printed. - * - * @see qcperf_get_error_info() - * @see g_is_error_verbose - */ -void print_error_info(enum QcPerfReturnCode return_code) { - struct QcPerfReturnCodeInfo info = {0}; - if (g_is_error_verbose) { - qcperf_get_error_info(return_code, &info); - printf("[ERROR] %s (code: %d)\n", info.info_str, return_code); - } else { - printf("\n"); - } -} - -/** - * @brief Message callback function for receiving messages from the backend - * - * This function is registered with the QcPerf library using qcperf_set_message_callback() - * to receive informational, warning, and error messages from the backend. - * It validates the message pointer and prints the message level and content to stdout. - * - * @param[in] message Pointer to the QcPerfMessage structure containing: - * - message: The message text - * - message_length: Length of the message in bytes - * - message_level: Severity level (debug, info, warning, error) - * - * @return QC_PERF_RETURN_CODE_SUCCESS if the message was processed successfully - * @return QC_PERF_RETURN_CODE_FAILED if the message pointer is NULL or the message text is NULL - * - * @see qcperf_set_message_callback() - * @see struct QcPerfMessage - */ -enum QcPerfReturnCode message_callback(struct QcPerfMessage* message) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; - const char* level_str = "UNKNOWN"; - - if (NULL == message || NULL == message->message) { - printf("[ERROR] Message callback received NULL message\n"); - return_code = QC_PERF_RETURN_CODE_FAILED; - } else { - // Convert message level to human-readable string - switch (message->message_level) { - case QC_PERF_MESSAGE_LEVEL_DEBUG: - level_str = "DEBUG"; - break; - case QC_PERF_MESSAGE_LEVEL_INFO: - level_str = "INFO"; - break; - case QC_PERF_MESSAGE_LEVEL_WARNING: - level_str = "WARNING"; - break; - case QC_PERF_MESSAGE_LEVEL_ERROR: - level_str = "ERROR"; - break; - default: - level_str = "UNKNOWN"; - break; - } - if (message->message_level != QC_PERF_MESSAGE_LEVEL_DEBUG) { - printf("[%s] Backend message: %s\n", level_str, message->message); - } - - return_code = QC_PERF_RETURN_CODE_SUCCESS; - } - return return_code; -} - -/** - * @brief Callback function for receiving performance data from the backend - * - * This function is registered with the QcPerf library using qcperf_set_data_callback() - * to receive performance metric data from the backend. It validates the data pointer - * and prints the capability ID, number of metrics, and metric values to stdout. - * - * The function supports two output modes: - * 1. Verbose mode: Prints metric names, descriptions, and units (requires g_backend_info) - * 2. Basic mode: Prints only metric IDs and values - * - * @param[in] data Pointer to the QcPerfData structure containing: - * - capabilityId: The capability that generated the data - * - metric_response: Array of metric responses - * - metric_response_len: Number of metrics in the array - * - * @return QC_PERF_RETURN_CODE_SUCCESS if the data was processed successfully - * @return QC_PERF_RETURN_CODE_FAILED if the data pointer is NULL or invalid - * - * @see qcperf_set_data_callback() - * @see struct QcPerfData - * @see g_is_verbose_print - * @see print_metric_value() - */ -enum QcPerfReturnCode result_callback(struct QcPerfData* data) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; - bool metric_found = false; - const char* metric_name = NULL; - const char* metric_unit = NULL; - const char* metric_desc = NULL; - if (NULL == data) { - printf("[ERROR] Data callback received NULL data\n"); - return_code = QC_PERF_RETURN_CODE_FAILED; - } else { - printf("[DATA] Capability ID: %d, Metrics count: %d\n", data->capabilityId, data->metric_response_len); - - if (NULL != data->metric_response) { - for (uint32_t metric_index = 0; metric_index < data->metric_response_len; metric_index++) { - // Check if we can use verbose printing mode - if (g_is_verbose_print && NULL != g_backend_info && NULL != g_backend_info->capabilities_list && data->capabilityId < g_backend_info->capabilities_list_length && - NULL != g_backend_info->capabilities_list[data->capabilityId].metric_ids_list) { - // Search for the metric by ID (don't use metric_id as array index) - for (uint32_t i = 0; i < g_backend_info->capabilities_list[data->capabilityId].metric_ids_list_len; i++) { - if (g_backend_info->capabilities_list[data->capabilityId].metric_ids_list[i].metric_id == data->metric_response[metric_index].metric_id) { - metric_name = g_backend_info->capabilities_list[data->capabilityId].metric_ids_list[i].metric_name; - metric_unit = g_backend_info->capabilities_list[data->capabilityId].metric_ids_list[i].metric_unit; - metric_desc = g_backend_info->capabilities_list[data->capabilityId].metric_ids_list[i].metric_description; - metric_found = true; - break; - } - } - - if (true == metric_found) { - // Verbose mode - print metric name, value, unit and description - printf(" [%llu] %s: ", (unsigned long long)data->metric_response[metric_index].timestamp, metric_name); - print_metric_value(&data->metric_response[metric_index].metric_value); - printf(" %s (%s)\n", metric_unit, metric_desc); - } else { - // Metric not found in list - print only metric ID and value - printf(" [%llu] Metric ID %d: ", (unsigned long long)data->metric_response[metric_index].timestamp, data->metric_response[metric_index].metric_id); - print_metric_value(&data->metric_response[metric_index].metric_value); - printf("\n"); - } - } else { - // Basic mode - print only metric ID and value - printf(" [%llu] Metric ID %d: ", (unsigned long long)data->metric_response[metric_index].timestamp, data->metric_response[metric_index].metric_id); - print_metric_value(&data->metric_response[metric_index].metric_value); - printf("\n"); - } - } - return_code = QC_PERF_RETURN_CODE_SUCCESS; - } - } - return return_code; -} - -/** - * @brief Main entry point for the QcPerf core test application - * - * This function performs a comprehensive test of the QcPerf library's core functionality, - * exercising the complete workflow from initialization to cleanup. It tests: - * - * 1. Library initialization with qcperf_init() - * 2. Backend connection with qcperf_connect_backend() - * 3. Capability discovery with qcperf_get_capabilities_info() - * 4. Deep copying of backend information (when verbose printing is enabled) - * 5. Message callback registration with qcperf_set_message_callback() - * 6. Data callback registration with qcperf_set_data_callback() - * 7. Performance monitoring with qcperf_start() and qcperf_stop() - * 8. Backend disconnection with qcperf_disconnect_backend() - * 9. Library deinitialization with qcperf_deinit() - * 10. Proper cleanup of all allocated resources - * - * The function includes comprehensive error handling and resource management, - * ensuring that all allocated memory is properly freed even in error cases. - * - * @param[in] argc Number of command line arguments (unused) - * @param[in] argv Array of command line argument strings (unused) - * - * @return RETURN_SUCCESS (0) if all tests pass - * @return RETURN_FAILED (-1) if any test fails - * - * @see qcperf_init() - * @see qcperf_connect_backend() - * @see qcperf_get_capabilities_info() - * @see qcperf_set_message_callback() - * @see qcperf_set_data_callback() - * @see qcperf_start() - * @see qcperf_stop() - * @see qcperf_disconnect_backend() - * @see qcperf_deinit() - */ -/** - * @brief Create a deep copy of backend info for verbose printing - * - * This function creates a deep copy of the backend information structure, - * including all nested capability and metric information. If any allocation - * fails during the copy process, all previously allocated memory is properly - * cleaned up before returning an error code. - * - * @param[in] backend_info Source backend info structure to copy - * @return QC_PERF_RETURN_CODE_SUCCESS if successful - * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if backend_info is NULL - * @return QC_PERF_RETURN_CODE_CALLOC_FAILED if memory allocation fails - * - * @note On failure, g_backend_info is set to NULL and g_is_verbose_print is set to false - * @note All allocated memory is freed on failure to prevent memory leaks - */ -static enum QcPerfReturnCode create_backend_info_copy(const struct QcPerfBackendInfo* backend_info) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; - uint8_t capability_itr = 0; - uint8_t metric_id_itr = 0; - - if (NULL == backend_info) { - return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; - } else { - // Allocate memory for global backend info - g_backend_info = (struct QcPerfBackendInfo*)calloc(1, sizeof(struct QcPerfBackendInfo)); - if (NULL == g_backend_info) { - printf("Failed to allocate memory for global backend info, disabling verbose print\n"); - g_is_verbose_print = false; - return_code = QC_PERF_RETURN_CODE_CALLOC_FAILED; - } else { - // Copy basic fields - g_backend_info->backend_id = backend_info->backend_id; - g_backend_info->capabilities_list_length = backend_info->capabilities_list_length; - - // Allocate memory for capabilities list - g_backend_info->capabilities_list = (struct QcPerfCapabilityInfo*)calloc(backend_info->capabilities_list_length, sizeof(struct QcPerfCapabilityInfo)); - - if (NULL == g_backend_info->capabilities_list) { - printf("Failed to allocate memory for capabilities list, disabling verbose print\n"); - g_is_verbose_print = false; - free((void*)g_backend_info); - g_backend_info = NULL; - return_code = QC_PERF_RETURN_CODE_CALLOC_FAILED; - } else { - // Copy each capability - for (capability_itr = 0; capability_itr < backend_info->capabilities_list_length; capability_itr++) { - // Copy capability structure - memcpy(&g_backend_info->capabilities_list[capability_itr], &backend_info->capabilities_list[capability_itr], sizeof(struct QcPerfCapabilityInfo)); - - // Allocate memory for metric_ids_list - g_backend_info->capabilities_list[capability_itr].metric_ids_list = - (struct QcPerfMetricInfo*)calloc(backend_info->capabilities_list[capability_itr].metric_ids_list_len, sizeof(struct QcPerfMetricInfo)); - - if (NULL == g_backend_info->capabilities_list[capability_itr].metric_ids_list) { - printf("Failed to allocate memory for metric IDs list, disabling verbose print\n"); - g_is_verbose_print = false; - return_code = QC_PERF_RETURN_CODE_CALLOC_FAILED; - // Clean up previously allocated metric_ids_list arrays - for (uint8_t cleanup_itr = 0; cleanup_itr < capability_itr; cleanup_itr++) { - if (NULL != g_backend_info->capabilities_list[cleanup_itr].metric_ids_list) { - free(g_backend_info->capabilities_list[cleanup_itr].metric_ids_list); - g_backend_info->capabilities_list[cleanup_itr].metric_ids_list = NULL; - } - } - free(g_backend_info->capabilities_list); - g_backend_info->capabilities_list = NULL; - free((void*)g_backend_info); - g_backend_info = NULL; - } else { - // Copy each metric - for (metric_id_itr = 0; metric_id_itr < g_backend_info->capabilities_list[capability_itr].metric_ids_list_len; metric_id_itr++) { - memcpy(&g_backend_info->capabilities_list[capability_itr].metric_ids_list[metric_id_itr], &backend_info->capabilities_list[capability_itr].metric_ids_list[metric_id_itr], - sizeof(struct QcPerfMetricInfo)); - } - } - } - } - } - } - return return_code; -} - -/** - * @brief Clean up the global backend info structure - */ -static void cleanup_backend_info(void) { - uint8_t capability_itr = 0; - - if (NULL == g_backend_info) { - return; - } - - if (NULL != g_backend_info->capabilities_list) { - for (capability_itr = 0; capability_itr < g_backend_info->capabilities_list_length; capability_itr++) { - if (NULL != g_backend_info->capabilities_list[capability_itr].metric_ids_list) { - free(g_backend_info->capabilities_list[capability_itr].metric_ids_list); - g_backend_info->capabilities_list[capability_itr].metric_ids_list = NULL; - } - } - free(g_backend_info->capabilities_list); - g_backend_info->capabilities_list = NULL; - } - - free(g_backend_info); - g_backend_info = NULL; -} - -/** - * @brief Test a specific capability - * - * @param[in] test_backend Backend ID to test - * @param[in] capability_info Pointer to capability information - * @param[in] request Pointer to request structure to use - * @return QC_PERF_RETURN_CODE_SUCCESS if successful, error code otherwise - */ -static enum QcPerfReturnCode test_capability(enum QcPerfBackendId test_backend, const struct QcPerfCapabilityInfo* capability_info, struct QcPerfRequest* request) { - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; - - if (NULL == capability_info || NULL == request) { - printf("[ERROR] Invalid parameters for capability test\n"); - return_code = QC_PERF_RETURN_CODE_FAILED; - } else { - printf("\n========================================================================\n"); - printf("[TEST] Testing capability ID: %d", capability_info->capability_id); - - if (g_is_verbose_print && NULL != capability_info->capability_name) { - printf(" (%s)", capability_info->capability_name); - } - printf("\n"); - - // Configure request with capability's recommended settings - request->capability_id = capability_info->capability_id; - - printf("[INFO] Using sampling rate: %d ms, streaming rate: %d ms\n", request->sampling_rate, request->streaming_rate); - - // Start profiling - printf("[INFO] Starting profiling...\n"); - return_code = qcperf_start(test_backend, request); - if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { - printf("[ERROR] Failed to start profiling"); - print_error_info(return_code); - } else { - printf("[INFO] Profiling started successfully\n"); - - // Wait for data collection -#ifdef _WIN32 - printf("[INFO] Collecting data for 10 seconds...\n"); - Sleep(10000); // Wait for 10 seconds to allow profiling to run -#else - printf("[INFO] Collecting data for 10 seconds...\n"); - sleep(10); // Wait for 10 seconds to allow profiling to run -#endif - - // Stop profiling - printf("[INFO] Stopping profiling...\n"); - return_code = qcperf_stop(test_backend, request); - if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { - printf("[ERROR] Failed to stop profiling"); - print_error_info(return_code); - } else { - printf("[INFO] Profiling stopped successfully\n"); - } - } - - printf("========================================================================\n"); - } - return return_code; -} - -/** - * @brief Main entry point for the QcPerf core test application - * - * @param[in] argc Number of command line arguments (unused) - * @param[in] argv Array of command line argument strings (unused) - * @return RETURN_SUCCESS if all tests pass, RETURN_FAILED if any test fails - */ -int main(int argc, char** argv) { - int main_return = RETURN_SUCCESS; - enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; - enum QcPerfBackendId test_backend = QC_PERF_BACKEND_DUMMY; - struct QcPerfBackendInfo* backend_info = NULL; - struct QcPerfRequest* request = NULL; - uint8_t capability_index = 0; - uint16_t streaming_rate = 0; - uint16_t sampling_rate = 0; - struct QcPerfVersionInfo version_info = {0}; - - printf("\n========================================================================\n"); - printf(" QCPerf Core Test \n"); - printf("========================================================================\n\n"); - - // Display version information - printf("[INFO] Getting QcPerf version information...\n"); - return_code = qcperf_version(&version_info); - if (QC_PERF_RETURN_CODE_SUCCESS == return_code) { - printf("[INFO] QcPerf Library Version: %d.%d.%d.%d\n", version_info.build, version_info.major, version_info.minor, version_info.patch); - - } else { - printf("[ERROR] Failed to get version information\n"); - } - printf("\n"); - if (argc == 5) { - test_backend = atoi(argv[1]); - sampling_rate = (uint16_t)atoi(argv[2]); - streaming_rate = (uint16_t)atoi(argv[3]); - - // Set verbose mode based on 4th argument (0 = false, any other value = true) - if (argv[4][0] == '0') { - g_is_verbose_print = false; - printf("[INFO] Verbose mode disabled\n"); - } else { - g_is_verbose_print = true; - printf("[INFO] Verbose mode enabled\n"); - } - - printf("[INFO] Using backend ID: %d, sampling rate: %d ms, streaming rate: %d ms\n", test_backend, sampling_rate, streaming_rate); - // ======================================================================== - // Step 1: Initialize QCPerf - // ======================================================================== - printf("[STEP 1] Initializing QCPerf library...\n"); - return_code = qcperf_init(); - if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { - printf("[ERROR] Failed to initialize QCPerf"); - print_error_info(return_code); - main_return = RETURN_FAILED; - } else { - printf("[INFO] QCPerf library initialized successfully\n\n"); - - // ======================================================================== - // Step 2: Connect to backend - // ======================================================================== - // Get backend name based on backend ID - const char* backend_name = "unknown"; - switch (test_backend) { - case QC_PERF_BACKEND_DUMMY: - backend_name = "dummy"; - break; - case QC_PERF_BACKEND_POWER: - backend_name = "power"; - break; - case QC_PERF_BACKEND_THERMAL: - backend_name = "thermal"; - break; - default: - backend_name = "unknown"; - break; - } - - printf("[STEP 2] Connecting to %s backend...\n", backend_name); - return_code = qcperf_connect_backend(test_backend, &message_callback); - if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { - printf("[ERROR] Failed to connect to backend"); - print_error_info(return_code); - main_return = RETURN_FAILED; - } else { - printf("[INFO] Backend connected successfully\n\n"); - - // ======================================================================== - // Step 3: Get backend capabilities - // ======================================================================== - printf("[STEP 3] Retrieving backend capabilities...\n"); - - // Allocate memory for backend info - backend_info = (struct QcPerfBackendInfo*)calloc(1, sizeof(struct QcPerfBackendInfo)); - if (NULL == backend_info) { - printf("[ERROR] Failed to allocate memory for backend info\n"); - main_return = RETURN_FAILED; - } else { - // Get capabilities info - return_code = qcperf_get_capabilities_info(test_backend, backend_info); - if (QC_PERF_RETURN_CODE_SUCCESS != return_code || 0 == backend_info->capabilities_list_length || NULL == backend_info->capabilities_list) { - printf("[ERROR] Failed to get backend capabilities"); - print_error_info(return_code); - main_return = RETURN_FAILED; - } else { - printf("[INFO] Retrieved %d capabilities from backend\n\n", backend_info->capabilities_list_length); - - // ======================================================================== - // Step 4: Create deep copy of backend info (if verbose mode enabled) - // ======================================================================== - if (true == g_is_verbose_print) { - printf("[STEP 4] Creating deep copy of backend info for verbose printing...\n"); - return_code = create_backend_info_copy(backend_info); - if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { - printf("[WARNING] Failed to create deep copy of backend info\n"); - main_return = RETURN_FAILED; - } else { - printf("[INFO] Backend info copied successfully\n\n"); - } - } - - // ======================================================================== - // Step 5: Register data callback - // ======================================================================== - printf("[STEP 5] Registering data callback...\n"); - return_code = qcperf_set_data_callback(test_backend, &result_callback); - if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { - printf("[ERROR] Failed to set data callback"); - print_error_info(return_code); - main_return = RETURN_FAILED; - } else { - printf("[INFO] Data callback registered successfully\n\n"); - - // ======================================================================== - // Step 6: Test each capability - // ======================================================================== - printf("[STEP 6] Testing %d capabilities...\n", backend_info->capabilities_list_length); - - // Allocate memory for request - request = (struct QcPerfRequest*)calloc(1, sizeof(struct QcPerfRequest)); - if (NULL == request) { - printf("[ERROR] Failed to allocate memory for request\n"); - main_return = RETURN_FAILED; - } else { - // Test each capability - for (capability_index = 0; capability_index < backend_info->capabilities_list_length; capability_index++) { - // Set sampling and streaming rates - if (sampling_rate != 0) { - request->sampling_rate = sampling_rate; - } else { - request->sampling_rate = backend_info->capabilities_list[capability_index].sampling_rate[0]; - } - - if (streaming_rate != 0) { - request->streaming_rate = streaming_rate; - } else { - request->streaming_rate = backend_info->capabilities_list[capability_index].streaming_rate[0]; - } - return_code = test_capability(test_backend, &backend_info->capabilities_list[capability_index], request); - - if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { - main_return = RETURN_FAILED; - } - } - printf("[INFO] Capability testing completed\n\n"); - } - } - } - } - - // ======================================================================== - // Step 7: Disconnect backend - // ======================================================================== - printf("[STEP 7] Disconnecting backend...\n"); - return_code = qcperf_disconnect_backend(test_backend); - if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { - printf("[ERROR] Failed to disconnect backend"); - print_error_info(return_code); - main_return = RETURN_FAILED; - } else { - printf("[INFO] Backend disconnected successfully\n\n"); - } - } - - // ======================================================================== - // Step 8: Deinitialize QCPerf - // ======================================================================== - printf("[STEP 8] Deinitializing QCPerf library...\n"); - return_code = qcperf_deinit(); - if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { - printf("[ERROR] Failed to deinitialize QCPerf"); - print_error_info(return_code); - main_return = RETURN_FAILED; - } else { - printf("[INFO] QCPerf library deinitialized successfully\n\n"); - } - } - // ======================================================================== - // Step 9: Clean up resources - // ======================================================================== - printf("[STEP 9] Cleaning up resources...\n"); - - if (NULL != request) { - free(request); - request = NULL; - } - - if (NULL != backend_info) { - free(backend_info); - backend_info = NULL; - } - - cleanup_backend_info(); - printf("[INFO] Resource cleanup completed\n\n"); - - // ======================================================================== - // Print final result - // ======================================================================== - printf("========================================================================\n"); - if (RETURN_SUCCESS == main_return) { - printf("[SUCCESS] Core test completed successfully\n"); - } else { - printf("[FAILURE] Core test failed\n"); - } - } else { - printf("[WARNING] Invalid arguments. Usage: %s \n", argv[0]); - } - printf("========================================================================\n\n"); - - return main_return; -} +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file qcperf_core_test.c + * @brief Test application for the QcPerf library core functionality + * @author Skand Gupta (skangupt@qti.qualcomm.com) + * + * This file implements a comprehensive test application that exercises the core + * functionality of the QcPerf library. It validates the complete workflow from + * initialization to cleanup, including backend connection, capability discovery, + * data collection, and proper resource management. + * + * The test application performs the following operations: + * 1. Library initialization with qcperf_init() + * 2. Backend connection with qcperf_connect_backend() + * 3. Capability discovery with qcperf_get_capabilities_info() + * 4. Deep copying of backend information for verbose printing + * 5. Callback registration for messages and data + * 6. Performance monitoring with qcperf_start() and qcperf_stop() + * 7. Backend disconnection with qcperf_disconnect_backend() + * 8. Library deinitialization with qcperf_deinit() + * 9. Proper cleanup of all allocated resources + * + * The test uses the dummy backend to verify the library's functionality + * without requiring actual hardware performance monitoring. This ensures + * that the core API functions correctly in a controlled environment. + */ + +#include +#include +#include +#include "qcperf.h" +#include "qcperf_common.h" + +#ifdef _WIN32 +#include // This includes winnt.h internally +#else +#include +#endif + +#if defined(QCPERF_ENABLED_QCOM_LINUX_NPU) +// For DSP NPU backend - include remote.h and define function pointers +#include "remote.h" + +// Define function pointers for remote operations that will be used by sysmonquery_stub +int (*local_remote_handle64_open)(const char* name, remote_handle64* ph) = remote_handle64_open; +int (*local_remote_handle64_close)(remote_handle64 h) = remote_handle64_close; +int (*local_remote_handle64_invoke)(remote_handle64 h, uint32_t sc, remote_arg* pra) = remote_handle64_invoke; +#endif + +/** + * @def RETURN_SUCCESS + * @brief Return code indicating successful test execution + * + * This value is returned by main() when all test operations complete successfully. + */ +#define RETURN_SUCCESS 0 + +/** + * @def RETURN_FAILED + * @brief Return code indicating test failure + * + * This value is returned by main() when any test operation fails. + */ +#define RETURN_FAILED -1 + +/** + * @brief Flag to control verbose printing of metric values + * + * When set to true, additional information about metrics will be printed, + * including metric names, descriptions, and units. This requires creating + * a deep copy of the backend information structure. + * + * When set to false, only essential information will be printed (metric IDs + * and values), which is more efficient but less informative. + */ +volatile bool g_is_verbose_print = false; + +/** + * @brief Flag to control verbose printing of error information + * + * When set to true, detailed error information will be retrieved using + * qcperf_get_error_info() and printed, including error codes and descriptive messages. + * + * When set to false, only a newline will be printed after error messages, + * resulting in more concise output but less diagnostic information. + */ +bool g_is_error_verbose = true; + +volatile struct QcPerfBackendInfo* g_backend_info = NULL; + +/** + * @brief Print a metric value based on its data type + * + * This function prints a metric value from a QcPerfGenericType structure + * to stdout, formatting the output based on the data type. It handles all + * supported data types (boolean, integer, floating-point, and string values) + * with appropriate formatting for each type. + * + * @param[in] metric_value Pointer to the QcPerfGenericType structure containing the value + * + * @note If metric_value is NULL, "NULL" will be printed. + * @note For string values, if the string pointer is NULL, "(null)" will be printed. + * @note For unknown data types, "Unknown type X" will be printed, where X is the data type value. + */ +void print_metric_value(const struct QcPerfGenericType* metric_value) { + if (NULL == metric_value) { + printf("NULL\n"); + } else { + switch (metric_value->data_type) { + case QC_PERF_DATA_TYPE_BOOL: + if (metric_value->bool_value) { + printf("true"); + } else { + printf("false"); + } + break; + case QC_PERF_DATA_TYPE_UINT64: + printf("%llu", (unsigned long long)metric_value->uint64_value); + break; + case QC_PERF_DATA_TYPE_INT64: + printf("%lld", (long long)metric_value->int64_value); + break; + case QC_PERF_DATA_TYPE_DOUBLE: + printf("%f", metric_value->double_value); + break; + case QC_PERF_DATA_TYPE_STRING: + if (NULL != metric_value->string_value) { + printf("%.*s", (int)metric_value->string_value_len, (char*)metric_value->string_value); + } else { + printf("(null)"); + } + break; + default: + printf("Unknown type %d", metric_value->data_type); + break; + } + } +} + +/** + * @brief Print detailed error information for a return code + * + * This function retrieves and prints detailed error information for a given + * return code using qcperf_get_error_info(). The verbosity of the output + * is controlled by the g_is_error_verbose flag. + * + * @param[in] return_code The return code to get information for + * + * @note If g_is_error_verbose is true, detailed error information will be printed. + * @note If g_is_error_verbose is false, only a newline will be printed. + * + * @see qcperf_get_error_info() + * @see g_is_error_verbose + */ +void print_error_info(enum QcPerfReturnCode return_code) { + struct QcPerfReturnCodeInfo info = {0}; + if (g_is_error_verbose) { + qcperf_get_error_info(return_code, &info); + printf("[ERROR] %s (code: %d)\n", info.info_str, return_code); + } else { + printf("\n"); + } +} + +/** + * @brief Message callback function for receiving messages from the backend + * + * This function is registered with the QcPerf library using qcperf_set_message_callback() + * to receive informational, warning, and error messages from the backend. + * It validates the message pointer and prints the message level and content to stdout. + * + * @param[in] message Pointer to the QcPerfMessage structure containing: + * - message: The message text + * - message_length: Length of the message in bytes + * - message_level: Severity level (debug, info, warning, error) + * + * @return QC_PERF_RETURN_CODE_SUCCESS if the message was processed successfully + * @return QC_PERF_RETURN_CODE_FAILED if the message pointer is NULL or the message text is NULL + * + * @see qcperf_set_message_callback() + * @see struct QcPerfMessage + */ +enum QcPerfReturnCode message_callback(struct QcPerfMessage* message) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; + const char* level_str = "UNKNOWN"; + + if (NULL == message || NULL == message->message) { + printf("[ERROR] Message callback received NULL message\n"); + return_code = QC_PERF_RETURN_CODE_FAILED; + } else { + // Convert message level to human-readable string + switch (message->message_level) { + case QC_PERF_MESSAGE_LEVEL_DEBUG: + level_str = "DEBUG"; + break; + case QC_PERF_MESSAGE_LEVEL_INFO: + level_str = "INFO"; + break; + case QC_PERF_MESSAGE_LEVEL_WARNING: + level_str = "WARNING"; + break; + case QC_PERF_MESSAGE_LEVEL_ERROR: + level_str = "ERROR"; + break; + default: + level_str = "UNKNOWN"; + break; + } + if (message->message_level != QC_PERF_MESSAGE_LEVEL_DEBUG) { + printf("[%s] Backend message: %s\n", level_str, message->message); + } + + return_code = QC_PERF_RETURN_CODE_SUCCESS; + } + return return_code; +} + +/** + * @brief Callback function for receiving performance data from the backend + * + * This function is registered with the QcPerf library using qcperf_set_data_callback() + * to receive performance metric data from the backend. It validates the data pointer + * and prints the capability ID, number of metrics, and metric values to stdout. + * + * The function supports two output modes: + * 1. Verbose mode: Prints metric names, descriptions, and units (requires g_backend_info) + * 2. Basic mode: Prints only metric IDs and values + * + * @param[in] data Pointer to the QcPerfData structure containing: + * - capabilityId: The capability that generated the data + * - metric_response: Array of metric responses + * - metric_response_len: Number of metrics in the array + * + * @return QC_PERF_RETURN_CODE_SUCCESS if the data was processed successfully + * @return QC_PERF_RETURN_CODE_FAILED if the data pointer is NULL or invalid + * + * @see qcperf_set_data_callback() + * @see struct QcPerfData + * @see g_is_verbose_print + * @see print_metric_value() + */ +enum QcPerfReturnCode result_callback(struct QcPerfData* data) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; + bool metric_found = false; + const char* metric_name = NULL; + const char* metric_unit = NULL; + const char* metric_desc = NULL; + if (NULL == data) { + printf("[ERROR] Data callback received NULL data\n"); + return_code = QC_PERF_RETURN_CODE_FAILED; + } else { + printf("[DATA] Capability ID: %d, Metrics count: %d\n", data->capabilityId, data->metric_response_len); + + if (NULL != data->metric_response) { + for (uint32_t metric_index = 0; metric_index < data->metric_response_len; metric_index++) { + // Check if we can use verbose printing mode + if (g_is_verbose_print && NULL != g_backend_info && NULL != g_backend_info->capabilities_list && data->capabilityId < g_backend_info->capabilities_list_length && + NULL != g_backend_info->capabilities_list[data->capabilityId].metric_ids_list) { + // Search for the metric by ID (don't use metric_id as array index) + for (uint32_t i = 0; i < g_backend_info->capabilities_list[data->capabilityId].metric_ids_list_len; i++) { + if (g_backend_info->capabilities_list[data->capabilityId].metric_ids_list[i].metric_id == data->metric_response[metric_index].metric_id) { + metric_name = g_backend_info->capabilities_list[data->capabilityId].metric_ids_list[i].metric_name; + metric_unit = g_backend_info->capabilities_list[data->capabilityId].metric_ids_list[i].metric_unit; + metric_desc = g_backend_info->capabilities_list[data->capabilityId].metric_ids_list[i].metric_description; + metric_found = true; + break; + } + } + + if (true == metric_found) { + // Verbose mode - print metric name, value, unit and description + printf(" [%llu] %s: ", (unsigned long long)data->metric_response[metric_index].timestamp, metric_name); + print_metric_value(&data->metric_response[metric_index].metric_value); + printf(" %s (%s)\n", metric_unit, metric_desc); + } else { + // Metric not found in list - print only metric ID and value + printf(" [%llu] Metric ID %d: ", (unsigned long long)data->metric_response[metric_index].timestamp, data->metric_response[metric_index].metric_id); + print_metric_value(&data->metric_response[metric_index].metric_value); + printf("\n"); + } + } else { + // Basic mode - print only metric ID and value + printf(" [%llu] Metric ID %d: ", (unsigned long long)data->metric_response[metric_index].timestamp, data->metric_response[metric_index].metric_id); + print_metric_value(&data->metric_response[metric_index].metric_value); + printf("\n"); + } + } + return_code = QC_PERF_RETURN_CODE_SUCCESS; + } + } + return return_code; +} + +/** + * @brief Main entry point for the QcPerf core test application + * + * This function performs a comprehensive test of the QcPerf library's core functionality, + * exercising the complete workflow from initialization to cleanup. It tests: + * + * 1. Library initialization with qcperf_init() + * 2. Backend connection with qcperf_connect_backend() + * 3. Capability discovery with qcperf_get_capabilities_info() + * 4. Deep copying of backend information (when verbose printing is enabled) + * 5. Message callback registration with qcperf_set_message_callback() + * 6. Data callback registration with qcperf_set_data_callback() + * 7. Performance monitoring with qcperf_start() and qcperf_stop() + * 8. Backend disconnection with qcperf_disconnect_backend() + * 9. Library deinitialization with qcperf_deinit() + * 10. Proper cleanup of all allocated resources + * + * The function includes comprehensive error handling and resource management, + * ensuring that all allocated memory is properly freed even in error cases. + * + * @param[in] argc Number of command line arguments (unused) + * @param[in] argv Array of command line argument strings (unused) + * + * @return RETURN_SUCCESS (0) if all tests pass + * @return RETURN_FAILED (-1) if any test fails + * + * @see qcperf_init() + * @see qcperf_connect_backend() + * @see qcperf_get_capabilities_info() + * @see qcperf_set_message_callback() + * @see qcperf_set_data_callback() + * @see qcperf_start() + * @see qcperf_stop() + * @see qcperf_disconnect_backend() + * @see qcperf_deinit() + */ +/** + * @brief Create a deep copy of backend info for verbose printing + * + * This function creates a deep copy of the backend information structure, + * including all nested capability and metric information. If any allocation + * fails during the copy process, all previously allocated memory is properly + * cleaned up before returning an error code. + * + * @param[in] backend_info Source backend info structure to copy + * @return QC_PERF_RETURN_CODE_SUCCESS if successful + * @return QC_PERF_RETURN_CODE_INVALID_ARGUMENTS if backend_info is NULL + * @return QC_PERF_RETURN_CODE_CALLOC_FAILED if memory allocation fails + * + * @note On failure, g_backend_info is set to NULL and g_is_verbose_print is set to false + * @note All allocated memory is freed on failure to prevent memory leaks + */ +static enum QcPerfReturnCode create_backend_info_copy(const struct QcPerfBackendInfo* backend_info) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; + uint8_t capability_itr = 0; + uint8_t metric_id_itr = 0; + + if (NULL == backend_info) { + return_code = QC_PERF_RETURN_CODE_INVALID_ARGUMENTS; + } else { + // Allocate memory for global backend info + g_backend_info = (struct QcPerfBackendInfo*)calloc(1, sizeof(struct QcPerfBackendInfo)); + if (NULL == g_backend_info) { + printf("Failed to allocate memory for global backend info, disabling verbose print\n"); + g_is_verbose_print = false; + return_code = QC_PERF_RETURN_CODE_CALLOC_FAILED; + } else { + // Copy basic fields + g_backend_info->backend_id = backend_info->backend_id; + g_backend_info->capabilities_list_length = backend_info->capabilities_list_length; + + // Allocate memory for capabilities list + g_backend_info->capabilities_list = (struct QcPerfCapabilityInfo*)calloc(backend_info->capabilities_list_length, sizeof(struct QcPerfCapabilityInfo)); + + if (NULL == g_backend_info->capabilities_list) { + printf("Failed to allocate memory for capabilities list, disabling verbose print\n"); + g_is_verbose_print = false; + free((void*)g_backend_info); + g_backend_info = NULL; + return_code = QC_PERF_RETURN_CODE_CALLOC_FAILED; + } else { + // Copy each capability + for (capability_itr = 0; capability_itr < backend_info->capabilities_list_length; capability_itr++) { + // Copy capability structure + memcpy(&g_backend_info->capabilities_list[capability_itr], &backend_info->capabilities_list[capability_itr], sizeof(struct QcPerfCapabilityInfo)); + + // Allocate memory for metric_ids_list + g_backend_info->capabilities_list[capability_itr].metric_ids_list = + (struct QcPerfMetricInfo*)calloc(backend_info->capabilities_list[capability_itr].metric_ids_list_len, sizeof(struct QcPerfMetricInfo)); + + if (NULL == g_backend_info->capabilities_list[capability_itr].metric_ids_list) { + printf("Failed to allocate memory for metric IDs list, disabling verbose print\n"); + g_is_verbose_print = false; + return_code = QC_PERF_RETURN_CODE_CALLOC_FAILED; + // Clean up previously allocated metric_ids_list arrays + for (uint8_t cleanup_itr = 0; cleanup_itr < capability_itr; cleanup_itr++) { + if (NULL != g_backend_info->capabilities_list[cleanup_itr].metric_ids_list) { + free(g_backend_info->capabilities_list[cleanup_itr].metric_ids_list); + g_backend_info->capabilities_list[cleanup_itr].metric_ids_list = NULL; + } + } + free(g_backend_info->capabilities_list); + g_backend_info->capabilities_list = NULL; + free((void*)g_backend_info); + g_backend_info = NULL; + } else { + // Copy each metric + for (metric_id_itr = 0; metric_id_itr < g_backend_info->capabilities_list[capability_itr].metric_ids_list_len; metric_id_itr++) { + memcpy(&g_backend_info->capabilities_list[capability_itr].metric_ids_list[metric_id_itr], &backend_info->capabilities_list[capability_itr].metric_ids_list[metric_id_itr], + sizeof(struct QcPerfMetricInfo)); + } + } + } + } + } + } + return return_code; +} + +/** + * @brief Clean up the global backend info structure + */ +static void cleanup_backend_info(void) { + uint8_t capability_itr = 0; + + if (NULL == g_backend_info) { + return; + } + + if (NULL != g_backend_info->capabilities_list) { + for (capability_itr = 0; capability_itr < g_backend_info->capabilities_list_length; capability_itr++) { + if (NULL != g_backend_info->capabilities_list[capability_itr].metric_ids_list) { + free(g_backend_info->capabilities_list[capability_itr].metric_ids_list); + g_backend_info->capabilities_list[capability_itr].metric_ids_list = NULL; + } + } + free(g_backend_info->capabilities_list); + g_backend_info->capabilities_list = NULL; + } + + free((void*)g_backend_info); + g_backend_info = NULL; +} + +/** + * @brief Test a specific capability + * + * @param[in] test_backend Backend ID to test + * @param[in] capability_info Pointer to capability information + * @param[in] request Pointer to request structure to use + * @return QC_PERF_RETURN_CODE_SUCCESS if successful, error code otherwise + */ +static enum QcPerfReturnCode test_capability(enum QcPerfBackendId test_backend, const struct QcPerfCapabilityInfo* capability_info, struct QcPerfRequest* request) { + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_SUCCESS; + + if (NULL == capability_info || NULL == request) { + printf("[ERROR] Invalid parameters for capability test\n"); + return_code = QC_PERF_RETURN_CODE_FAILED; + } else { + printf("\n========================================================================\n"); + printf("[TEST] Testing capability ID: %d", capability_info->capability_id); + + if (g_is_verbose_print) { + printf(" (%s)", capability_info->capability_name); + } + printf("\n"); + + // Configure request with capability's recommended settings + request->capability_id = capability_info->capability_id; + + printf("[INFO] Using sampling rate: %d ms, streaming rate: %d ms\n", request->sampling_rate, request->streaming_rate); + + // Start profiling + printf("[INFO] Starting profiling...\n"); + return_code = qcperf_start(test_backend, request); + if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { + printf("[ERROR] Failed to start profiling"); + print_error_info(return_code); + } else { + printf("[INFO] Profiling started successfully\n"); + + // Wait for data collection +#ifdef _WIN32 + printf("[INFO] Collecting data for 10 seconds...\n"); + Sleep(10000); // Wait for 10 seconds to allow profiling to run +#else + printf("[INFO] Collecting data for 10 seconds...\n"); + sleep(10); // Wait for 10 seconds to allow profiling to run +#endif + + // Stop profiling + printf("[INFO] Stopping profiling...\n"); + return_code = qcperf_stop(test_backend, request); + if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { + printf("[ERROR] Failed to stop profiling"); + print_error_info(return_code); + } else { + printf("[INFO] Profiling stopped successfully\n"); + } + } + + printf("========================================================================\n"); + } + return return_code; +} + +/** + * @brief Main entry point for the QcPerf core test application + * + * @param[in] argc Number of command line arguments (unused) + * @param[in] argv Array of command line argument strings (unused) + * @return RETURN_SUCCESS if all tests pass, RETURN_FAILED if any test fails + */ +int main(int argc, char** argv) { + int main_return = RETURN_SUCCESS; + enum QcPerfReturnCode return_code = QC_PERF_RETURN_CODE_FAILED; + enum QcPerfBackendId test_backend = QC_PERF_BACKEND_DUMMY; + struct QcPerfBackendInfo* backend_info = NULL; + struct QcPerfRequest* request = NULL; + uint8_t capability_index = 0; + uint16_t streaming_rate = 0; + uint16_t sampling_rate = 0; + struct QcPerfVersionInfo version_info = {0}; + + printf("\n========================================================================\n"); + printf(" QCPerf Core Test \n"); + printf("========================================================================\n\n"); + + // Display version information + printf("[INFO] Getting QcPerf version information...\n"); + return_code = qcperf_version(&version_info); + if (QC_PERF_RETURN_CODE_SUCCESS == return_code) { + printf("[INFO] QcPerf Library Version: %d.%d.%d.%d\n", version_info.build, version_info.major, version_info.minor, version_info.patch); + + } else { + printf("[ERROR] Failed to get version information\n"); + } + printf("\n"); + if (argc == 5) { + test_backend = atoi(argv[1]); + sampling_rate = (uint16_t)atoi(argv[2]); + streaming_rate = (uint16_t)atoi(argv[3]); + + // Set verbose mode based on 4th argument (0 = false, any other value = true) + if (argv[4][0] == '0') { + g_is_verbose_print = false; + printf("[INFO] Verbose mode disabled\n"); + } else { + g_is_verbose_print = true; + printf("[INFO] Verbose mode enabled\n"); + } + + printf("[INFO] Using backend ID: %d, sampling rate: %d ms, streaming rate: %d ms\n", test_backend, sampling_rate, streaming_rate); + // ======================================================================== + // Step 1: Initialize QCPerf + // ======================================================================== + printf("[STEP 1] Initializing QCPerf library...\n"); + return_code = qcperf_init(); + if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { + printf("[ERROR] Failed to initialize QCPerf"); + print_error_info(return_code); + main_return = RETURN_FAILED; + } else { + printf("[INFO] QCPerf library initialized successfully\n\n"); + + // ======================================================================== + // Step 2: Connect to backend + // ======================================================================== + // Get backend name based on backend ID + const char* backend_name = "unknown"; + switch (test_backend) { +#if defined(QCPERF_ENABLED_DUMMY) + case QC_PERF_BACKEND_DUMMY: + backend_name = "dummy"; + break; +#endif +#if defined(QCPERF_ENABLED_QCOM_LINUX_CPU) + case QC_PERF_BACKEND_QCOM_LINUX_CPU: + backend_name = "cpu"; + break; +#endif +#if defined(QCPERF_ENABLED_QCOM_LINUX_NPU) + case QC_PERF_BACKEND_DSP_NPU: + backend_name = "npu"; + break; +#endif +#if defined(QCPERF_ENABLED_WOS_POWER) + case QC_PERF_BACKEND_POWER: + backend_name = "power"; + break; +#endif +#if defined(QCPERF_ENABLED_WOS_THERMAL) + case QC_PERF_BACKEND_THERMAL: + backend_name = "thermal"; + break; +#endif + default: + backend_name = "unknown"; + break; + } + + printf("[STEP 2] Connecting to %s backend...\n", backend_name); + return_code = qcperf_connect_backend(test_backend, &message_callback); + if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { + printf("[ERROR] Failed to connect to backend"); + print_error_info(return_code); + main_return = RETURN_FAILED; + } else { + printf("[INFO] Backend connected successfully\n\n"); + + // ======================================================================== + // Step 3: Get backend capabilities + // ======================================================================== + printf("[STEP 3] Retrieving backend capabilities...\n"); + + // Allocate memory for backend info + backend_info = (struct QcPerfBackendInfo*)calloc(1, sizeof(struct QcPerfBackendInfo)); + if (NULL == backend_info) { + printf("[ERROR] Failed to allocate memory for backend info\n"); + main_return = RETURN_FAILED; + } else { + // Get capabilities info + return_code = qcperf_get_capabilities_info(test_backend, backend_info); + if (QC_PERF_RETURN_CODE_SUCCESS != return_code || 0 == backend_info->capabilities_list_length || NULL == backend_info->capabilities_list) { + printf("[ERROR] Failed to get backend capabilities"); + print_error_info(return_code); + main_return = RETURN_FAILED; + } else { + printf("[INFO] Retrieved %d capabilities from backend\n\n", backend_info->capabilities_list_length); + + // ======================================================================== + // Step 4: Create deep copy of backend info (if verbose mode enabled) + // ======================================================================== + if (true == g_is_verbose_print) { + printf("[STEP 4] Creating deep copy of backend info for verbose printing...\n"); + return_code = create_backend_info_copy(backend_info); + if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { + printf("[WARNING] Failed to create deep copy of backend info\n"); + main_return = RETURN_FAILED; + } else { + printf("[INFO] Backend info copied successfully\n\n"); + } + } + + // ======================================================================== + // Step 5: Register data callback + // ======================================================================== + printf("[STEP 5] Registering data callback...\n"); + return_code = qcperf_set_data_callback(test_backend, &result_callback); + if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { + printf("[ERROR] Failed to set data callback"); + print_error_info(return_code); + main_return = RETURN_FAILED; + } else { + printf("[INFO] Data callback registered successfully\n\n"); + + // ======================================================================== + // Step 6: Test each capability + // ======================================================================== + printf("[STEP 6] Testing %d capabilities...\n", backend_info->capabilities_list_length); + + // Allocate memory for request + request = (struct QcPerfRequest*)calloc(1, sizeof(struct QcPerfRequest)); + if (NULL == request) { + printf("[ERROR] Failed to allocate memory for request\n"); + main_return = RETURN_FAILED; + } else { + // Test each capability + for (capability_index = 0; capability_index < backend_info->capabilities_list_length; capability_index++) { + // Set sampling and streaming rates + if (sampling_rate != 0) { + request->sampling_rate = sampling_rate; + } else { + request->sampling_rate = backend_info->capabilities_list[capability_index].sampling_rate[0]; + } + + if (streaming_rate != 0) { + request->streaming_rate = streaming_rate; + } else { + request->streaming_rate = backend_info->capabilities_list[capability_index].streaming_rate[0]; + } + return_code = test_capability(test_backend, &backend_info->capabilities_list[capability_index], request); + + if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { + main_return = RETURN_FAILED; + } + } + printf("[INFO] Capability testing completed\n\n"); + } + } + } + } + + // ======================================================================== + // Step 7: Disconnect backend + // ======================================================================== + printf("[STEP 7] Disconnecting backend...\n"); + return_code = qcperf_disconnect_backend(test_backend); + if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { + printf("[ERROR] Failed to disconnect backend"); + print_error_info(return_code); + main_return = RETURN_FAILED; + } else { + printf("[INFO] Backend disconnected successfully\n\n"); + } + } + + // ======================================================================== + // Step 8: Deinitialize QCPerf + // ======================================================================== + printf("[STEP 8] Deinitializing QCPerf library...\n"); + return_code = qcperf_deinit(); + if (QC_PERF_RETURN_CODE_SUCCESS != return_code) { + printf("[ERROR] Failed to deinitialize QCPerf"); + print_error_info(return_code); + main_return = RETURN_FAILED; + } else { + printf("[INFO] QCPerf library deinitialized successfully\n\n"); + } + } + // ======================================================================== + // Step 9: Clean up resources + // ======================================================================== + printf("[STEP 9] Cleaning up resources...\n"); + + if (NULL != request) { + free(request); + request = NULL; + } + + if (NULL != backend_info) { + free(backend_info); + backend_info = NULL; + } + + cleanup_backend_info(); + printf("[INFO] Resource cleanup completed\n\n"); + + // ======================================================================== + // Print final result + // ======================================================================== + printf("========================================================================\n"); + if (RETURN_SUCCESS == main_return) { + printf("[SUCCESS] Core test completed successfully\n"); + } else { + printf("[FAILURE] Core test failed\n"); + } + } else { + printf("[WARNING] Invalid arguments. Usage: %s \n", argv[0]); + } + printf("========================================================================\n\n"); + + return main_return; +} diff --git a/qcperf/utils/qcondition-variable/CMakeLists.txt b/qcperf/utils/qcondition-variable/CMakeLists.txt index 1f5c25e..efa3cc6 100644 --- a/qcperf/utils/qcondition-variable/CMakeLists.txt +++ b/qcperf/utils/qcondition-variable/CMakeLists.txt @@ -5,15 +5,21 @@ cmake_minimum_required(VERSION 3.13.5) if(QCPERF_OS_WINDOWS) add_library(QcPerfQCv STATIC - src/windows/qcv.c + src/windows/QCv.c ) else() add_library(QcPerfQCv STATIC - src/linux/qcv.c + src/linux/QCv.c + ) + target_link_libraries(QcPerfQCv PUBLIC + QcPerfQTime + ) + target_include_directories(QcPerfQCv PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/utils/qtime/inc ) endif() -# Include public headers + target_include_directories(QcPerfQCv PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/inc ) diff --git a/qcperf/utils/qcondition-variable/inc/QCv.h b/qcperf/utils/qcondition-variable/inc/QCv.h index f8bbffa..af16a08 100644 --- a/qcperf/utils/qcondition-variable/inc/QCv.h +++ b/qcperf/utils/qcondition-variable/inc/QCv.h @@ -46,6 +46,8 @@ */ #define CV_NAME_SIZE 128 +#define MS_SECOND_MULTIPLIER 1000U + /** * @brief Return codes for condition variable operations */ @@ -67,7 +69,9 @@ enum QCvReturnCode { RETURN_CODE_CV_DESTROY_SUCCESS, /**< Condition variable destruction successful */ RETURN_CODE_CV_INVALID_HANDLE, /**< Invalid condition variable handle */ RETURN_CODE_CV_MUTEX_INVALID_HANDLE, /**< Invalid mutex handle */ - RETURN_CODE_CV_MUTEX_MEMORY_CALLOC_FAILED /**< Mutex memory allocation failed */ + RETURN_CODE_CV_MUTEX_MEMORY_CALLOC_FAILED, /**< Mutex memory allocation failed */ + RETURN_CODE_CV_COND_DESTROY_FAILED, /**< Thread conditional variable destroy failed */ + RETURN_CODE_CV_MUTEX_DESTROY_FAILED /**< Mutex destroy failed */ }; /** diff --git a/qcperf/utils/qcondition-variable/src/linux/QCv.c b/qcperf/utils/qcondition-variable/src/linux/QCv.c index 6aa7e58..a07ed2e 100644 --- a/qcperf/utils/qcondition-variable/src/linux/QCv.c +++ b/qcperf/utils/qcondition-variable/src/linux/QCv.c @@ -43,8 +43,8 @@ * functionality required by the qcv interface. */ -#include "qcv.h" -#include "Qtimer.h" +#include "QCv.h" +#include "qtime.h" #include enum QCvReturnCode cv_create(const struct CvAttributes* cv_request, struct CvInfo* cv_info) { @@ -58,20 +58,16 @@ enum QCvReturnCode cv_create(const struct CvAttributes* cv_request, struct CvInf p_thread_mutex = calloc(1, sizeof(pthread_mutex_t)); if (p_thread_cond == NULL) { return_code = RETURN_CODE_CV_MUTEX_MEMORY_CALLOC_FAILED; - printf("Linux ConditionVariable memory allocation failed"); } else if (p_thread_mutex == NULL) { return_code = RETURN_CODE_CV_MUTEX_MEMORY_CALLOC_FAILED; - printf("Linux Mutex memory allocation failed"); } else { return_signal_code = pthread_cond_init(p_thread_cond, NULL); if (return_signal_code != 0) { return_code = RETURN_CODE_CV_CREATE_FAILED; - printf("Linux pthread_cond_init API error: %d\n", return_signal_code); } else { return_signal_code = pthread_mutex_init(p_thread_mutex, NULL); if (return_signal_code != 0) { return_code = RETURN_CODE_CV_CREATE_FAILED; - printf("Linux pthread_mutex_init API error: %d\n", return_signal_code); } else { cv_info->p_cv_handle = (void*)p_thread_cond; cv_info->p_mutex_handle = (void*)p_thread_mutex; @@ -111,7 +107,6 @@ enum QCvReturnCode cv_wait(const struct CvInfo* cv_info) { return_signal_code = pthread_cond_wait(p_thread_cond, p_thread_mutex); pthread_mutex_unlock(p_thread_mutex); if (return_signal_code != 0) { - printf("Linux pthread_cond_wait API error: %d\n", return_signal_code); return_code = RETURN_CODE_CV_WAIT_FAILED; } else { return_code = RETURN_CODE_CV_WAIT_COMPLETED; @@ -141,7 +136,6 @@ enum QCvReturnCode cv_wait_for(const struct CvInfo* cv_info, uint32_t timeout) { return_signal_code = pthread_cond_timedwait(p_thread_cond, p_thread_mutex, &tm_spec); pthread_mutex_unlock(p_thread_mutex); if (return_signal_code != 0) { - printf("Linux pthread_cond_timedwait API error: %d\n", return_signal_code); return_code = RETURN_CODE_CV_WAIT_FAILED; } else { return_code = RETURN_CODE_CV_WAIT_COMPLETED; @@ -167,7 +161,6 @@ enum QCvReturnCode cv_notify(const struct CvInfo* cv_info) { return_signal_code = pthread_cond_signal(p_thread_cond); pthread_mutex_unlock(p_thread_mutex); if (return_signal_code != 0) { - printf("Linux pthread_cond_signal API error: %d\n", return_signal_code); return_code = RETURN_CODE_CV_NOTIFY_FAILED; } else { return_code = RETURN_CODE_CV_NOTIFY_SUCCESS; @@ -193,7 +186,6 @@ enum QCvReturnCode cv_notifyAll(const struct CvInfo* cv_info) { return_signal_code = pthread_cond_broadcast(p_thread_cond); pthread_mutex_unlock(p_thread_mutex); if (return_signal_code != 0) { - printf("Linux pthread_cond_broadcast API error: %d\n", return_signal_code); return_code = RETURN_CODE_CV_NOTIFY_ALL_FAILED; } else { return_code = RETURN_CODE_CV_NOTIFY_ALL_SUCCESS; @@ -217,11 +209,11 @@ enum QCvReturnCode cv_destroy(struct CvInfo* cv_info) { p_thread_mutex = (pthread_mutex_t*)cv_info->p_mutex_handle; return_signal_code = pthread_cond_destroy(p_thread_cond); if (return_signal_code != 0) { - printf("Linux pthread_cond_destroy API error: %d\n", return_signal_code); + return_code = RETURN_CODE_CV_COND_DESTROY_FAILED; } return_signal_code = pthread_mutex_destroy(p_thread_mutex); if (return_signal_code != 0) { - printf("Linux pthread_mutex_destroy API error: %d\n", return_signal_code); + return_code = RETURN_CODE_CV_MUTEX_DESTROY_FAILED; } free(cv_info->p_mutex_handle); cv_info->p_mutex_handle = NULL; diff --git a/qcperf/utils/qcondition-variable/src/windows/QCv.c b/qcperf/utils/qcondition-variable/src/windows/QCv.c index 0e9e09d..073e505 100644 --- a/qcperf/utils/qcondition-variable/src/windows/QCv.c +++ b/qcperf/utils/qcondition-variable/src/windows/QCv.c @@ -42,7 +42,7 @@ * to provide the functionality required by the qcv interface. */ -#include "qcv.h" +#include "QCv.h" #include enum QCvReturnCode cv_create(const struct CvAttributes* cv_request, struct CvInfo* cv_info) { @@ -105,7 +105,6 @@ enum QCvReturnCode cv_wait(const struct CvInfo* cv_info) { LeaveCriticalSection(p_mutex_handle); if (0 == return_signal_code) { - printf("Windows SleepConditionVariableCS API error: %d\n", GetLastError()); return_code = RETURN_CODE_CV_WAIT_FAILED; } else { return_code = RETURN_CODE_CV_WAIT_COMPLETED; diff --git a/qcperf/utils/qlist/CMakeLists.txt b/qcperf/utils/qlist/CMakeLists.txt index 1bebfe3..e022998 100644 --- a/qcperf/utils/qlist/CMakeLists.txt +++ b/qcperf/utils/qlist/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.13.5) add_library(QcPerfqlist STATIC - src/qlist.c + src/QList.c ) # Link with qmutex library for thread safety diff --git a/qcperf/utils/qlist/inc/QList.h b/qcperf/utils/qlist/inc/QList.h index f026972..2b61818 100644 --- a/qcperf/utils/qlist/inc/QList.h +++ b/qcperf/utils/qlist/inc/QList.h @@ -42,7 +42,7 @@ #include #include -#include "qmutex.h" +#include "QMutex.h" /** * @brief Return codes for list operations diff --git a/qcperf/utils/qlist/src/QList.c b/qcperf/utils/qlist/src/QList.c index 971a919..f3e1862 100644 --- a/qcperf/utils/qlist/src/QList.c +++ b/qcperf/utils/qlist/src/QList.c @@ -42,7 +42,7 @@ * error handling and validation to ensure robust operation. */ -#include "qlist.h" +#include "QList.h" enum QListReturnCode list_create(struct List** pp_list, const char mutex_name[]) { enum QListReturnCode return_code = RETURN_CODE_LIST_SUCCESS; diff --git a/qcperf/utils/qmutex/CMakeLists.txt b/qcperf/utils/qmutex/CMakeLists.txt index 2c98f00..9a9bb9e 100644 --- a/qcperf/utils/qmutex/CMakeLists.txt +++ b/qcperf/utils/qmutex/CMakeLists.txt @@ -5,11 +5,11 @@ cmake_minimum_required(VERSION 3.13.5) if(QCPERF_OS_WINDOWS) add_library(QcPerfQMutex STATIC - src/windows/qmutex.c + src/windows/QMutex.c ) else() add_library(QcPerfQMutex STATIC - src/linux/qmutex.c + src/linux/QMutex.c ) endif() diff --git a/qcperf/utils/qmutex/src/linux/QMutex.c b/qcperf/utils/qmutex/src/linux/QMutex.c index 67cf7c7..02a9749 100644 --- a/qcperf/utils/qmutex/src/linux/QMutex.c +++ b/qcperf/utils/qmutex/src/linux/QMutex.c @@ -42,7 +42,7 @@ * provide the functionality required by the qmutex interface. */ -#include "qmutex.h" +#include "QMutex.h" #include enum QMutexReturnCode mutex_create(const struct MutexAttributes* mutex_request, struct MutexInfo* mutex_info) { @@ -53,10 +53,9 @@ enum QMutexReturnCode mutex_create(const struct MutexAttributes* mutex_request, pthread_mutex_t* lock = (pthread_mutex_t*)calloc(1, sizeof(pthread_mutex_t)); if (lock == NULL) { return_code = RETURN_CODE_MUTEX_NULL_POINTER; - printf("Unable to create mutex.\n"); } else { mutex_info->p_mutex_handle = (void*)lock; - uint16_t return_init = pthread_mutex_init(mutex_info->p_mutex_handle, NULL); + uint16_t return_init = (uint16_t)pthread_mutex_init(mutex_info->p_mutex_handle, NULL); if (return_init == 0) { return_code = RETURN_CODE_MUTEX_CREATE_SUCCESS; } @@ -80,11 +79,10 @@ enum QMutexReturnCode mutex_lock(const struct MutexInfo* mutex_info) { return_code = RETURN_CODE_MUTEX_NULL_POINTER; } else { pthread_mutex_t* lock = (pthread_mutex_t*)mutex_info->p_mutex_handle; - uint32_t return_lock = pthread_mutex_lock(lock); + uint32_t return_lock = (uint32_t)pthread_mutex_lock(lock); if (return_lock == 0) { return_code = RETURN_CODE_MUTEX_LOCK_SUCCESS; } else { - printf("Mutex lock failed.\n"); return_code = RETURN_CODE_MUTEX_LOCK_FAILED; } } @@ -97,11 +95,10 @@ enum QMutexReturnCode mutex_unlock(const struct MutexInfo* mutex_info) { return_code = RETURN_CODE_MUTEX_NULL_POINTER; } else { pthread_mutex_t* lock = (pthread_mutex_t*)mutex_info->p_mutex_handle; - uint32_t return_lock = pthread_mutex_unlock(lock); + uint32_t return_lock = (uint32_t)pthread_mutex_unlock(lock); if (return_lock == 0) { return_code = RETURN_CODE_MUTEX_UNLOCK_SUCCESS; } else { - printf("Mutex unlock failed.\n"); return_code = RETURN_CODE_MUTEX_UNLOCK_FAILED; } } @@ -114,11 +111,10 @@ enum QMutexReturnCode mutex_destroy(struct MutexInfo* mutex_info) { return_code = RETURN_CODE_MUTEX_NULL_POINTER; } else { pthread_mutex_t* lock = (pthread_mutex_t*)mutex_info->p_mutex_handle; - uint32_t return_lock = pthread_mutex_destroy(lock); + uint32_t return_lock = (uint32_t)pthread_mutex_destroy(lock); if (return_lock == 0) { return_code = RETURN_CODE_MUTEX_DESTROY_SUCCESS; } else { - printf("Mutex destroy failed.\n"); return_code = RETURN_CODE_MUTEX_DESTROY_FAILED; } free(lock); diff --git a/qcperf/utils/qmutex/src/windows/QMutex.c b/qcperf/utils/qmutex/src/windows/QMutex.c index d4717e5..e54d8c3 100644 --- a/qcperf/utils/qmutex/src/windows/QMutex.c +++ b/qcperf/utils/qmutex/src/windows/QMutex.c @@ -41,7 +41,7 @@ * ReleaseMutex, and CloseHandle to provide the functionality required by the qmutex interface. */ -#include "qmutex.h" +#include "QMutex.h" #include enum QMutexReturnCode mutex_create(const struct MutexAttributes* mutex_request, struct MutexInfo* mutex_info) { diff --git a/qcperf/utils/qsleep/CMakeLists.txt b/qcperf/utils/qsleep/CMakeLists.txt index 014a00b..888686c 100644 --- a/qcperf/utils/qsleep/CMakeLists.txt +++ b/qcperf/utils/qsleep/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.13.5) add_library(QcPerfQSleep STATIC - src/qsleep.c + src/QSleep.c ) # Include public headers diff --git a/qcperf/utils/qsleep/src/QSleep.c b/qcperf/utils/qsleep/src/QSleep.c index 09798e1..39a7453 100644 --- a/qcperf/utils/qsleep/src/QSleep.c +++ b/qcperf/utils/qsleep/src/QSleep.c @@ -42,7 +42,7 @@ * usleep() for millisecond-level precision. */ -#include "qsleep.h" +#include "QSleep.h" #ifdef _WIN32 #include diff --git a/qcperf/utils/qthread/CMakeLists.txt b/qcperf/utils/qthread/CMakeLists.txt index 79bf066..05ef37a 100644 --- a/qcperf/utils/qthread/CMakeLists.txt +++ b/qcperf/utils/qthread/CMakeLists.txt @@ -3,11 +3,11 @@ if(QCPERF_OS_WINDOWS) add_library(QcPerfQThread STATIC - src/windows/qthread.c + src/windows/QThread.c ) else() add_library(QcPerfQThread STATIC - src/linux/qthread.c + src/linux/QThread.c ) endif() diff --git a/qcperf/utils/qthread/src/linux/QThread.c b/qcperf/utils/qthread/src/linux/QThread.c index acb7756..1f94ca5 100644 --- a/qcperf/utils/qthread/src/linux/QThread.c +++ b/qcperf/utils/qthread/src/linux/QThread.c @@ -41,7 +41,7 @@ * and pthread_cancel to provide the functionality required by the qthread interface. */ -#include "qthread.h" +#include "QThread.h" #include #include diff --git a/qcperf/utils/qthread/src/windows/QThread.c b/qcperf/utils/qthread/src/windows/QThread.c index 0a0fa06..eb09b4d 100644 --- a/qcperf/utils/qthread/src/windows/QThread.c +++ b/qcperf/utils/qthread/src/windows/QThread.c @@ -41,7 +41,7 @@ * and TerminateThread to provide the functionality required by the qthread interface. */ -#include "qthread.h" +#include "QThread.h" #include enum QThreadReturnCode thread_create(struct QThreadAttributes* thread_request, struct QThreadInfo* thread_info) { diff --git a/qcperf/utils/qtime/CMakeLists.txt b/qcperf/utils/qtime/CMakeLists.txt index cdbe26c..f257f6f 100644 --- a/qcperf/utils/qtime/CMakeLists.txt +++ b/qcperf/utils/qtime/CMakeLists.txt @@ -5,10 +5,10 @@ if(QCPERF_OS_WINDOWS) add_library(QcPerfQTime STATIC src/windows/qtime.c ) -# else() -# add_library(QcPerfQTime STATIC -# src/linux/qtime.c -# ) +else() + add_library(QcPerfQTime STATIC + src/linux/qtime.c + ) endif() # Link with OS-specific time libraries diff --git a/qcperf/utils/qtime/src/linux/qtime.c b/qcperf/utils/qtime/src/linux/qtime.c new file mode 100644 index 0000000..2785be8 --- /dev/null +++ b/qcperf/utils/qtime/src/linux/qtime.c @@ -0,0 +1,67 @@ +/* + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + Redistribution and use in source and binary forms, with or without + modification, are permitted (subject to the limitations in the + disclaimer below) provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Qualcomm Technologies, Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE + GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT + HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file qtime.c + * @brief Linux implementation of time utility functions + * @author Himanshu Keshri (hkeshri@qti.qualcomm.com) + * + * This file implements the time utility functions defined in qtime.h + * for Linux platforms. It provides a cross-platform abstraction layer over + * the Linux high-resolution timing APIs. + */ + +#include +#include +#include "qtime.h" + +#define QTIMER_NS_PER_TICKS 52 + +enum QTimeReturnCode get_time_ns(uint64_t* time_ns) { + enum QTimeReturnCode return_code = RETURN_CODE_TIME_FAILED; +#ifdef LINUX_ARM64 + uint64_t ticks = 0; +#else + struct timespec spec = {0}; +#endif + if (NULL == time_ns) { + return_code = RETURN_CODE_TIME_NULL_POINTER; + } else { +#ifdef LINUX_ARM64 + asm volatile("mrs %0, cntvct_el0" : "=r"(ticks)); // Get QTimer ticks + *time_ns = (uint64_t)(ticks * QTIMER_NS_PER_TICKS); +#else + if (clock_gettime(CLOCK_REALTIME, &spec) != -1) { + *time_ns = (uint64_t)(spec.tv_sec * 1e9) + spec.tv_nsec; + } +#endif + return_code = RETURN_CODE_TIME_SUCCESS; + } + return return_code; +}