Program Listing for File QnnProfile.h

Return to documentation for file (include/QNN/QnnProfile.h)

//==============================================================================
//
// Copyright (c) 2019-2024 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
//
//==============================================================================

/**
 *  @file
 *  @brief Profile component API.
 *
 *          Requires Backend to be initialized.
 *          Provides means to profile QNN backends to evaluate performance
 *          (memory and timing) of graphs and operations.
 */

#ifndef QNN_PROFILE_H
#define QNN_PROFILE_H

#include "QnnCommon.h"
#include "QnnTypes.h"

#ifdef __cplusplus
extern "C" {
#endif

//=============================================================================
// Macros
//=============================================================================
/**
 * @brief QnnProfile_EventType_t definition to get stats related to creation of
 *        context and graphs. If supported, this profile data captures stats
 *        starting with the context creation (QnnContext_create) and ending with
 *        graph finalize (QnnGraph_finalize). Alternatively, in case of loading
 *        a cached context, it captures stats for creating context from the
 *        cache (QnnContext_createFromBinary).
 *
 * @note init information maybe available on both QNN_PROFILE_LEVEL_BASIC and
 *       QNN_PROFILE_LEVEL_DETAILED levels
 *
 * @note If unit information is not available, the value should be interpreted
 *       as time in microseconds.
 */
#define QNN_PROFILE_EVENTTYPE_INIT 100

/**
 * @brief QnnProfile_EventType_t definition to get stats related to finalize
 *        operation on graphs in a context. If supported, this profile data
 *        captures stats for graph finalize (QnnGraph_finalize).
 *
 * @note finalize information maybe available on both QNN_PROFILE_LEVEL_BASIC and
 *       QNN_PROFILE_LEVEL_DETAILED levels
 *
 * @note If unit information is not available, the value should be interpreted
 *       as time in microseconds.
 */
#define QNN_PROFILE_EVENTTYPE_FINALIZE 300

/**
 * @brief QnnProfile_EventType_t definition to get stats related to execution
 *        of graphs in a context (QnnGraph_execute or QnnGraph_executeAsync).
 *        Basic level might include stats related to execution of entire graphs.
 *        In addition, detailed level can include stats related to individual
 *        nodes in graphs as sub-events.
 *
 * @note execute information maybe available on both QNN_PROFILE_LEVEL_BASIC and
 *       QNN_PROFILE_LEVEL_DETAILED levels
 *
 * @note If unit information is not available, the value should be interpreted
 *       as time in microseconds.
 */
#define QNN_PROFILE_EVENTTYPE_EXECUTE 400

/**
 * @brief QnnProfile_EventType_t definition to get data related to execution of
 *        an operation. This value can be interpreted appropriately in conjunction
 *        with the unit.
 *
 * @note node specific information is available on QNN_PROFILE_LEVEL_DETAILED level
 *
 * @note This is a sub-event of the QNN_PROFILE_EVENTTYPE_EXECUTE event.
 */
#define QNN_PROFILE_EVENTTYPE_NODE 404

/**
 * @brief QnnProfile_EventType_t definition to get stats related to time spent
 *        waiting in a queue when executing a graph.
 *
 * @note execute enqueue information maybe available on both QNN_PROFILE_LEVEL_BASIC
 *       and QNN_PROFILE_LEVEL_DETAILED levels
 *
 * @note This is a sub-event of the QNN_PROFILE_EVENTTYPE_EXECUTE event.
 */
#define QNN_PROFILE_EVENTTYPE_EXECUTE_QUEUE_WAIT 405

/**
 * @brief QnnProfile_EventType_t definition to get stats related to time spent
 *        pre-processing in preparation of executing a graph.
 *
 * @note execute preprocess information maybe available on both QNN_PROFILE_LEVEL_BASIC
 *       and QNN_PROFILE_LEVEL_DETAILED levels
 *
 * @note This is a sub-event of the QNN_PROFILE_EVENTTYPE_EXECUTE event.
 */
#define QNN_PROFILE_EVENTTYPE_EXECUTE_PREPROCESS 406

/**
 * @brief QnnProfile_EventType_t definition to get stats related to time spent
 *        on-device executing a graph.
 *
 * @note execute device information maybe available on both QNN_PROFILE_LEVEL_BASIC
 *       and QNN_PROFILE_LEVEL_DETAILED levels
 *
 * @note This is a sub-event of the QNN_PROFILE_EVENTTYPE_EXECUTE event.
 */
#define QNN_PROFILE_EVENTTYPE_EXECUTE_DEVICE 407

/**
 * @brief QnnProfile_EventType_t definition to get stats related to time spent
 *        post-processing after execution of a graph.
 *
 * @note execute postprocess information maybe available on both QNN_PROFILE_LEVEL_BASIC
 *       and QNN_PROFILE_LEVEL_DETAILED levels
 *
 * @note This is a sub-event of the QNN_PROFILE_EVENTTYPE_EXECUTE event.
 */
#define QNN_PROFILE_EVENTTYPE_EXECUTE_POSTPROCESS 408

/**
 * @brief QnnProfile_EventType_t definition to get stats related to deinit
 *        graphs and free context operation. This profile data captures stats
 *        for QnnContext_free.
 *
 * @note deinit information maybe available on both QNN_PROFILE_LEVEL_BASIC and
 *       QNN_PROFILE_LEVEL_DETAILED levels
 *
 * @note If unit information is not available, the value should be interpreted
 *       as time in microseconds.
 */
#define QNN_PROFILE_EVENTTYPE_DEINIT 500

/**
 * @brief QnnProfile_EventType_t definition to get traces related to graph
 *        preparation and execution steps. This profile data captures stats
 *        for QnnGraph_execute.
 *
 * @note trace information is available on QNN_PROFILE_LEVEL_DETAILED
 *       level only.
 */
#define QNN_PROFILE_EVENTTYPE_TRACE 600

/**
 * @brief QnnProfile_EventType_t definition reserved for each back end to define
 *        and extend
 *
 * @note The client should consult the backend-specific SDK documentation for
 *       information regarding interpretation of unit, value and identifier.
 */
#define QNN_PROFILE_EVENTTYPE_BACKEND 1000

/**
 * @brief Basic QnnProfile_Level_t definition that allows to collect performance
 *        metrics for graph finalization and execution stages.
 */
#define QNN_PROFILE_LEVEL_BASIC 1

/**
 * @brief Detailed QnnProfile_Level_t definition that allows to collect performance
 *        metrics for each operation in the graph
 */
#define QNN_PROFILE_LEVEL_DETAILED 2

/**
 * @brief QnnProfile_Level_t definition reserved for each back end to define and
 *        extend
 */
#define QNN_PROFILE_LEVEL_BACKEND 1000

/**
 * @brief QnnProfile_EventUnit_t definition to provide profiling measurement as
 *        time in microseconds
 */
#define QNN_PROFILE_EVENTUNIT_MICROSEC 1

/**
 * @brief QnnProfile_EventUnit_t definition to provide profiling measurement as
 *        memory in bytes
 */
#define QNN_PROFILE_EVENTUNIT_BYTES 2

/**
 * @brief QnnProfile_EventUnit_t definition to provide profiling measurement as
 *        time in cycles
 */
#define QNN_PROFILE_EVENTUNIT_CYCLES 3

/**
 * @brief QnnProfile_EventUnit_t definition to provide profiling measurement as
 *        a count
 */
#define QNN_PROFILE_EVENTUNIT_COUNT 4

/**
 * @brief QnnProfile_EventUnit_t definition to provide profiling measurement as
 *        an opaque object
 */
#define QNN_PROFILE_EVENTUNIT_OBJECT 5

/**
 * @brief QnnProfile_EventUnit_t definition to provide profiling measurement with
 *        no unit
 */
#define QNN_PROFILE_EVENTUNIT_NONE 6

/**
 * @brief QnnProfile_EventUnit_t definition reserved for each back end to define
 *        and extend
 */
#define QNN_PROFILE_EVENTUNIT_BACKEND 1000

//=============================================================================
// Data Types
//=============================================================================

/**
 * @brief QNN Profile API result / error codes.
 */
typedef enum {
  QNN_PROFILE_MIN_ERROR = QNN_MIN_ERROR_PROFILE,
  ////////////////////////////////////////////

  /// Qnn Profile success
  QNN_PROFILE_NO_ERROR = QNN_SUCCESS,
  /// Backend does not support requested functionality
  QNN_PROFILE_ERROR_UNSUPPORTED = QNN_COMMON_ERROR_NOT_SUPPORTED,
  /// Invalid function argument
  QNN_PROFILE_ERROR_INVALID_ARGUMENT = QNN_COMMON_ERROR_INVALID_ARGUMENT,
  /// General error relating to memory allocation in Profile API
  QNN_PROFILE_ERROR_MEM_ALLOC = QNN_COMMON_ERROR_MEM_ALLOC,
  /// Invalid/NULL QNN profile handle
  QNN_PROFILE_ERROR_INVALID_HANDLE = QNN_MIN_ERROR_PROFILE + 0,
  /// Attempt to free or reconfigure a profile handle that is in-use
  QNN_PROFILE_ERROR_HANDLE_IN_USE = QNN_MIN_ERROR_PROFILE + 1,
  /// Event is incompatible with API
  QNN_PROFILE_ERROR_INCOMPATIBLE_EVENT = QNN_MIN_ERROR_PROFILE + 2,

  ////////////////////////////////////////////
  QNN_PROFILE_MAX_ERROR = QNN_MAX_ERROR_PROFILE,
  // Unused, present to ensure 32 bits.
  QNN_PROFILE_ERROR_UNDEFINED = 0x7FFFFFFF
} QnnProfile_Error_t;

/**
 * @brief Backend defined type for a profiled event such as time_taken, time_start, memory
 */
typedef uint32_t QnnProfile_EventType_t;

/**
 * @brief Represents a profiled event value
 */
typedef uint64_t QnnProfile_EventValue_t;

/**
 * @brief Profile levels supported by each backend
 */
typedef uint32_t QnnProfile_Level_t;

/**
 * @brief ID of a profiling event
 */
typedef uint64_t QnnProfile_EventId_t;

/**
 * @brief Unit of measurement of a profiling event
 */
typedef uint32_t QnnProfile_EventUnit_t;

/**
 * @brief This struct provides event information.
 */
typedef struct {
  /// Type of event
  QnnProfile_EventType_t type;
  /// Unit of measurement for the event
  QnnProfile_EventUnit_t unit;
  /// Value for the event
  QnnProfile_EventValue_t value;
  /// Identifier for the event
  const char* identifier;
} QnnProfile_EventData_t;

// clang-format off
/// QnnProfile_EventData_t initializer macro
#define QNN_PROFILE_EVENT_DATA_INIT \
  {                                 \
    0u,      /*type*/               \
    0u,      /*unit*/               \
    0u,      /*value*/              \
    NULL     /*identifier*/         \
  }
// clang-format on

/**
 * @brief A struct which defines a backend opaque object
 */
typedef struct {
  /// Opaque object
  Qnn_OpaqueObject_t opaqueObject;
  /// Name of the file. Can be NULL.
  const char* fileName;
} QnnProfile_BackendOpaqueObject_t;

// clang-format off
/// QnnProfile_BackendOpaqueObject_t initializer macro
#define QNN_PROFILE_BACKEND_OPAQUE_OBJECT_INIT \
  {                                            \
    QNN_OPAQUE_OBJECT_INIT, /*opaqueObject*/   \
    NULL                    /*fileName*/       \
  }
// clang-format on

/**
 * @brief This struct provides extended event information.
 */
typedef struct {
  /// Type of the event
  QnnProfile_EventType_t type;
  /// Unit of measurement for the event
  QnnProfile_EventUnit_t unit;
  /// Event data
  /// The field used is dependent on the event unit.
  union UNNAMED {
    /// Used for MICROSEC, BYTES, CYCLES, COUNT.
    Qnn_Scalar_t value;
    /// Used for OBJECT.
    QnnProfile_BackendOpaqueObject_t backendOpaqueObject;
  };
  /// Timestamp for the event, represented in microsecond unit.
  uint64_t timestamp;
  /// Identifier for the event. Can be NULL.
  const char* identifier;
} QnnProfile_ExtendedEventDataV1_t;

// clang-format off
/// QnnProfile_ExtendedEventDataV1_t initializer macro
#define QNN_PROFILE_EXTENDED_EVENT_DATA_V1_INIT \
  {                                             \
    0u,               /*type*/                  \
    0u,               /*unit*/                  \
    {                                           \
      QNN_SCALAR_INIT /*value*/                 \
    },                                          \
    0u,               /*timestamp*/             \
    NULL              /*identifier*/            \
  }
// clang-format on

typedef enum {
  QNN_PROFILE_DATA_VERSION_1         = 1,
  QNN_PROFILE_DATA_VERSION_UNDEFINED = 0x7FFFFFFF
} QnnProfile_ExtendedEventDataVersion_t;

typedef struct {
  QnnProfile_ExtendedEventDataVersion_t version;
  union UNNAMED {
    QnnProfile_ExtendedEventDataV1_t v1;
  };
} QnnProfile_ExtendedEventData_t;

// clang-format off
/// QnnProfile_ExtendedEventData_t initializer macro
#define QNN_PROFILE_EXTENDED_EVENT_DATA_INIT         \
  {                                                  \
    QNN_PROFILE_DATA_VERSION_1, /*version*/          \
    {                                                \
      QNN_PROFILE_EXTENDED_EVENT_DATA_V1_INIT /*v1*/ \
    }                                                \
  }
// clang-format on

/**
 * @brief This enum defines profile config options.
 */
typedef enum {
  /// Sets backend custom configs, see backend specific documentation.
  QNN_PROFILE_CONFIG_OPTION_CUSTOM = 0,
  /// This config sets the maximum number of profiling events
  /// that can be stored in the profile handle. Once the maximum
  /// number of events is reached, no more events will be stored.
  /// The absolute maximum number of events is subject to a maximum limit
  /// determined by the backend and available system resources. The default
  /// maximum number of events is backend-specific, refer to SDK documentation.
  QNN_PROFILE_CONFIG_OPTION_MAX_EVENTS = 1,
  /// Set optrace profiling support via enableOptrace flag.
  /// Please note that the trace information is available on QNN_PROFILE_LEVEL_DETAILED level only.
  QNN_PROFILE_CONFIG_OPTION_ENABLE_OPTRACE = 2,
  /// Value selected to ensure 32 bits.
  QNN_PROFILE_CONFIG_OPTION_UNDEFINED = 0x7FFFFFFF
} QnnProfile_ConfigOption_t;

/**
 * @brief Profile specific object for custom configuration
 *
 * Please refer to documentation provided by the backend for usage information
 */
typedef void* QnnProfile_CustomConfig_t;

/**
 * @brief This struct provides profile configuration.
 */
typedef struct {
  QnnProfile_ConfigOption_t option;
  union UNNAMED {
    QnnProfile_CustomConfig_t customConfig;
    uint64_t numMaxEvents;
    uint8_t enableOptrace;
  };
} QnnProfile_Config_t;

// clang-format off
/// QnnProfile_Config_t initializer macro
#define QNN_PROFILE_CONFIG_INIT                     \
  {                                                 \
    QNN_PROFILE_CONFIG_OPTION_UNDEFINED, /*option*/ \
    {                                               \
      NULL /*customConfig*/                         \
    }                                               \
  }
// clang-format on

//=============================================================================
// Public Functions
//=============================================================================

/**
 * @brief Create a handle to a profile object.
 *
 * @param[in] backend A backend handle.
 *
 * @param[in] level Granularity level at which the profile should collect events.
 *
 * @param[out] profile A profile handle.
 *
 * @return Error code
 *         - QNN_SUCCESS: No error encountered
 *         - QNN_PROFILE_ERROR_INVALID_ARGUMENT: _profile_ is NULL or _level_ is invalid.
 *         - QNN_PROFILE_ERROR_UNSUPPORTED: Profiling is unsupported on a backend.
 *         - QNN_PROFILE_ERROR_MEM_ALLOC: Error in allocating memory when creating profile handle
 *         - QNN_PROFILE_ERROR_INVALID_HANDLE: _backend_ is not a valid handle
 *
 * @note Use corresponding API through QnnInterface_t.
 */
QNN_API
Qnn_ErrorHandle_t QnnProfile_create(Qnn_BackendHandle_t backend,
                                    QnnProfile_Level_t level,
                                    Qnn_ProfileHandle_t* profile);

/**
 * @brief A function to set/modify configuration options on an already created profile handle.
 *
 * @param[in] profileHandle A profile handle.
 *
 * @param[in] config Pointer to a NULL terminated array of config option pointers. NULL is allowed
 *                   and indicates no config options are provided. All config options have default
 *                   value, in case not provided. If same config option type is provided multiple
 *                   times, the last option value will be used. If a backend cannot support all
 *                   provided configs it will fail.
 *
 * @return Error code:
 *         - QNN_SUCCESS: no error is encountered
 *         - QNN_PROFILE_ERROR_INVALID_HANDLE: _profileHandle_ is not a valid handle
 *         - QNN_PROFILE_ERROR_INVALID_ARGUMENT: at least one config option is invalid
 *         - QNN_PROFILE_ERROR_HANDLE_IN_USE: when attempting to reconfigure a profile handle
 *         - QNN_PROFILE_ERROR_UNSUPPORTED: Config option is not supported
 *
 * @note Use corresponding API through QnnInterface_t.
 */
QNN_API
Qnn_ErrorHandle_t QnnProfile_setConfig(Qnn_ProfileHandle_t profileHandle,
                                       const QnnProfile_Config_t** config);

/**
 * @brief Get Qnn profile events collected on the profile handle.
 *
 * @param[in] profile A profile handle.
 *
 * @param[out] profileEventIds Returns handles to Qnn profile events collected on this profile
 *                             object.
 *
 * @param[out] numEvents Number of profile events.
 *
 * @note profileEvents parameter: profile event memory is associated with the profile object and
 *       released on profile object release in QnnProfile_free().
 *
 * @return Error code
 *         - QNN_SUCCESS: No error encountered
 *         - QNN_PROFILE_ERROR_INVALID_ARGUMENT: _profileEventIds_ or _numEvents_ is NULL.
 *         - QNN_PROFILE_ERROR_INVALID_HANDLE: _profile_ is not a valid handle.
 *         - QNN_PROFILE_ERROR_MEM_ALLOC: error related to memory allocation
 *
 * @note Use corresponding API through QnnInterface_t.
 */
QNN_API
Qnn_ErrorHandle_t QnnProfile_getEvents(Qnn_ProfileHandle_t profile,
                                       const QnnProfile_EventId_t** profileEventIds,
                                       uint32_t* numEvents);

/**
 * @brief Get Qnn profile event handles nested within this Qnn profile event handle.
 *
 * @param[in] eventId QNN Profile event whose sub events are being queried.
 *
 * @param[out] subEventIds Nested profile events on this event.
 *
 * @param[out] numSubEvents Number of profile events.
 *
 * @note subEventIds parameter: profile event memory is associated with the profile object and
 *       released on profile object release in QnnProfile_free().
 *
 * @return Error code
 *         - QNN_SUCCESS: No error encountered
 *         - QNN_PROFILE_ERROR_INVALID_ARGUMENT: _subEventIds_ or _numSubEvents_ is NULL.
 *         - QNN_PROFILE_ERROR_INVALID_HANDLE: _eventId_ does not identify a valid event.
 *         - QNN_PROFILE_ERROR_MEM_ALLOC: error related to memory allocation
 *
 * @note Use corresponding API through QnnInterface_t.
 */
QNN_API
Qnn_ErrorHandle_t QnnProfile_getSubEvents(QnnProfile_EventId_t eventId,
                                          const QnnProfile_EventId_t** subEventIds,
                                          uint32_t* numSubEvents);

/**
 * @brief Query the data associated with this profile event.
 *
 * @param[in] eventId Qnn profile event being queried.
 *
 * @param[out] eventData Event data associated to this event.
 *
 * @note eventData parameter: eventData memory is associated with the profile object and released
 *       on profile object release in QnnProfile_free().
 *
 * @return Error code
 *         - QNN_SUCCESS: No error encountered
 *         - QNN_PROFILE_ERROR_UNSUPPORTED: API not supported.
 *         - QNN_PROFILE_ERROR_INCOMPATIBLE_EVENT: _eventData_ is incompatible with the API. Use
 *           QnnProfile_getExtendedEventData instead.
 *         - QNN_PROFILE_ERROR_INVALID_ARGUMENT: _eventData_ is NULL.
 *         - QNN_PROFILE_ERROR_INVALID_HANDLE: _eventId_ does not identify a valid event.
 *         - QNN_PROFILE_ERROR_MEM_ALLOC: error related to memory allocation
 *
 * @note Use corresponding API through QnnInterface_t.
 */
QNN_API
Qnn_ErrorHandle_t QnnProfile_getEventData(QnnProfile_EventId_t eventId,
                                          QnnProfile_EventData_t* eventData);

/**
 * @brief Query the data associated with this profile extended event.
 *
 * @param[in] eventId Qnn profile extended event being queried.
 *
 * @param[out] eventData Event data associated to this extended event.
 *
 * @note eventData parameter: eventData memory is associated with the profile object and released
 *       on profile object release in QnnProfile_free().
 *
 * @return Error code
 *         - QNN_SUCCESS: No error encountered
 *         - QNN_PROFILE_ERROR_UNSUPPORTED: API not supported.
 *         - QNN_PROFILE_ERROR_INVALID_ARGUMENT: _eventData_ is NULL.
 *         - QNN_PROFILE_ERROR_INVALID_HANDLE: _eventId_ does not identify a valid event.
 *         - QNN_PROFILE_ERROR_MEM_ALLOC: error related to memory allocation
 *
 * @note Use corresponding API through QnnInterface_t.
 */
QNN_API
Qnn_ErrorHandle_t QnnProfile_getExtendedEventData(QnnProfile_EventId_t eventId,
                                                  QnnProfile_ExtendedEventData_t* eventData);

/**
 * @brief Free memory associated with the profile handle.
 *        All associated QnnProfile_EventId_t event handles are implicitly freed.
 *
 * @param[in] profile Handle to be freed.
 *
 * @note Releasing the profile handle invalidates the memory returned via calls on this handle such
 *       as QnnProfile_getEvents(), QnnProfile_getSubEvents(), QnnProfile_getEventData(),
 *       QnnProfile_getExtendedEventData(), etc.
 *
 * @note The profile handle cannot be freed when it is bound to another API component or
 *       in use by an API call.
 *
 * @return Error code
 *         - QNN_SUCCESS: No error encountered
 *         - QNN_PROFILE_ERROR_INVALID_HANDLE: _profile_ is not a valid handle.
 *         - QNN_PROFILE_ERROR_MEM_ALLOC: error related to memory de-allocation
 *         - QNN_PROFILE_ERROR_HANDLE_IN_USE: _profile_ is in-use and cannot be freed.
 *
 * @note Use corresponding API through QnnInterface_t.
 */
QNN_API
Qnn_ErrorHandle_t QnnProfile_free(Qnn_ProfileHandle_t profile);

#ifdef __cplusplus
}
#endif

#endif  // QNN_PROFILE_H