Info Logs Extension#

Introduced in Level Zero version 1.19

API#

Info Logs Overview#

An info log is a stream of records reported by the driver, where each record describes an error or another event of interest that occurred on one of the devices managed by that driver.

Info logs are driver scoped: a single info log may carry records generated by any of the devices managed by the driver. The device that generated a record is identified by the PCI address and the UUID reported in the metadata of that record.

The format of the records is reported by zesInfoLogGetPropertiesExt. Records in :ref:`ZES_INFO_LOG_FORMAT_EXT_CPER <zes-info-log-format-ext-t>`\ format are UEFI Common Platform Error Records; the extension returns them as opaque binary data and the application is responsible for decoding them.

Enumerating Info Logs and Querying Properties#

// Query the number of info logs supported by the driver
uint32_t logCount = 0;
zesDriverEnumInfoLogsExt(hDriver, &logCount, nullptr);

if (logCount == 0) {
    output("No info logs available\n");
    return;
}

zes_info_log_handle_t* phInfoLogs = (zes_info_log_handle_t*)
    allocate(logCount * sizeof(zes_info_log_handle_t));
zesDriverEnumInfoLogsExt(hDriver, &logCount, phInfoLogs);

// Query the properties of the first info log
zes_info_log_ext_properties_t logProps = {};
logProps.stype = ZES_STRUCTURE_TYPE_INFO_LOG_EXT_PROPERTIES;
logProps.pNext = nullptr;

zesInfoLogGetPropertiesExt(phInfoLogs[0], &logProps);

output("Info log type: %u, format: %u\n",
       logProps.infoLogType, logProps.infoLogFormat);
output("Named collection instances supported: %s\n",
       logProps.isNamedInstanceSupported ? "yes" : "no");
output("Peek supported: %s\n",
       logProps.isPeekDataSupported ? "yes" : "no");

Collecting and Reading Records#

// Request a 256 KB collection buffer
uint32_t bufferSizeInKb = 256;

zes_info_log_instance_ext_desc_t desc = {};
desc.stype = ZES_STRUCTURE_TYPE_INFO_LOG_INSTANCE_EXT_DESC;
desc.pNext = nullptr;
desc.pBufferSizeInKb = &bufferSizeInKb;

// Named instances require isNamedInstanceSupported == true
const char* pInstanceName =
    logProps.isNamedInstanceSupported ? "my_collection" : nullptr;

zes_info_log_instance_handle_t hInstance = nullptr;
if (zesInfoLogCreateInstanceExt(phInfoLogs[0], pInstanceName, &desc, &hInstance)
        != ZE_RESULT_SUCCESS) {
    output("Could not start info log collection\n");
    return;
}

// The driver may round the requested values; re-read what was applied
output("Collecting into %u KB\n", bufferSizeInKb);

const uint64_t timeoutInMs = 500;

// Size a working buffer once
const uint32_t bufferSize = 64 * 1024;
const uint32_t maxRecords = 64;

uint8_t* pBuffer = (uint8_t*) allocate(bufferSize);
zes_info_log_metadata_ext_t* pDescriptors = (zes_info_log_metadata_ext_t*)
    allocate(maxRecords * sizeof(zes_info_log_metadata_ext_t));

ze_bool_t hasDataToRead = true;
while (hasDataToRead) {
    uint32_t size = bufferSize;
    uint32_t recordCount = maxRecords;

    for (uint32_t i = 0; i < maxRecords; i++) {
        pDescriptors[i].stype = ZES_STRUCTURE_TYPE_INFO_LOG_METADATA_EXT;
        pDescriptors[i].pNext = nullptr;
    }

    zes_info_log_read_status_ext_t readStatus = {};
    readStatus.stype = ZES_STRUCTURE_TYPE_INFO_LOG_READ_STATUS_EXT;
    readStatus.pNext = nullptr;

    ze_result_t result = zesInfoLogInstanceReadWithMetadataExt(
        hInstance, timeoutInMs, &size, pBuffer,
        &recordCount, pDescriptors, &readStatus);

    if (result != ZE_RESULT_SUCCESS &&
        result != ZE_RESULT_WARNING_DROPPED_DATA) {
        output("Could not read info log records\n");
        break;
    }

    if (result == ZE_RESULT_WARNING_DROPPED_DATA) {
        // The collection buffer overflowed. Consider a larger pBufferSizeInKb
        // or reading more often.
        if (readStatus.droppedRecordCount == UINT32_MAX) {
            output("Warning: records were dropped, count unknown\n");
        } else {
            output("Warning: %u records dropped\n",
                   readStatus.droppedRecordCount);
        }
    }

    for (uint32_t i = 0; i < recordCount; i++) {
        output("Record %u: device %04x:%02x:%02x.%x, timestamp %llu ns, %u bytes\n",
               i, pDescriptors[i].address.domain, pDescriptors[i].address.bus,
               pDescriptors[i].address.device, pDescriptors[i].address.function,
               pDescriptors[i].timestamp, pDescriptors[i].lengthOfData);

        switch (pDescriptors[i].recordType) {
        case ZES_INFO_LOG_RECORD_TYPE_EXT_ERROR_RECOVERABLE:
            escalate(&pDescriptors[i]);
            break;
        case ZES_INFO_LOG_RECORD_TYPE_EXT_ERROR_CORRECTED:
        case ZES_INFO_LOG_RECORD_TYPE_EXT_INFORMATIONAL:
            break;
        default:
            // Includes values added by a later version of this extension
            break;
        }

        const uint8_t* pRecord = pBuffer + pDescriptors[i].offset;
        process(pRecord, pDescriptors[i].lengthOfData);
    }

    hasDataToRead = readStatus.hasDataToRead;
}

free(pDescriptors);
free(pBuffer);

// Cleanup
zesInfoLogInstanceDeleteExt(hInstance);
free(phInfoLogs);