[PATCH i-g-t v1] tools/xe_guc_logger: Add guc logger for Xe
Peter Senna Tschudin
peter.senna at linux.intel.com
Tue Apr 8 09:10:10 UTC 2025
Dear Zhanjun,
On 3/12/2025 10:30 PM, Zhanjun Dong wrote:
> Add guc logger for Xe, support save guc log in LFD format.
I tested this patch and found the behavior of the tool a bit
confusing. It behaves more like a test than a standalone tool.
For example:
$ sudo ./build/tools/xe_guc_logger -i /sys/kernel/debug/dri/0000:03:00.0/gt0/uc/guc_log
IGT-Version: 2.0-g4b22256d0 (x86_64) (Linux: 6.14.0-xe x86_64)
Using IGT_SRANDOM=1744102201 for randomisation
SUCCESS (0.371s)
$ sudo ./build/tools/xe_guc_logger --help
Usage: xe_guc_logger [OPTIONS]
--list-subtests
--show-testlist
--run-subtest <pattern>
--dynamic-subtest <pattern>
--debug[=log-domain]
--interactive-debug[=domain]
--skip-crc-compare
--trace-on-oops
--hook [<events>:]<cmd>
--help-hook
--help-description
--describe
--device filters
--version
--help|-h
-i --inputfile=name name of the guc log file, including the path
-o --outputfile=name name of the output file, including the location, where logs will be stored
-v --verbosity=level verbosity level of output
This makes it appear as if the logger is a test case rather
than a tool. I suggest removing this test-like behavior. You
can look at other examples under the tools/ directory, such
as lsgpu and igt_facts, which are implemented as tools.
Additionally, the tool is hard to use without reading the
source code. It would help to:
- Automatically locate the guc_log files in /sys/kernel/debug/
- Provide a clearer error message when the input file is
not specified
Right now, omitting the -i option results in a test-like
assertion failure with no guidance:
$ sudo ./build/tools/xe_guc_logger
IGT-Version: 2.0-g4b22256d0 (x86_64) (Linux: 6.14.0-xe x86_64)
Using IGT_SRANDOM=1744102681 for randomisation
(xe_guc_logger:2445) CRITICAL: Test assertion failure function load_guc_log, file ../tools/xe_guc_logger.c:267:
(xe_guc_logger:2445) CRITICAL: Failed assertion: fd
(xe_guc_logger:2445) CRITICAL: Last errno: 2, No such file or directory
(xe_guc_logger:2445) CRITICAL: couldn't open the file: guc_log
Stack trace:
#0 ../lib/igt_core.c:2065 __igt_fail_assert()
#1 ../tools/xe_guc_logger.c:166 main()
#2 ../sysdeps/nptl/libc_start_call_main.h:74 __libc_start_call_main()
#3 ../csu/libc-start.c:128 __libc_start_main@@GLIBC_2.34()
#4 [_start+0x25]
Test xe_guc_logger failed.
**** DEBUG ****
(xe_guc_logger:2445) igt_core-INFO: IGT-Version: 2.0-g4b22256d0 (x86_64) (Linux: 6.14.0-xe x86_64)
(xe_guc_logger:2445) igt_core-INFO: Using IGT_SRANDOM=1744102681 for randomisation
(xe_guc_logger:2445) CRITICAL: Test assertion failure function load_guc_log, file ../tools/xe_guc_logger.c:267:
(xe_guc_logger:2445) CRITICAL: Failed assertion: fd
(xe_guc_logger:2445) CRITICAL: Last errno: 2, No such file or directory
(xe_guc_logger:2445) CRITICAL: couldn't open the file: guc_log
(xe_guc_logger:2445) igt_core-INFO: Stack trace:
(xe_guc_logger:2445) igt_core-INFO: #0 ../lib/igt_core.c:2065 __igt_fail_assert()
(xe_guc_logger:2445) igt_core-INFO: #1 ../tools/xe_guc_logger.c:166 main()
(xe_guc_logger:2445) igt_core-INFO: #2 ../sysdeps/nptl/libc_start_call_main.h:74 __libc_start_call_main()
(xe_guc_logger:2445) igt_core-INFO: #3 ../csu/libc-start.c:128 __libc_start_main@@GLIBC_2.34()
(xe_guc_logger:2445) igt_core-INFO: #4 [_start+0x25]
**** END ****
FAIL (0.046s)
Instead, please consider printing a helpful usage message,
such as:
$ sudo ./build/tools/xe_guc_logger
ERROR: Please use -i to specify the guc_log file
(e.g. -i /sys/kernel/debug/dri/0000:03:00.0/gt0/uc/guc_log)
Lastly, it would be helpful to clarify the purpose of the
output file. What does the tool provide that a simple cat
on the guc_log file wouldn’t? A short explanation in the
source code and the --help output would help users and
developers understand this tool.
Thank you,
Peter>
> Reference:
> https://coredocs.intel.com/InterfaceDocs/sphinx/core/kmd_log_file_format.html?highlight=lfd
>
> Signed-off-by: Zhanjun Dong <zhanjun.dong at intel.com>
> ---
> Cc: John Harrison <John.C.Harrison at Intel.com>
> Cc: Alan Previn <alan.previn.teres.alexis at intel.com>
>
> tools/lfd.h | 590 ++++++++++++++++++++++++++++++++++++++++
> tools/lfd_default.h | 39 +++
> tools/meson.build | 1 +
> tools/xe_guc_logger.c | 615 ++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 1245 insertions(+)
> create mode 100644 tools/lfd.h
> create mode 100644 tools/lfd_default.h
> create mode 100644 tools/xe_guc_logger.c
>
> diff --git a/tools/lfd.h b/tools/lfd.h
> new file mode 100644
> index 000000000..b29627f50
> --- /dev/null
> +++ b/tools/lfd.h
> @@ -0,0 +1,590 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2016-2019 Intel Corporation
> + */
> +
> +#ifndef _INTEL_GUC_LFD_H_
> +#define _INTEL_GUC_LFD_H_
> +
> +#include <stdint.h>
> +
> +/* The current major version of GuC-Log-File format. */
> +#define GUC_LOG_FILE_FORMAT_VERSION_MAJOR 0x0001
> +
> +/* The current minor version of GuC-Log-File format. */
> +#define GUC_LOG_FILE_FORMAT_VERSION_MINOR 0x0000
> +
> +/* Magic keys define */
> +#define GUC_LOGFILE_LFD_MAGIC 0x8086
> +#define LFD_DRIVER_KEY_1 0X808655CC
> +#define LFD_DRIVER_KEY_1 0X808655CC
> +#define LFD_DRIVER_KEY_1V2 0X808655DD
> +#define LFD_DRIVER_KEY_2 0X8086EEAA
> +#define LFD_DRIVER_KEY_2V2 0X8086EEBB
> +#define LFD_DRIVER_KEY_STREAMING1 0X474C5346
> +#define LFD_DRIVER_KEY_STREAMING2 0X8086AAAA
> +#define LFD_DRIVER_KEY_STREAMING 0X8086AAAA474C5346
> +#define LFD_LOG_BUFFER_MARKER_1 0XCABBA9E5
> +#define LFD_LOG_BUFFER_MARKER_2 0XDEADFEED
> +#define LFD_CRASH_DUMP_BUFFER_MARKER_1 0XCABBA9E5
> +#define LFD_CRASH_DUMP_BUFFER_MARKER_2 0X8086DEAD
> +#define LFD_STATE_CAPTURE_BUFFER_MARKER_1 0XCABBA9F6
> +#define LFD_STATE_CAPTURE_BUFFER_MARKER_2 0XBEEFFEED
> +#define LFD_LOG_BUFFER_MARKER_1V2 0XCABBA9E6
> +#define LFD_CRASH_DUMP_BUFFER_MARKER_1V2 0XCABBA9E6
> +#define LFD_STATE_CAPTURE_BUFFER_MARKER_1V2 0XCABBA9F7
> +
> +#define GUC_LOG_BUFFER_STATE_HEADER_LENGTH 4096
> +#define GUC_LOG_BUFFER_STATE_HEADER_ENTRY_COUNT 4
> +#define GUC_LOG_BUFFER_STATE_HEADER_ENTRY_LOG 0
> +#define GUC_LOG_BUFFER_STATE_HEADER_ENTRY_CRASH 1
> +#define GUC_LOG_BUFFER_STATE_HEADER_ENTRY_CAPTURE 2
> +#define GUC_LOG_BUFFER_STATE_HEADER_ENTRY_INIT 3
> +
> +#define GUC_LOG_INIT_CONFIG_LIC_MAGIC 0x8086900D
> +#define GUC_LOG_INIT_CONFIG_FORMAT_VERSION_MAJOR 0x0001
> +#define GUC_LOG_INIT_CONFIG_FORMAT_VERSION_MINOR 0x0000
> +
> +#define GUC_LOG_EVENT_ENTRY_FORMAT_VERSION 2
> +
> +#define LFD_MAGIC_SIM_KEY 0X900DFEED
> +
> +/* Log format descriptor type. */
> +enum guc_lfd_type_t {
> + /* Start of range for required LFDs from GuC. */
> + GUC_LFD_TYPE_FW_REQUIRED_RANGE_START = 0x1,
> +
> + /*
> + * GuC Firmware Version structure. LFDs payload is
> + * guc_lfd_data_fw_version_t
> + */
> + GUC_LFD_TYPE_FW_VERSION = 0x1,
> +
> + /*
> + * GuC microcontroller device ID. LFDs payload is
> + * guc_lfd_data_guc_devid_t
> + */
> + GUC_LFD_TYPE_GUC_DEVICE_ID = 0x2,
> +
> + /*
> + * Frequency of GuC timestamps. LFDs payload is
> + * guc_lfd_data_tsc_freq_t.
> + */
> + GUC_LFD_TYPE_TSC_FREQUENCY = 0x3,
> +
> + /* End of this range. */
> + GUC_LFD_TYPE_FW_REQUIRED_RANGE_END = 0x1FFF,
> +
> + /* Start of range for required LFDs from GuC. */
> + GUC_LFD_TYPE_FW_OPTIONAL_RANGE_START = 0x2000,
> +
> + /*
> + * Log-event-entries buffer. LFDs payload is
> + * guc_lfd_data_log_events_buf_t
> + */
> + GUC_LFD_TYPE_LOG_EVENTS_BUFFER = 0x2000,
> +
> + /*
> + * GuC generated crash-dump blob. LFDs payload is
> + * guc_lfd_data_fw_crashdump_t
> + */
> + GUC_LFD_TYPE_FW_CRASH_DUMP = 0x2001,
> +
> + /* End of this range. */
> + GUC_LFD_TYPE_FW_OPTIONAL_RANGE_END = 0x3FFF,
> +
> + /* Start of range for required KMD LFDs. */
> + GUC_LFD_TYPE_KMD_REQUIRED_RANGE_START = 0x4000,
> +
> + /* An identifier for the OS. LFDs payload is guc_lfd_data_os_id_t. */
> + GUC_LFD_TYPE_OS_ID = 0x4000,
> +
> + /* End of this range. */
> + GUC_LFD_TYPE_KMD_REQUIRED_RANGE_END = 0x5FFF,
> +
> + /* Start of range for optional KMD LFDs. */
> + GUC_LFD_TYPE_KMD_OPTIONAL_RANGE_START = 0x6000,
> +
> + /*
> + * Binary representation of GuC log-events schema.
> + * LFDs TLV payload is guc_lfd_data_binary_schema_t
> + */
> + GUC_LFD_TYPE_BINARY_SCHEMA_FORMAT = 0x6000,
> +
> + /*
> + * ASCII string containing comments from the host/KMD.
> + * LFDs TLV payload is guc_lfd_data_host_comment_t
> + */
> + GUC_LFD_TYPE_HOST_COMMENT = 0x6001,
> +
> + /* End of this range. */
> + GUC_LFD_TYPE_KMD_OPTIONAL_RANGE_END = 0x7FFF,
> +
> + /* Start of reserved range. */
> + GUC_LFD_TYPE_RESERVED_RANGE_START = 0x8000,
> +
> + /* End of this range. */
> + GUC_LFD_TYPE_RESERVED_RANGE_END = 0xFFFF,
> +};
> +
> +/* OS Type LFD-ID. */
> +enum guc_lfd_os_type_t {
> + /* Windows OS. */
> + GUC_LFD_OS_TYPE_OSID_WIN = 0x1,
> +
> + /* Linux OS. */
> + GUC_LFD_OS_TYPE_OSID_LIN = 0x2,
> +
> + /* VMWare OS. */
> + GUC_LFD_OS_TYPE_OSID_VMW = 0x3,
> +
> + /* Other. */
> + GUC_LFD_OS_TYPE_OSID_OTHER = 0x4,
> +};
> +
> +/*
> + * Log format descriptor (LFD). A type of KLV with custom
> + * field-sizes + magic numbers.
> + */
> +struct guc_logfile_lfd_t {
> + /* BR[15:0] Expected value: 0x8086. Helpful in detecting file errors. */
> + uint32_t magic : 16;
> +
> + /*
> + * BR[31:16] File descriptor type (the ‘T’ in TLV) is used to identify
> + * how to interpret data below. For the range of types,
> + * see guc_lfd_type_t
> + */
> + uint32_t desc_type : 16;
> +
> + /* Number of dwords the data field contains. */
> + uint32_t desc_dw_size;
> +
> + /* Data defined by File descriptor type. */
> + uint32_t data[];
> +};
> +
> +/*
> + * GuC Log File Format Version. Major-Minor is not a fractional number
> + * (i.e. Ver 1.3 would be older than 1.12)
> + */
> +struct guc_logfile_fmt_ver_t {
> + /*
> + * BR[15: 0] Guc-Log-File Format minor version.
> + * Must be GUC_LOG_FILE_FORMAT_VERSION_MINOR
> + */
> + uint32_t minor_version : 16;
> +
> + /*
> + * BR[31:16] Guc-Log-File Format major version.
> + * Must be GUC_LOG_FILE_FORMAT_VERSION_MAJOR
> + */
> + uint32_t major_version : 16;
> +};
> +
> +/*
> + * GuC Log Streaming-LFD-File Format. This structure encapsulates the layout of
> + * the guc-log-file format.
> + */
> +struct guc_logfile_t {
> + /*
> + * A magic number set by producer of a GuC log file to identify that
> + * file is a valid guc-log-file containing a stream of LFDs:
> + * Expected value: 0x8086AAAA474C5346.
> + */
> + uint64_t magic;
> +
> + /* Version of this file format layout as per guc_logfile_fmt_ver_t. */
> + struct guc_logfile_fmt_ver_t version;
> +
> + /* A stream of one or more guc_logfile_lfd_t LFD data. */
> + struct guc_logfile_lfd_t lfd_stream[];
> +};
> +
> +/* This structure describes the full version of a software component. */
> +struct guc_sw_version_t {
> + /* BR[ 7: 0] Patch version. */
> + uint32_t patch_version : 8;
> +
> + /* BR[15: 8] Minor version. */
> + uint32_t minor_version : 8;
> +
> + /* BR[23:16] Major version. */
> + uint32_t major_version : 8;
> +
> + /* BR[31:24] Branch ID. */
> + uint32_t branch_id : 8;
> +};
> +
> +/* GuC FW Version. This is mandatory fw LFD data. */
> +struct guc_lfd_data_fw_version_t {
> + /* The full version of the GuC microkernel that generated the logs. */
> + struct guc_sw_version_t guc_sw_version;
> +};
> +
> +/*
> + * Log Init Config Types.
> + * The first word of the each TLV payload of guc_log_init_config_t contains one
> + * of the following enum values. This value determines how subsequent bytes are
> + * parsed to obtain the TLV information.
> + */
> +enum guc_log_lic_type_t {
> + /*
> + * GuC firmware version.
> + * Subsequent bytes of current log-init-config are parsed as per
> + * guc_lic_guc_sw_version_t structure layout.
> + */
> + GUC_LOG_LIC_TYPE_GUC_SW_VERSION = 0x1,
> +
> + /*
> + * TSC Frequency.
> + * Subsequent bytes of current log-init-config are parsed as per
> + * guc_lic_tsc_freq_t structure layout.
> + */
> + GUC_LOG_LIC_TYPE_TSC_FREQUENCY = 0x2,
> +
> + /*
> + * GuC device id.
> + * Subsequent bytes of current log-init-config are parsed as per
> + * guc_lic_guc_devid_t structure layout.
> + */
> + GUC_LOG_LIC_TYPE_GUC_DEVICE_ID = 0x3
> +};
> +
> +/* Log Init Config: GUC software version. */
> +struct guc_lic_guc_sw_version_t {
> + /* BR[31:16] Number of dwords in proceeding payload = 1. */
> + uint32_t size : 16;
> +
> + /*
> + * BR[15: 0] Log-init-config
> + * TLV type enum = GUC_LOG_LIC_TYPE_GUC_SW_VERSION.
> + */
> + uint32_t type : 16;
> +
> + /* 32 bit number representing the Guc’s software version. */
> + struct guc_sw_version_t guc_sw_version;
> +};
> +
> +/*
> + * Log Init Config Structure Version.
> + * Major-Minor is not a fractional number
> + * (i.e. Ver 1.3 would be older than 1.12)
> + */
> +struct guc_lic_format_version_t {
> + /*
> + * BR[15: 0] Log-Init-Config structure minor version.
> + * Must be GUC_LOG_FILE_FORMAT_VERSION_MINOR
> + */
> + uint32_t minor_version : 16;
> +
> + /*
> + * BR[31:16] Log-Init-Config structure major version.
> + * Must be GUC_LOG_FILE_FORMAT_VERSION_MAJOR
> + */
> + uint32_t major_version : 16;
> +};
> +
> +/* Log Init Config: GUC Device ID. */
> +struct guc_lic_guc_devid_t {
> + /* BR[31:16] Number of dwords in proceeding payload = 1. */
> + uint32_t size : 16;
> +
> + /*
> + * BR[15: 0] Log-init-config TLV type enum =
> + * GUC_LOG_LIC_TYPE_GUC_DEVICE_ID.
> + */
> + uint32_t type : 16;
> +
> + /*
> + * BR[31: 0] Guc device ID. Refer bspec symbol GUC_DEVICEID
> + * https://gfxspecs.intel.com/Predator/Home/Index/50668.
> + */
> + uint32_t guc_devid : 32;
> +};
> +
> +/* GuC Device ID. This is mandatory fw LFD data. */
> +struct guc_lfd_data_guc_devid_t {
> + /* GuC microcontroller device ID defined as per guc_lic_guc_devid_t. */
> + struct guc_lic_guc_devid_t guc_devid;
> +};
> +
> +/* Log Init Config: TSC Fequency. */
> +struct guc_lic_tsc_freq_t {
> + /* BR[31:16] Number of dwords in proceeding payload = 1. */
> + uint32_t size : 16;
> +
> + /*
> + * BR[15: 0] Log-init-config TLV type enum =
> + * GUC_LOG_LIC_TYPE_TSC_FREQUENCY.
> + */
> + uint32_t type : 16;
> +
> + /*
> + * 32 bit number representing frequency in kilohertz for all the
> + * timestamps being used in the log-entry.
> + */
> + uint32_t tsc_freq;
> +};
> +
> +/* GuC TSC Fequency. This is mandatory fw LFD data. */
> +struct guc_lfd_data_tsc_freq_t {
> + /*
> + * The frequency of timestamps used in guc logs as described in
> + * guc_lic_tsc_freq_t
> + */
> + struct guc_lic_tsc_freq_t tsc_freq;
> +};
> +
> +/*
> + * GuC Log-Init-Config structure.
> + * This is populated by the GUC at log init time and is located in the log
> + * buffer as per the Log Buffer Layout (In Memory). The array of guc log
> + * buffer states plus this structure must not exceed 4KB.
> + */
> +struct guc_log_init_config_t {
> + /*
> + * A magic number set by GuC to identify that this structure
> + * contains valid information: lic_magic = 0x8086900D.
> + * Used to verify the information in this structure is valid.
> + */
> + uint32_t lic_magic;
> +
> + /*
> + * The version of the this structure.
> + * Detail description is guc_lic_format_version_t
> + */
> + struct guc_lic_format_version_t lic_ver;
> +
> + /* Number of Dws the lic_data array contains. */
> + uint32_t lic_dw_size;
> +
> + /*
> + * Array of dwords representing a sequence of LIC TLVs types.
> + * See guc_log_lic_type_t enums
> + */
> + uint32_t lic_data[];
> +};
> +
> +/* GuC Log entry format Version 2. */
> +struct guc_log_format_version_2_t {
> + /* BR[31: 0] The GuC timestamp of the log event. */
> + uint32_t timestamp : 32;
> +
> + /* BR[19: 0] The Vf ID the log entry has been generated for. */
> + uint32_t vf_id : 20;
> +
> + /* BR[31:20] Reserved. */
> + uint32_t reserved_1 : 12;
> +
> + /* BR[14: 0] The GuC Event ID value for the log event. */
> + uint32_t event_id : 15;
> +
> + /* BR[15:15] Indicates if Event should be visible to Vf Host driver. */
> + uint32_t vf_visible : 1;
> +
> + /*
> + * BR[17:16] This field contains the verbosity level of the log entry,
> + * see the Log Verbosity section. This can then be used by the PF driver
> + * to filter the logs copied to a VF based on the verbosity requested by
> + * a VF.
> + */
> + uint32_t verbosity : 2;
> +
> + /* BR[31:18] Reserved. */
> + uint32_t reserved_2 : 14;
> +
> + /* BR[31: 0] The value of Parameter 1 of the log event. */
> + uint32_t parameter_1 : 32;
> +
> + /* BR[31: 0] The value of Parameter 2 of the log event. */
> + uint32_t parameter_2 : 32;
> +};
> +
> +/* GuC Log Buffer State. */
> +struct guc_log_buffer_state_t {
> + /*
> + * A marker set by the ukernel to identify the buffer state start
> + * location in a binary file containing the GuC log. This is used
> + * by log parsing tools. The Current values are:
> + *
> + * Log buffer
> + * Marker[0] 0XCABBA9E6,
> + * Marker[1] 0XDEADFEED
> + * Crashdump
> + * Marker[0] 0XCABBA9E6,
> + * Marker[1] 0x8086DEAD
> + * Error State Capture
> + * Marker[0] 0XCABBA9F7,
> + * Marker[1] 0XBEEFFEED
> + * Schema
> + * Marker[0] 0x808655DD,
> + * Marker[1] 0x8086EEBB.
> + * Note: The schema is never written to the memory by ukernel.
> + * Its an optional feature for KMD to embed schema in guclog file.
> + */
> + uint32_t Marker[2];
> +
> + /*
> + * BR[31: 0] This is the Last Byte Offset Location that was read by
> + * KMD. KMD will write to this and uKernel will read this.
> + */
> + uint32_t log_buf_rd_ptr : 32;
> +
> + /*
> + * BR[31: 0] This is the Byte Offset Location that will be written
> + * by uKernel.
> + */
> + uint32_t log_guc_wr_ptr : 32;
> +
> + /*
> + * BR[31: 0] Log buffer size.
> + * This is written by the KMD and specifies the size of the buffer
> + * in bytes
> + */
> + uint32_t log_buf_size : 32;
> +
> + /*
> + * BR[31: 0] This is written by ukernel to the byte offset of the
> + * next free entry in the buffer on log buffer half full or state
> + * capture notification.
> + */
> + uint32_t sampled_log_buf_wr_ptr : 32;
> +
> + /*
> + * BR[31: 0] This is the byte offset of location 1 byte after last
> + * valid guc log event entry written by Guc firmware before there
> + * was a wraparound.
> + * This field is updated by guc firmware and should be used by Host
> + * when copying buffer contents to file.
> + */
> + uint32_t log_guc_buff_wrap_offset : 32;
> +
> + /*
> + * BR[ 0: 0] uKernel sets this when log buffer is half full or when
> + * a flush has been requested by KMD through host2guc.
> + * uKernel will send GUC2HOST only if this bit is cleared. This is
> + * to avoid unnecessary interrupts from GuC.
> + */
> + uint32_t log_buf_flush_to_file : 1;
> +
> + /*
> + * BR[ 4: 1] uKernel increments this when log buffer overflows.
> + * This is initialized to 0 by KMD.
> + */
> + uint32_t buffer_full_cnt : 4;
> +
> + /* BR[31: 5] Reserved. */
> + uint32_t reserved : 27;
> +
> + /*
> + * BR[31: 0] The Guc-Log-Entry format version, a single integer.
> + * Current version is GUC_LOG_EVENT_ENTRY_FORMAT_VERSION
> + */
> + uint32_t version : 32;
> +};
> +
> +/* GuC Log Events Buffer. This is optional fw LFD data. */
> +struct guc_lfd_data_log_events_buf_t {
> + /* version of GuC log format of buffer */
> + uint32_t log_events_format_version;
> +
> + /*
> + * If log_format_version == 1, array of guc_log_format_version_1_t.
> + * If log_format_version == 2, array of guc_log_format_version_2_t.
> + * Dword size determined by guc_logfile_lfd_t.desc_dw_size - 1
> + */
> + uint32_t log_format_buf[];
> +};
> +
> +/* OS Version Information. This is mandatory host LFD data. */
> +struct guc_lfd_data_os_id_t {
> + /*
> + * enum values to identify the OS brand (1=Windows, 2=Linux, etc..).
> + * See guc_lfd_os_type_t for the range of types
> + */
> + uint32_t os_id;
> +
> + /*
> + * ASCII string containing OS build version information based on os_id.
> + * String is padded with null characters to ensure its DWORD aligned.
> + * Dword size determined by guc_logfile_lfd_t.desc_dw_size - 1
> + */
> + char build_version[];
> +};
> +
> +/* The type id for a Binary-Schema-Encoding record. */
> +enum guc_bse_record_types_t {
> + /*
> + * Event descriptor record.
> + * Subsequent bytes of the binary schema encoding are parsed as per
> + * guc_bse_event_t structure layout
> + */
> + GUC_BSE_RECORD_TYPES_EVENT_DESC = 0x41,
> +
> + /*
> + * Parameter descriptor record.
> + * Subsequent bytes of the binary schema encoding are parsed as per
> + * guc_bse_param_t structure layout
> + */
> + GUC_BSE_RECORD_TYPES_PARAM_DESC = 0x42,
> +
> + /*
> + * Time stamp record.
> + * Subsequent bytes of the binary schema encoding are parsed as per
> + * guc_bse_timestamp_t structure layout
> + */
> + GUC_BSE_RECORD_TYPES_TIMESTAMP = 0x43,
> +
> + /*
> + * Schema version record.
> + * Subsequent bytes of current binary schema descriptor are parsed as
> + * per guc_bse_schema_ver_t structure layout.
> + * This shall be the first record descriptor to appear in the
> + * binary-schema stream.
> + */
> + GUC_BSE_RECORD_TYPES_SCHEMA_VERSION_RECORD = 0x44,
> +
> + /*
> + * GuC Firmware version record.
> + * Subsequent bytes of the binary schema encoding are parsed as per
> + * guc_bse_fw_ver_t structure layout
> + */
> + GUC_BSE_RECORD_TYPES_FW_VERSION_RECORD = 0x45
> +};
> +
> +/* Binary Schema Encoding for the general log record. */
> +struct guc_bse_record_t {
> + /*
> + * 8 bit identifier for the type of binary schema record descriptor
> + * record being. This value must be one of guc_bse_record_types_t
> + */
> + uint8_t type;
> +
> + /*
> + * Stream of bytes that contain the encoded payload for the
> + * corresponding record type. Bytes are parsed based on ‘type’
> + * structure
> + */
> + uint8_t enc_payload[];
> +};
> +
> +/*
> + * Binary Schema Encoding Stream. This structure encapsulates a stream of
> + * guc-log-translation-schema for all log record types.
> + */
> +struct guc_bse_stream_t {
> + /* A stream of one or more guc_bse_record_t encodings. */
> + struct guc_bse_record_t bse_records;
> +};
> +
> +/* GuC Schema Binary. This is optional host LFD data. */
> +struct guc_lfd_data_binary_schema_t {
> + /*
> + * Binary schema encoding followed by any byte padding to align to
> + * dword size. Dword size determined by guc_logfile_lfd_t.desc_dw_size
> + */
> + struct guc_bse_stream_t binary_schema;
> +};
> +
> +#endif
> diff --git a/tools/lfd_default.h b/tools/lfd_default.h
> new file mode 100644
> index 000000000..aa0d3a834
> --- /dev/null
> +++ b/tools/lfd_default.h
> @@ -0,0 +1,39 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2016-2019 Intel Corporation
> + */
> +
> +#ifndef _INTEL_GUC_LFD_DEFAULT_H_
> +#define _INTEL_GUC_LFD_DEFAULT_H_
> +
> +#include "lfd.h"
> +
> +const struct guc_logfile_lfd_t default_guc_logfile_lfd = {
> + .magic = GUC_LOGFILE_LFD_MAGIC,
> +};
> +
> +const struct guc_logfile_t default_guc_logfile = {
> + .magic = LFD_DRIVER_KEY_STREAMING,
> + .version = {
> + .minor_version = GUC_LOG_FILE_FORMAT_VERSION_MINOR,
> + .major_version = GUC_LOG_FILE_FORMAT_VERSION_MAJOR
> + }
> +};
> +
> +const struct guc_lic_guc_devid_t default_guc_lic_guc_devid = {
> + .type = GUC_LOG_LIC_TYPE_GUC_DEVICE_ID,
> + .size = 1,
> + .guc_devid = 0
> +};
> +
> +const struct guc_lic_tsc_freq_t default_guc_lic_tsc_freq = {
> + .type = GUC_LOG_LIC_TYPE_TSC_FREQUENCY,
> + .size = 1,
> + .tsc_freq = 0
> +};
> +
> +const struct guc_lfd_data_log_events_buf_t default_lfd_data_log_events_buf = {
> + .log_events_format_version = GUC_LOG_EVENT_ENTRY_FORMAT_VERSION,
> +};
> +
> +#endif
> diff --git a/tools/meson.build b/tools/meson.build
> index de866c392..6fadc40fa 100644
> --- a/tools/meson.build
> +++ b/tools/meson.build
> @@ -46,6 +46,7 @@ tools_progs = [
> 'intel_gvtg_test',
> 'dpcd_reg',
> 'lsgpu',
> + 'xe_guc_logger',
> ]
> tool_deps = igt_deps
> tool_deps += zlib
> diff --git a/tools/xe_guc_logger.c b/tools/xe_guc_logger.c
> new file mode 100644
> index 000000000..a8b5551dd
> --- /dev/null
> +++ b/tools/xe_guc_logger.c
> @@ -0,0 +1,615 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2016-2019 Intel Corporation
> + */
> +
> +#include <assert.h>
> +#include <fcntl.h>
> +#include <regex.h>
> +#include <stdbool.h>
> +#include <stddef.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <zlib.h>
> +#include <arpa/inet.h>
> +
> +#include "igt.h"
> +#include "lfd.h"
> +#include "lfd_default.h"
> +
> +#define PR printf("@ %s:%d\n", __func__, __LINE__)
> +
> +#define DEFAULT_FILE_LEN (256 * 1024 * 1024)
> +#define LINE_BUF_SIZE (16 * 1024 * 1024)
> +
> +/* Optional Space */
> +#define SPC_O "[ \t]*"
> +/* Required Space */
> +#define SPC ": "
> +/* Optional Non-Space */
> +#define NSPC_O "([^:]*)"
> +/* Required Non-Space */
> +#define NSPC "([^:]+)"
> +#define BEG "^" SPC_O
> +#define REQ_FIELD NSPC SPC
> +#define OPT_FIELD NSPC_O SPC_O
> +#define END SPC_O "$"
> +
> +#define REGEX_NON_SPACE_GROUPS BEG REQ_FIELD OPT_FIELD OPT_FIELD OPT_FIELD END
> +#define REGEX_NON_SPACE_GROUPS_COUNT 4
> +
> +#define INDEX_KEY 1
> +#define INDEX_VALUE 2
> +
> +#define OS_VERSION_FILENAME "/proc/version"
> +#define DEFAULT_GUC_LOG_FILENAME "guc_log"
> +#define DEFAULT_OUTPUT_FILE_NAME "guc_log_dump.dat"
> +
> +static struct guc_log_buffer_entry_list {
> + uint32_t key[2];
> + uint32_t offset;
> + uint32_t rd_ptr;
> + uint32_t wr_ptr;
> + uint32_t buf_size;
> +} entry_list[GUC_LOG_BUFFER_STATE_HEADER_ENTRY_COUNT] = {
> + {
> + {
> + LFD_LOG_BUFFER_MARKER_1V2,
> + LFD_LOG_BUFFER_MARKER_2
> + }
> + },
> + {
> + {
> + LFD_LOG_BUFFER_MARKER_1V2,
> + LFD_CRASH_DUMP_BUFFER_MARKER_2
> + }
> + },
> + {
> + {
> + LFD_STATE_CAPTURE_BUFFER_MARKER_1V2,
> + LFD_STATE_CAPTURE_BUFFER_MARKER_2
> + }
> + },
> + {
> + {
> + GUC_LOG_INIT_CONFIG_LIC_MAGIC,
> + ((GUC_LOG_INIT_CONFIG_FORMAT_VERSION_MAJOR << 16)
> + | GUC_LOG_INIT_CONFIG_FORMAT_VERSION_MINOR)
> + }
> + },
> +};
> +
> +regex_t regex;
> +int verbose = 0;
> +struct guc_sw_version_t fw_ver;
> +struct guc_lic_tsc_freq_t fw_tsc_freq;
> +struct guc_lic_guc_devid_t fw_dev_id;
> +struct guc_log_buffer_state_t log_buf_state;
> +char *out_filename = NULL;
> +char *guc_log_filename = NULL;
> +
> +/*
> + * Header example:
> + * **** GuC Log ****
> + * CS reference clock: 19200000
> + * GuC firmware: i915/mtl_guc_70.bin
> + * GuC version: 70.36.0 (wanted 70.29.2)
> + * Kernel timestamp: 0x1DE9CFB690A4 [32890049433764]
> + * GuC timestamp: 0x325FF4AA2 [13522389666]
> + * Log level: 3
> + * [LOG].length: 0x113000
> + * [LOG].data: <ASCII85 DATA>
> + */
> +#define TAG_GUC_LOG_START "**** GuC Log ****"
> +
> +enum TAG_TYPE {
> + TAG_GUC_FIRMWARE = 0,
> + TAG_GUC_VERSION,
> + TAG_CS_REFERENCE_CLOCK,
> + TAG_KERNEL_TIMESTAMP,
> + TAG_GUC_TIMESTAMP,
> + TAG_LOG_LEVEL,
> + TAG_LOG_LENGTH,
> + TAG_LOG_DATA,
> + TAG_MAX
> +};
> +
> +static const char *tags[TAG_MAX] = {
> + "GuC firmware",
> + "GuC version",
> + "CS reference clock",
> + "Kernel timestamp",
> + "GuC timestamp",
> + "Log level",
> + "[LOG].length",
> + "[LOG].data: " /* This tag only being matched by strcmp, so add ": " */
> +};
> +
> +static char tag_values[TAG_MAX - 1][80];
> +
> +static int zlib_inflate(uint32_t **ptr, int len)
> +{
> + struct z_stream_s zstream;
> + void *out;
> +
> + memset(&zstream, 0, sizeof(zstream));
> +
> + zstream.next_in = (unsigned char *)*ptr;
> + zstream.avail_in = 4 * len;
> +
> + if (inflateInit(&zstream) != Z_OK)
> + return 0;
> +
> + out = malloc(128 * 4096); /* approximate obj size */
> + zstream.next_out = out;
> + zstream.avail_out = 128 * 4096;
> +
> + do {
> + switch (inflate(&zstream, Z_SYNC_FLUSH)) {
> + case Z_STREAM_END:
> + goto end;
> + case Z_OK:
> + break;
> + default:
> + inflateEnd(&zstream);
> + return 0;
> + }
> +
> + if (zstream.avail_out)
> + break;
> +
> + out = realloc(out, 2 * zstream.total_out);
> + if (out == NULL) {
> + inflateEnd(&zstream);
> + return 0;
> + }
> +
> + zstream.next_out = (unsigned char *)out + zstream.total_out;
> + zstream.avail_out = zstream.total_out;
> + } while (1);
> +end:
> + inflateEnd(&zstream);
> + free(*ptr);
> + *ptr = out;
> + return zstream.total_out / 4;
> +}
> +
> +static unsigned long
> +ascii85_decode(char *in, uint32_t **out)
> +{
> + unsigned long len = 0, size = 1024;
> + bool inflated;
> +
> + *out = realloc(*out, sizeof(uint32_t) * size);
> + if (*out == NULL)
> + return 0;
> +
> + inflated = (in[0] == ':');
> +
> + while (*in >= '!' && *in <= 'z') {
> + uint32_t v = 0;
> +
> + if (len == size) {
> + size *= 2;
> + *out = realloc(*out, sizeof(uint32_t) * size);
> + if (*out == NULL)
> + return 0;
> + }
> +
> + if (*in == 'z') {
> + in++;
> + } else {
> + v += in[0] - 33; v *= 85;
> + v += in[1] - 33; v *= 85;
> + v += in[2] - 33; v *= 85;
> + v += in[3] - 33; v *= 85;
> + v += in[4] - 33;
> + in += 5;
> + }
> + (*out)[len++] = v;
> + }
> +
> + if (!inflated)
> + return len;
> +
> + return zlib_inflate(out, len);
> +}
> +
> +static enum TAG_TYPE get_tag_entry(char *line)
> +{
> + int i;
> + regmatch_t match[REGEX_NON_SPACE_GROUPS_COUNT];
> +
> + if (strncmp(tags[TAG_LOG_DATA], line, strlen(tags[TAG_LOG_DATA])) == 0)
> + return TAG_LOG_DATA;
> +
> + if ((regexec(®ex, line, REGEX_NON_SPACE_GROUPS_COUNT, match, 0)) == 0) {
> + char *key = NULL, *value = NULL;
> +
> + if (match[INDEX_KEY].rm_so >= 0) {
> + key = &line[match[INDEX_KEY].rm_so];
> + line[match[INDEX_KEY].rm_eo] = '\0';
> + }
> + if (match[INDEX_VALUE].rm_so >= 0) {
> + value = &line[match[INDEX_VALUE].rm_so];
> + line[match[INDEX_VALUE].rm_eo] = '\0';
> + }
> +
> + for (i = 0; i < TAG_LOG_DATA; i++) {
> + if (key && value && strcmp(tags[i], key) == 0) {
> + strcpy(tag_values[i], value);
> + return i;
> + }
> + }
> + }
> + return TAG_MAX;
> +}
> +
> +static int load_guc_log(uint32_t **bin_buf)
> +{
> + FILE *fd;
> + int log_len = 0;
> + enum TAG_TYPE type;
> + char *fname;
> + char *line = (char *)malloc(LINE_BUF_SIZE);
> + int i = 0;
> +
> + igt_assert_f(line, "Out of memory\n");
> +
> + fname = guc_log_filename ? : (char *)DEFAULT_GUC_LOG_FILENAME;
> + if (verbose)
> + igt_info("Loading %s\n", fname);
> +
> + fd = fopen(fname, "r");
> + igt_assert_f(fd, "couldn't open the file: %s\n", fname);
> +
> + while (fgets(line, LINE_BUF_SIZE, fd)) {
> + if (i == 0) {
> + /* Require line 0 is start tag */
> + igt_assert_f(!strncmp(line, TAG_GUC_LOG_START,
> + sizeof(TAG_GUC_LOG_START) - 1),
> + "Invalid guc log\n");
> + }
> + type = get_tag_entry(line);
> + if (type == TAG_LOG_DATA) {
> + char *encoded = &line[strlen(tags[TAG_LOG_DATA])];
> +
> + log_len = ascii85_decode(encoded, bin_buf);
> + if (verbose)
> + igt_info("Ascii85 decoded length: 0x%x\n", log_len);
> + }
> + i++;
> + }
> +
> + if (ferror(fd) != 0)
> + printf("Failed to read file, error: %d\n", ferror(fd));
> +
> + fclose(fd);
> + free(line);
> + if (guc_log_filename)
> + free(guc_log_filename);
> +
> + return log_len;
> +}
> +
> +static int add_lfd_headr(char *buf)
> +{
> + int len;
> +
> + igt_assert(buf);
> +
> + len = sizeof(default_guc_logfile_lfd);
> + memcpy(buf, &default_guc_logfile_lfd, len);
> +
> + return len;
> +}
> +
> +static int add_payload(char *buf, uint32_t data_len, void *data)
> +{
> + struct guc_logfile_lfd_t *lfd = (struct guc_logfile_lfd_t *)buf;
> +
> + igt_assert(buf);
> +
> + /* make length DW aligned */
> + lfd->desc_dw_size = data_len / 4;
> + if (data_len % 4)
> + lfd->desc_dw_size++;
> +
> + if (lfd->data != data)
> + memcpy(lfd->data, data, data_len);
> +
> + return lfd->desc_dw_size * 4;
> +}
> +
> +static int add_typed_payload(char *buf, uint32_t type, uint32_t data_len, void *data)
> +{
> + int len;
> + struct guc_logfile_lfd_t *lfd = (struct guc_logfile_lfd_t *)buf;
> +
> + igt_assert(buf);
> +
> + len = add_lfd_headr(buf);
> + lfd->desc_type = type;
> + len += add_payload(buf, data_len, data);
> +
> + return len;
> +}
> +
> +static int add_sw_ver(char *buf)
> +{
> + return add_typed_payload(buf, GUC_LFD_TYPE_FW_VERSION,
> + sizeof(fw_ver), &fw_ver);
> +}
> +
> +static int add_guc_device_id(char *buf)
> +{
> + return add_typed_payload(buf, GUC_LFD_TYPE_GUC_DEVICE_ID,
> + sizeof(fw_dev_id),
> + (void *)&fw_dev_id);
> +}
> +
> +static int add_os_id(char *buf, uint32_t os_id)
> +{
> + int len;
> + FILE *f;
> + char *temp;
> +
> + temp = malloc(BUFSIZ);
> + assert(buf);
> +
> + /* Get host build version */
> + f = fopen(OS_VERSION_FILENAME, "r");
> + fgets(temp, BUFSIZ, f);
> + fclose(f);
> +
> + /* Remove trailing newline */
> + temp[strcspn(temp, "\n\r")] = 0;
> + len = add_typed_payload(buf, GUC_LFD_TYPE_OS_ID, strlen(temp), temp);
> + free(temp);
> +
> + return len;
> +}
> +
> +static int add_log_event(char *buf, char *log_bin)
> +{
> + int len;
> + char *data;
> + uint32_t data_len;
> + struct guc_lfd_data_log_events_buf_t *events_buf;
> + struct guc_logfile_lfd_t *lfd = (struct guc_logfile_lfd_t *)buf;
> + struct guc_log_buffer_entry_list *entry;
> +
> + entry = &entry_list[GUC_LOG_BUFFER_STATE_HEADER_ENTRY_LOG];
> +
> + /* Skip empty log */
> + if (entry->rd_ptr == entry->wr_ptr)
> + return 0;
> +
> + len = add_lfd_headr(buf);
> + lfd = (struct guc_logfile_lfd_t *)buf;
> +
> + lfd->desc_type = GUC_LFD_TYPE_LOG_EVENTS_BUFFER;
> + events_buf = (struct guc_lfd_data_log_events_buf_t *)&lfd->data;
> + events_buf->log_events_format_version = log_buf_state.version;
> +
> + data = log_bin + entry->offset + entry->rd_ptr;
> + if (entry->rd_ptr < entry->wr_ptr) {
> + data_len = entry->wr_ptr - entry->rd_ptr;
> + memcpy(events_buf->log_format_buf, data, data_len);
> + } else {
> + /* Copy rd to buf end 1st */
> + data_len = entry->buf_size - entry->rd_ptr;
> + memcpy(events_buf->log_format_buf, data, data_len);
> +
> + /* Copy buf start to wr */
> + data = &log_bin[entry->offset];
> + memcpy(&events_buf->log_format_buf[data_len / 4], data, entry->wr_ptr);
> + data_len += entry->wr_ptr;
> + }
> +
> + if (verbose)
> + igt_info("log event data length: 0x%x\n", data_len);
> +
> + /* make length DW aligned */
> + lfd->desc_dw_size = data_len / 4;
> + if (data_len % 4)
> + lfd->desc_dw_size++;
> +
> + /* Addup log_events_format_version size */
> + lfd->desc_dw_size++;
> +
> + return len + lfd->desc_dw_size * 4;
> +}
> +
> +static void loop_log_init(struct guc_log_init_config_t *init)
> +{
> + int i;
> + struct guc_lic_tsc_freq_t *p;
> +
> + assert(init);
> + p = (struct guc_lic_tsc_freq_t *)init->lic_data;
> +
> + for (i = 0; i < init->lic_dw_size; i += 2) {
> + switch (p->type) {
> + case GUC_LOG_LIC_TYPE_GUC_SW_VERSION:
> + fw_ver = ((struct guc_lic_guc_sw_version_t *)p)->guc_sw_version;
> + break;
> + case GUC_LOG_LIC_TYPE_TSC_FREQUENCY:
> + fw_dev_id = *(struct guc_lic_guc_devid_t *)p;
> + break;
> + case GUC_LOG_LIC_TYPE_GUC_DEVICE_ID:
> + fw_tsc_freq = *(struct guc_lic_tsc_freq_t *)p;
> + fw_tsc_freq.type = GUC_LOG_LIC_TYPE_TSC_FREQUENCY;
> + break;
> + default:
> + break;
> + }
> + p++;
> + }
> +}
> +
> +static void load_log_buffer(uint32_t *guc_log, int len)
> +{
> + int i = 0;
> + uint32_t offset = GUC_LOG_BUFFER_STATE_HEADER_LENGTH;
> + struct guc_log_buffer_state_t *p = (struct guc_log_buffer_state_t *)guc_log;
> + struct guc_log_init_config_t *init;
> +
> + assert(guc_log);
> +
> + while (p) {
> + for (i = 0; i < GUC_LOG_BUFFER_STATE_HEADER_ENTRY_COUNT; i++) {
> + if (p->Marker[0] == entry_list[i].key[0] &&
> + p->Marker[1] == entry_list[i].key[1]) {
> + entry_list[i].offset = offset;
> + entry_list[i].rd_ptr = p->log_buf_rd_ptr;
> + entry_list[i].wr_ptr = p->log_guc_wr_ptr;
> + entry_list[i].buf_size = p->log_buf_size;
> +
> + if (i == GUC_LOG_BUFFER_STATE_HEADER_ENTRY_LOG)
> + log_buf_state = *p;
> +
> + if (i != GUC_LOG_BUFFER_STATE_HEADER_ENTRY_INIT) {
> + offset += p->log_buf_size;
> + p++;
> + } else {
> + int init_size_with_data;
> +
> + init = (struct guc_log_init_config_t *)p;
> + /* Load log init config */
> + loop_log_init(init);
> + init_size_with_data = init->lic_dw_size * 4 +
> + sizeof(struct guc_log_init_config_t);
> + offset += init_size_with_data;
> + p = (struct guc_log_buffer_state_t *)
> + ((char *)p + init_size_with_data);
> + }
> + }
> + }
> + if (i >= GUC_LOG_BUFFER_STATE_HEADER_ENTRY_COUNT)
> + break;
> + }
> +}
> +
> +static void save_output_file(char *buf, uint32_t *guc_log_bin)
> +{
> + int ret, index = 0;
> + char *bin = (char *)guc_log_bin;
> + struct guc_logfile_t *guc_logfile;
> + struct guc_log_buffer_entry_list *entry;
> +
> + char *fname = out_filename ? : (char *)DEFAULT_OUTPUT_FILE_NAME;
> + int fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0600);
> +
> + igt_assert_f(fd >= 0, "couldn't open the output file\n");
> +
> + if (verbose)
> + igt_info("Creating binary file: %s\n", fname);
> +
> + guc_logfile = (struct guc_logfile_t *)buf;
> + *guc_logfile = default_guc_logfile;
> +
> + index = offsetof(struct guc_logfile_t, lfd_stream);
> + index += add_sw_ver(&buf[index]);
> + index += add_guc_device_id(&buf[index]);
> + index += add_typed_payload(&buf[index], GUC_LFD_TYPE_TSC_FREQUENCY,
> + sizeof(fw_tsc_freq), (void *)&fw_tsc_freq);
> + index += add_os_id(&buf[index], GUC_LFD_OS_TYPE_OSID_LIN);
> + index += add_log_event(&buf[index], bin);
> +
> + /* For Crash dump, rd/wr ptr has no effect, do simple payload add */
> + entry = &entry_list[GUC_LOG_BUFFER_STATE_HEADER_ENTRY_CRASH];
> + if (entry->buf_size) {
> + index += add_typed_payload(&buf[index], GUC_LFD_TYPE_FW_CRASH_DUMP,
> + entry->buf_size, &bin[entry->offset]);
> + }
> +
> + ret = write(fd, buf, index);
> + if (ret != index)
> + igt_info("Couldn't save output file. errno: %d\n", errno);
> +
> + close(fd);
> +
> + if (verbose)
> + igt_info("Binary file saved.\n");
> +
> + if (out_filename)
> + free(out_filename);
> +}
> +
> +static int parse_options(int opt, int opt_index, void *data)
> +{
> + switch (opt) {
> + case 'i':
> + guc_log_filename = strdup(optarg);
> + igt_assert_f(guc_log_filename, "Couldn't allocate the input filename\n");
> + igt_debug("logs to be read %s\n", guc_log_filename);
> + break;
> + case 'o':
> + out_filename = strdup(optarg);
> + igt_assert_f(out_filename, "Couldn't allocate the output filename\n");
> + igt_debug("logs to be stored in file %s\n", out_filename);
> + break;
> + case 'v':
> + verbose = 1;
> + break;
> + }
> +
> + return IGT_OPT_HANDLER_SUCCESS;
> +}
> +
> +static void process_command_line(int argc, char **argv)
> +{
> + static struct option long_options[] = {
> + {"outputfile", required_argument, 0, 'o'},
> + {"inputfile", required_argument, 0, 'i'},
> + {"verbosity", optional_argument, 0, 'v'},
> + { 0, 0, 0, 0 }
> + };
> +
> + const char *help =
> + " -i --inputfile=name\tname of the guc log file, including the path\n"
> + " -o --outputfile=name\tname of the output file, including the location, where logs will be stored\n"
> + " -v --verbosity=level verbosity level of output\n";
> +
> + igt_simple_init_parse_opts(&argc, argv, "o:i:v", long_options,
> + help, parse_options, NULL);
> +}
> +
> +int main(int argc, char **argv)
> +{
> + int decode_len;
> + char *buf;
> + uint32_t *guc_log_bin = NULL;
> +
> + buf = malloc(DEFAULT_FILE_LEN);
> + assert(buf);
> + memset(buf, 0, DEFAULT_FILE_LEN);
> + guc_log_bin = NULL;
> +
> + regcomp(®ex, REGEX_NON_SPACE_GROUPS, REG_EXTENDED | REG_NEWLINE);
> +
> + process_command_line(argc, argv);
> +
> + /* guc_log_bin will be alloc by load_guc_log/ascii85_decode */
> + decode_len = load_guc_log(&guc_log_bin);
> +
> + /* Only keep hex value part for timestamp string */
> + tag_values[TAG_KERNEL_TIMESTAMP][strcspn(tag_values[TAG_KERNEL_TIMESTAMP], " ")] = 0;
> + tag_values[TAG_GUC_TIMESTAMP][strcspn(tag_values[TAG_GUC_TIMESTAMP], " ")] = 0;
> +
> + load_log_buffer(guc_log_bin, decode_len);
> +
> + save_output_file(buf, guc_log_bin);
> +
> + free(buf);
> + free(guc_log_bin);
> + regfree(®ex);
> + igt_exit();
> +
> + return 0;
> +}
> +
More information about the igt-dev
mailing list