diff --git a/src/amd/Makefile.sources b/src/amd/Makefile.sources index b14ddb02cc7..4f8dab2c640 100644 --- a/src/amd/Makefile.sources +++ b/src/amd/Makefile.sources @@ -44,6 +44,8 @@ AMD_COMMON_FILES = \ common/ac_gpu_info.h \ common/ac_surface.c \ common/ac_surface.h \ + common/ac_rgp.c \ + common/ac_rgph \ common/ac_rtld.c \ common/ac_rtld.h \ common/ac_shader_args.c \ diff --git a/src/amd/common/ac_rgp.c b/src/amd/common/ac_rgp.c new file mode 100644 index 00000000000..9e009b72d0a --- /dev/null +++ b/src/amd/common/ac_rgp.c @@ -0,0 +1,663 @@ +/* + * Copyright 2020 Advanced Micro Devices, Inc. + * Copyright © 2020 Valve Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include "ac_rgp.h" + +#include "util/macros.h" +#include "util/os_misc.h" +#include "util/os_time.h" +#include "util/u_process.h" +#include "util/u_math.h" + +#include "ac_sqtt.h" +#include "ac_gpu_info.h" +#include "drm-uapi/amdgpu_drm.h" + +#include +#include +#include + +#define SQTT_FILE_MAGIC_NUMBER 0x50303042 +#define SQTT_FILE_VERSION_MAJOR 1 +#define SQTT_FILE_VERSION_MINOR 4 + +#define SQTT_GPU_NAME_MAX_SIZE 256 +#define SQTT_MAX_NUM_SE 32 +#define SQTT_SA_PER_SE 2 + +enum sqtt_version +{ + SQTT_VERSION_NONE = 0x0, + SQTT_VERSION_1_0 = 0x1, + SQTT_VERSION_1_1 = 0x2, + SQTT_VERSION_2_0 = 0x3, /* GFX6 */ + SQTT_VERSION_2_1 = 0x4, /* GFX7 */ + SQTT_VERSION_2_2 = 0x5, /* GFX8 */ + SQTT_VERSION_2_3 = 0x6, /* GFX9 */ + SQTT_VERSION_2_4 = 0x7 /* GFX10 */ +}; + +/** + * SQTT chunks. + */ +enum sqtt_file_chunk_type +{ + SQTT_FILE_CHUNK_TYPE_ASIC_INFO, + SQTT_FILE_CHUNK_TYPE_SQTT_DESC, + SQTT_FILE_CHUNK_TYPE_SQTT_DATA, + SQTT_FILE_CHUNK_TYPE_API_INFO, + SQTT_FILE_CHUNK_TYPE_ISA_DATABASE, + SQTT_FILE_CHUNK_TYPE_QUEUE_EVENT_TIMINGS, + SQTT_FILE_CHUNK_TYPE_CLOCK_CALIBRATION, + SQTT_FILE_CHUNK_TYPE_CPU_INFO, + SQTT_FILE_CHUNK_TYPE_SPM_DB, + SQTT_FILE_CHUNK_TYPE_CODE_OBJECT_DATABASE, + SQTT_FILE_CHUNK_TYPE_CODE_OBJECT_LOADER_EVENTS, + SQTT_FILE_CHUNK_TYPE_PSO_CORRELATION, + SQTT_FILE_CHUNK_TYPE_INSTRUMENTATION_TABLE, + SQTT_FILE_CHUNK_TYPE_COUNT +}; + +struct sqtt_file_chunk_id { + enum sqtt_file_chunk_type type : 8; + int32_t index : 8; + int32_t reserved : 16; +}; + +struct sqtt_file_chunk_header { + struct sqtt_file_chunk_id chunk_id; + uint16_t minor_version; + uint16_t major_version; + int32_t size_in_bytes; + int32_t padding; +}; + +/** + * SQTT file header. + */ +struct sqtt_file_header_flags { + union { + struct { + int32_t is_semaphore_queue_timing_etw : 1; + int32_t no_queue_semaphore_timestamps : 1; + int32_t reserved : 30; + }; + + uint32_t value; + }; +}; + +struct sqtt_file_header { + uint32_t magic_number; + uint32_t version_major; + uint32_t version_minor; + struct sqtt_file_header_flags flags; + int32_t chunk_offset; + int32_t second; + int32_t minute; + int32_t hour; + int32_t day_in_month; + int32_t month; + int32_t year; + int32_t day_in_week; + int32_t day_in_year; + int32_t is_daylight_savings; +}; + +static_assert(sizeof(struct sqtt_file_header) == 56, "sqtt_file_header doesn't match RGP spec"); + +static void ac_sqtt_fill_header(struct sqtt_file_header *header) +{ + struct tm *timep, result; + time_t raw_time; + + header->magic_number = SQTT_FILE_MAGIC_NUMBER; + header->version_major = SQTT_FILE_VERSION_MAJOR; + header->version_minor = SQTT_FILE_VERSION_MINOR; + header->flags.value = 0; + header->flags.is_semaphore_queue_timing_etw = 1; + header->flags.no_queue_semaphore_timestamps = 0; + header->chunk_offset = sizeof(*header); + + time(&raw_time); + timep = os_localtime(&raw_time, &result); + + header->second = timep->tm_sec; + header->minute = timep->tm_min; + header->hour = timep->tm_hour; + header->day_in_month = timep->tm_mday; + header->month = timep->tm_mon; + header->year = timep->tm_year; + header->day_in_week = timep->tm_wday; + header->day_in_year = timep->tm_yday; + header->is_daylight_savings = timep->tm_isdst; +} + +/** + * SQTT CPU info. + */ +struct sqtt_file_chunk_cpu_info { + struct sqtt_file_chunk_header header; + uint32_t vendor_id[4]; + uint32_t processor_brand[12]; + uint32_t reserved[2]; + uint64_t cpu_timestamp_freq; + uint32_t clock_speed; + uint32_t num_logical_cores; + uint32_t num_physical_cores; + uint32_t system_ram_size; +}; + +static_assert(sizeof(struct sqtt_file_chunk_cpu_info) == 112, + "sqtt_file_chunk_cpu_info doesn't match RGP spec"); + +static void ac_sqtt_fill_cpu_info(struct sqtt_file_chunk_cpu_info *chunk) +{ + uint64_t system_ram_size = 0; + + chunk->header.chunk_id.type = SQTT_FILE_CHUNK_TYPE_CPU_INFO; + chunk->header.chunk_id.index = 0; + chunk->header.major_version = 0; + chunk->header.minor_version = 0; + chunk->header.size_in_bytes = sizeof(*chunk); + + chunk->cpu_timestamp_freq = 1000000000; /* tick set to 1ns */ + + /* TODO: fill with real info. */ + + strncpy((char *)chunk->vendor_id, "Unknown", sizeof(chunk->vendor_id)); + strncpy((char *)chunk->processor_brand, "Unknown", sizeof(chunk->processor_brand)); + chunk->clock_speed = 0; + chunk->num_logical_cores = 0; + chunk->num_physical_cores = 0; + + chunk->system_ram_size = 0; + if (os_get_total_physical_memory(&system_ram_size)) + chunk->system_ram_size = system_ram_size / (1024 * 1024); +} + +/** + * SQTT ASIC info. + */ +enum sqtt_file_chunk_asic_info_flags +{ + SQTT_FILE_CHUNK_ASIC_INFO_FLAG_SC_PACKER_NUMBERING = (1 << 0), + SQTT_FILE_CHUNK_ASIC_INFO_FLAG_PS1_EVENT_TOKENS_ENABLED = (1 << 1) +}; + +enum sqtt_gpu_type +{ + SQTT_GPU_TYPE_UNKNOWN = 0x0, + SQTT_GPU_TYPE_INTEGRATED = 0x1, + SQTT_GPU_TYPE_DISCRETE = 0x2, + SQTT_GPU_TYPE_VIRTUAL = 0x3 +}; + +enum sqtt_gfxip_level +{ + SQTT_GFXIP_LEVEL_NONE = 0x0, + SQTT_GFXIP_LEVEL_GFXIP_6 = 0x1, + SQTT_GFXIP_LEVEL_GFXIP_7 = 0x2, + SQTT_GFXIP_LEVEL_GFXIP_8 = 0x3, + SQTT_GFXIP_LEVEL_GFXIP_8_1 = 0x4, + SQTT_GFXIP_LEVEL_GFXIP_9 = 0x5, + SQTT_GFXIP_LEVEL_GFXIP_10_1 = 0x7, +}; + +enum sqtt_memory_type +{ + SQTT_MEMORY_TYPE_UNKNOWN = 0x0, + SQTT_MEMORY_TYPE_DDR = 0x1, + SQTT_MEMORY_TYPE_DDR2 = 0x2, + SQTT_MEMORY_TYPE_DDR3 = 0x3, + SQTT_MEMORY_TYPE_DDR4 = 0x4, + SQTT_MEMORY_TYPE_GDDR3 = 0x10, + SQTT_MEMORY_TYPE_GDDR4 = 0x11, + SQTT_MEMORY_TYPE_GDDR5 = 0x12, + SQTT_MEMORY_TYPE_GDDR6 = 0x13, + SQTT_MEMORY_TYPE_HBM = 0x20, + SQTT_MEMORY_TYPE_HBM2 = 0x21, + SQTT_MEMORY_TYPE_HBM3 = 0x22, +}; + +struct sqtt_file_chunk_asic_info { + struct sqtt_file_chunk_header header; + uint64_t flags; + uint64_t trace_shader_core_clock; + uint64_t trace_memory_clock; + int32_t device_id; + int32_t device_revision_id; + int32_t vgprs_per_simd; + int32_t sgprs_per_simd; + int32_t shader_engines; + int32_t compute_unit_per_shader_engine; + int32_t simd_per_compute_unit; + int32_t wavefronts_per_simd; + int32_t minimum_vgpr_alloc; + int32_t vgpr_alloc_granularity; + int32_t minimum_sgpr_alloc; + int32_t sgpr_alloc_granularity; + int32_t hardware_contexts; + enum sqtt_gpu_type gpu_type; + enum sqtt_gfxip_level gfxip_level; + int32_t gpu_index; + int32_t gds_size; + int32_t gds_per_shader_engine; + int32_t ce_ram_size; + int32_t ce_ram_size_graphics; + int32_t ce_ram_size_compute; + int32_t max_number_of_dedicated_cus; + int64_t vram_size; + int32_t vram_bus_width; + int32_t l2_cache_size; + int32_t l1_cache_size; + int32_t lds_size; + char gpu_name[SQTT_GPU_NAME_MAX_SIZE]; + float alu_per_clock; + float texture_per_clock; + float prims_per_clock; + float pixels_per_clock; + uint64_t gpu_timestamp_frequency; + uint64_t max_shader_core_clock; + uint64_t max_memory_clock; + uint32_t memory_ops_per_clock; + enum sqtt_memory_type memory_chip_type; + uint32_t lds_granularity; + uint16_t cu_mask[SQTT_MAX_NUM_SE][SQTT_SA_PER_SE]; + char reserved1[128]; + char padding[4]; +}; + +static_assert(sizeof(struct sqtt_file_chunk_asic_info) == 720, + "sqtt_file_chunk_asic_info doesn't match RGP spec"); + +static enum sqtt_gfxip_level ac_chip_class_to_sqtt_gfxip_level(enum chip_class chip_class) +{ + switch (chip_class) { + case GFX6: + return SQTT_GFXIP_LEVEL_GFXIP_6; + case GFX7: + return SQTT_GFXIP_LEVEL_GFXIP_7; + case GFX8: + return SQTT_GFXIP_LEVEL_GFXIP_8; + case GFX9: + return SQTT_GFXIP_LEVEL_GFXIP_9; + case GFX10: + return SQTT_GFXIP_LEVEL_GFXIP_10_1; + default: + unreachable("Invalid chip class"); + } +} + +static enum sqtt_memory_type ac_vram_type_to_sqtt_memory_type(uint32_t vram_type) +{ + switch (vram_type) { + case AMDGPU_VRAM_TYPE_UNKNOWN: + return SQTT_MEMORY_TYPE_UNKNOWN; + case AMDGPU_VRAM_TYPE_DDR2: + return SQTT_MEMORY_TYPE_DDR2; + case AMDGPU_VRAM_TYPE_DDR3: + return SQTT_MEMORY_TYPE_DDR3; + case AMDGPU_VRAM_TYPE_DDR4: + return SQTT_MEMORY_TYPE_DDR4; + case AMDGPU_VRAM_TYPE_GDDR5: + return SQTT_MEMORY_TYPE_GDDR5; + case AMDGPU_VRAM_TYPE_HBM: + return SQTT_MEMORY_TYPE_HBM; + case AMDGPU_VRAM_TYPE_GDDR6: + return SQTT_MEMORY_TYPE_GDDR6; + case AMDGPU_VRAM_TYPE_GDDR1: + case AMDGPU_VRAM_TYPE_GDDR3: + case AMDGPU_VRAM_TYPE_GDDR4: + default: + unreachable("Invalid vram type"); + } +} + +static void ac_fill_sqtt_asic_info(struct radeon_info *rad_info, + struct sqtt_file_chunk_asic_info *chunk) +{ + bool has_wave32 = rad_info->chip_class >= GFX10; + + chunk->header.chunk_id.type = SQTT_FILE_CHUNK_TYPE_ASIC_INFO; + chunk->header.chunk_id.index = 0; + chunk->header.major_version = 0; + chunk->header.minor_version = 4; + chunk->header.size_in_bytes = sizeof(*chunk); + + chunk->flags = 0; + + /* All chips older than GFX9 are affected by the "SPI not + * differentiating pkr_id for newwave commands" bug. + */ + if (rad_info->chip_class < GFX9) + chunk->flags |= SQTT_FILE_CHUNK_ASIC_INFO_FLAG_SC_PACKER_NUMBERING; + + /* Only FIJI and GFX9+ support PS1 events. */ + if (rad_info->family == CHIP_FIJI || rad_info->chip_class >= GFX9) + chunk->flags |= SQTT_FILE_CHUNK_ASIC_INFO_FLAG_PS1_EVENT_TOKENS_ENABLED; + + chunk->trace_shader_core_clock = rad_info->max_shader_clock * 1000000; + chunk->trace_memory_clock = rad_info->max_memory_clock * 1000000; + + chunk->device_id = rad_info->pci_id; + chunk->device_revision_id = rad_info->pci_rev_id; + chunk->vgprs_per_simd = rad_info->num_physical_wave64_vgprs_per_simd * (has_wave32 ? 2 : 1); + chunk->sgprs_per_simd = rad_info->num_physical_sgprs_per_simd; + chunk->shader_engines = rad_info->max_se; + chunk->compute_unit_per_shader_engine = rad_info->min_good_cu_per_sa * rad_info->max_sa_per_se; + chunk->simd_per_compute_unit = rad_info->num_simd_per_compute_unit; + chunk->wavefronts_per_simd = rad_info->max_wave64_per_simd; + + chunk->minimum_vgpr_alloc = rad_info->min_wave64_vgpr_alloc; + chunk->vgpr_alloc_granularity = rad_info->wave64_vgpr_alloc_granularity * (has_wave32 ? 2 : 1); + chunk->minimum_sgpr_alloc = rad_info->min_sgpr_alloc; + chunk->sgpr_alloc_granularity = rad_info->sgpr_alloc_granularity; + + chunk->hardware_contexts = 8; + chunk->gpu_type = + rad_info->has_dedicated_vram ? SQTT_GPU_TYPE_DISCRETE : SQTT_GPU_TYPE_INTEGRATED; + chunk->gfxip_level = ac_chip_class_to_sqtt_gfxip_level(rad_info->chip_class); + chunk->gpu_index = 0; + + chunk->max_number_of_dedicated_cus = 0; + chunk->ce_ram_size = rad_info->ce_ram_size; + chunk->ce_ram_size_graphics = 0; + chunk->ce_ram_size_compute = 0; + + chunk->vram_bus_width = rad_info->vram_bit_width; + chunk->vram_size = rad_info->vram_size; + chunk->l2_cache_size = rad_info->l2_cache_size; + chunk->l1_cache_size = rad_info->l1_cache_size; + chunk->lds_size = rad_info->lds_size_per_workgroup; + + strncpy(chunk->gpu_name, rad_info->name, SQTT_GPU_NAME_MAX_SIZE - 1); + + chunk->alu_per_clock = 0.0; + chunk->texture_per_clock = 0.0; + chunk->prims_per_clock = 0.0; + chunk->pixels_per_clock = 0.0; + + chunk->gpu_timestamp_frequency = rad_info->clock_crystal_freq * 1000; + chunk->max_shader_core_clock = rad_info->max_shader_clock * 1000000; + chunk->max_memory_clock = rad_info->max_memory_clock * 1000000; + chunk->memory_ops_per_clock = 0; + chunk->memory_chip_type = ac_vram_type_to_sqtt_memory_type(rad_info->vram_type); + chunk->lds_granularity = rad_info->lds_granularity; + + for (unsigned se = 0; se < 4; se++) { + for (unsigned sa = 0; sa < 2; sa++) { + chunk->cu_mask[se][sa] = rad_info->cu_mask[se][sa]; + } + } +} + +/** + * SQTT API info. + */ +enum sqtt_api_type +{ + SQTT_API_TYPE_DIRECTX_12, + SQTT_API_TYPE_VULKAN, + SQTT_API_TYPE_GENERIC, + SQTT_API_TYPE_OPENCL +}; + +enum sqtt_instruction_trace_mode +{ + SQTT_INSTRUCTION_TRACE_DISABLED = 0x0, + SQTT_INSTRUCTION_TRACE_FULL_FRAME = 0x1, + SQTT_INSTRUCTION_TRACE_API_PSO = 0x2, +}; + +enum sqtt_profiling_mode +{ + SQTT_PROFILING_MODE_PRESENT = 0x0, + SQTT_PROFILING_MODE_USER_MARKERS = 0x1, + SQTT_PROFILING_MODE_INDEX = 0x2, + SQTT_PROFILING_MODE_TAG = 0x3, +}; + +union sqtt_profiling_mode_data { + struct { + char start[256]; + char end[256]; + } user_marker_profiling_data; + + struct { + uint32_t start; + uint32_t end; + } index_profiling_data; + + struct { + uint32_t begin_hi; + uint32_t begin_lo; + uint32_t end_hi; + uint32_t end_lo; + } tag_profiling_data; +}; + +union sqtt_instruction_trace_data { + struct { + uint64_t api_pso_filter; + } api_pso_data; + + struct { + char start[256]; + char end[256]; + } user_marker_data; +}; + +struct sqtt_file_chunk_api_info { + struct sqtt_file_chunk_header header; + enum sqtt_api_type api_type; + uint16_t major_version; + uint16_t minor_version; + enum sqtt_profiling_mode profiling_mode; + uint32_t reserved; + union sqtt_profiling_mode_data profiling_mode_data; + enum sqtt_instruction_trace_mode instruction_trace_mode; + uint32_t reserved2; + union sqtt_instruction_trace_data instruction_trace_data; +}; + +static_assert(sizeof(struct sqtt_file_chunk_api_info) == 1064, + "sqtt_file_chunk_api_info doesn't match RGP spec"); + +static void ac_sqtt_fill_api_info(struct sqtt_file_chunk_api_info *chunk) +{ + chunk->header.chunk_id.type = SQTT_FILE_CHUNK_TYPE_API_INFO; + chunk->header.chunk_id.index = 0; + chunk->header.major_version = 0; + chunk->header.minor_version = 1; + chunk->header.size_in_bytes = sizeof(*chunk); + + chunk->api_type = SQTT_API_TYPE_VULKAN; + chunk->major_version = 0; + chunk->minor_version = 0; + chunk->profiling_mode = SQTT_PROFILING_MODE_PRESENT; + chunk->instruction_trace_mode = SQTT_INSTRUCTION_TRACE_DISABLED; +} + +/** + * SQTT desc info. + */ +struct sqtt_file_chunk_sqtt_desc { + struct sqtt_file_chunk_header header; + int32_t shader_engine_index; + enum sqtt_version sqtt_version; + union { + struct { + int32_t instrumentation_version; + } v0; + struct { + int16_t instrumentation_spec_version; + int16_t instrumentation_api_version; + int32_t compute_unit_index; + } v1; + }; +}; + +static_assert(sizeof(struct sqtt_file_chunk_sqtt_desc) == 32, + "sqtt_file_chunk_sqtt_desc doesn't match RGP spec"); + +static enum sqtt_version ac_chip_class_to_sqtt_version(enum chip_class chip_class) +{ + switch (chip_class) { + case GFX6: + return SQTT_VERSION_2_0; + case GFX7: + return SQTT_VERSION_2_1; + case GFX8: + return SQTT_VERSION_2_2; + case GFX9: + return SQTT_VERSION_2_3; + case GFX10: + return SQTT_VERSION_2_4; + default: + unreachable("Invalid chip class"); + } +} + +static void ac_sqtt_fill_sqtt_desc(struct radeon_info *info, + struct sqtt_file_chunk_sqtt_desc *chunk, int32_t chunk_index, + int32_t shader_engine_index, int32_t compute_unit_index) +{ + chunk->header.chunk_id.type = SQTT_FILE_CHUNK_TYPE_SQTT_DESC; + chunk->header.chunk_id.index = chunk_index; + chunk->header.major_version = 0; + chunk->header.minor_version = 2; + chunk->header.size_in_bytes = sizeof(*chunk); + + chunk->sqtt_version = + ac_chip_class_to_sqtt_version(info->chip_class); + chunk->shader_engine_index = shader_engine_index; + chunk->v1.instrumentation_spec_version = 1; + chunk->v1.instrumentation_api_version = 0; + chunk->v1.compute_unit_index = compute_unit_index; +} + +/** + * SQTT data info. + */ +struct sqtt_file_chunk_sqtt_data { + struct sqtt_file_chunk_header header; + int32_t offset; /* in bytes */ + int32_t size; /* in bytes */ +}; + +static_assert(sizeof(struct sqtt_file_chunk_sqtt_data) == 24, + "sqtt_file_chunk_sqtt_data doesn't match RGP spec"); + +static void ac_sqtt_fill_sqtt_data(struct sqtt_file_chunk_sqtt_data *chunk, int32_t chunk_index, + int32_t offset, int32_t size) +{ + chunk->header.chunk_id.type = SQTT_FILE_CHUNK_TYPE_SQTT_DATA; + chunk->header.chunk_id.index = chunk_index; + chunk->header.major_version = 0; + chunk->header.minor_version = 0; + chunk->header.size_in_bytes = sizeof(*chunk) + size; + + chunk->offset = sizeof(*chunk) + offset; + chunk->size = size; +} + +static void ac_sqtt_dump_data(struct radeon_info *rad_info, + const struct ac_thread_trace *thread_trace, FILE *output) +{ + struct sqtt_file_chunk_asic_info asic_info = {0}; + struct sqtt_file_chunk_cpu_info cpu_info = {0}; + struct sqtt_file_chunk_api_info api_info = {0}; + struct sqtt_file_header header = {0}; + size_t file_offset = 0; + + /* SQTT header file. */ + ac_sqtt_fill_header(&header); + file_offset += sizeof(header); + fwrite(&header, sizeof(header), 1, output); + + /* SQTT cpu chunk. */ + ac_sqtt_fill_cpu_info(&cpu_info); + file_offset += sizeof(cpu_info); + fwrite(&cpu_info, sizeof(cpu_info), 1, output); + + /* SQTT asic chunk. */ + ac_fill_sqtt_asic_info(rad_info, &asic_info); + file_offset += sizeof(asic_info); + fwrite(&asic_info, sizeof(asic_info), 1, output); + + /* SQTT api chunk. */ + ac_sqtt_fill_api_info(&api_info); + file_offset += sizeof(api_info); + fwrite(&api_info, sizeof(api_info), 1, output); + + if (thread_trace) { + for (unsigned i = 0; i < thread_trace->num_traces; i++) { + const struct ac_thread_trace_se *se = &thread_trace->traces[i]; + const struct ac_thread_trace_info *info = &se->info; + struct sqtt_file_chunk_sqtt_desc desc = {0}; + struct sqtt_file_chunk_sqtt_data data = {0}; + uint64_t size = info->cur_offset * 32; /* unit of 32 bytes */ + + /* SQTT desc chunk. */ + ac_sqtt_fill_sqtt_desc(rad_info, &desc, i, se->shader_engine, se->compute_unit); + file_offset += sizeof(desc); + fwrite(&desc, sizeof(desc), 1, output); + + /* SQTT data chunk. */ + ac_sqtt_fill_sqtt_data(&data, i, file_offset, size); + file_offset += sizeof(data); + fwrite(&data, sizeof(data), 1, output); + + /* Copy thread trace data generated by the hardware. */ + file_offset += size; + fwrite(se->data_ptr, size, 1, output); + } + } +} + +int ac_dump_thread_trace(struct radeon_info *info, const struct ac_thread_trace *thread_trace) +{ + char filename[2048]; + struct tm now; + time_t t; + FILE *f; + + t = time(NULL); + now = *localtime(&t); + + snprintf(filename, sizeof(filename), "/tmp/%s_%04d.%02d.%02d_%02d.%02d.rgp", + util_get_process_name(), 1900 + now.tm_year, now.tm_mon + 1, now.tm_mday, now.tm_hour, + now.tm_min); + + f = fopen(filename, "w+"); + if (!f) + return -1; + + ac_sqtt_dump_data(info, thread_trace, f); + + fprintf(stderr, "Thread trace capture saved to '%s'\n", filename); + + fclose(f); + return 0; +} diff --git a/src/amd/common/ac_rgp.h b/src/amd/common/ac_rgp.h new file mode 100644 index 00000000000..caef1e19ba9 --- /dev/null +++ b/src/amd/common/ac_rgp.h @@ -0,0 +1,38 @@ +/* + * Copyright 2020 Advanced Micro Devices, Inc. + * Copyright 2020 Valve Corporation + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef AC_RGP_H +#define AC_RGP_H + +#include + +struct radeon_info; +struct ac_thread_trace; + +int +ac_dump_thread_trace(struct radeon_info *info, + const struct ac_thread_trace *thread_trace); + +#endif diff --git a/src/amd/common/meson.build b/src/amd/common/meson.build index d0e7fee9bf1..d4330819d34 100644 --- a/src/amd/common/meson.build +++ b/src/amd/common/meson.build @@ -82,6 +82,8 @@ amd_common_files = files( 'ac_shadowed_regs.h', 'ac_sqtt.c', 'ac_sqtt.h', + 'ac_rgp.c', + 'ac_rgp.h', ) libamd_common = static_library( diff --git a/src/amd/vulkan/Makefile.sources b/src/amd/vulkan/Makefile.sources index 25485c42c66..4b03b2007a3 100644 --- a/src/amd/vulkan/Makefile.sources +++ b/src/amd/vulkan/Makefile.sources @@ -74,7 +74,6 @@ VULKAN_FILES := \ radv_pipeline_cache.c \ radv_private.h \ radv_radeon_winsys.h \ - radv_rgp.c \ radv_shader.c \ radv_shader_args.c \ radv_shader_args.h \ diff --git a/src/amd/vulkan/layers/radv_sqtt_layer.c b/src/amd/vulkan/layers/radv_sqtt_layer.c index 0f6761b499f..33e2bb775fc 100644 --- a/src/amd/vulkan/layers/radv_sqtt_layer.c +++ b/src/amd/vulkan/layers/radv_sqtt_layer.c @@ -23,6 +23,8 @@ #include "radv_private.h" +#include "ac_rgp.h" + /** * Identifiers for RGP SQ thread-tracing markers (Table 1) */ @@ -633,7 +635,7 @@ radv_handle_thread_trace(VkQueue _queue) radv_QueueWaitIdle(_queue); if (radv_get_thread_trace(queue, &thread_trace)) - radv_dump_thread_trace(queue->device, &thread_trace); + ac_dump_thread_trace(&queue->device->physical_device->rad_info, &thread_trace); } else { bool frame_trigger = num_frames == queue->device->thread_trace.start_frame; bool file_trigger = false; diff --git a/src/amd/vulkan/meson.build b/src/amd/vulkan/meson.build index ed14839e891..6c0fad72e1c 100644 --- a/src/amd/vulkan/meson.build +++ b/src/amd/vulkan/meson.build @@ -88,7 +88,6 @@ libradv_files = files( 'radv_pipeline_cache.c', 'radv_private.h', 'radv_radeon_winsys.h', - 'radv_rgp.c', 'radv_shader.c', 'radv_shader.h', 'radv_shader_args.c', diff --git a/src/amd/vulkan/radv_private.h b/src/amd/vulkan/radv_private.h index 6ac7e07e70c..d03537c5851 100644 --- a/src/amd/vulkan/radv_private.h +++ b/src/amd/vulkan/radv_private.h @@ -2563,10 +2563,6 @@ bool radv_get_thread_trace(struct radv_queue *queue, void radv_emit_thread_trace_userdata(const struct radv_device *device, struct radeon_cmdbuf *cs, const void *data, uint32_t num_dwords); -/* radv_rgp.c */ -int radv_dump_thread_trace(struct radv_device *device, - const struct ac_thread_trace *trace); - /* radv_sqtt_layer_.c */ struct radv_barrier_data { union { diff --git a/src/amd/vulkan/radv_rgp.c b/src/amd/vulkan/radv_rgp.c deleted file mode 100644 index 7037e511f67..00000000000 --- a/src/amd/vulkan/radv_rgp.c +++ /dev/null @@ -1,669 +0,0 @@ -/* - * Copyright © 2020 Valve Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#include -#include -#include -#include "radv_private.h" - -#include "util/u_process.h" - -#include "drm-uapi/amdgpu_drm.h" - -#define SQTT_FILE_MAGIC_NUMBER 0x50303042 -#define SQTT_FILE_VERSION_MAJOR 1 -#define SQTT_FILE_VERSION_MINOR 4 - -#define SQTT_GPU_NAME_MAX_SIZE 256 -#define SQTT_MAX_NUM_SE 32 -#define SQTT_SA_PER_SE 2 - -enum sqtt_version { - SQTT_VERSION_NONE = 0x0, - SQTT_VERSION_1_0 = 0x1, - SQTT_VERSION_1_1 = 0x2, - SQTT_VERSION_2_0 = 0x3, /* GFX6 */ - SQTT_VERSION_2_1 = 0x4, /* GFX7 */ - SQTT_VERSION_2_2 = 0x5, /* GFX8 */ - SQTT_VERSION_2_3 = 0x6, /* GFX9 */ - SQTT_VERSION_2_4 = 0x7 /* GFX10 */ -}; - -/** - * SQTT chunks. - */ -enum sqtt_file_chunk_type { - SQTT_FILE_CHUNK_TYPE_ASIC_INFO, - SQTT_FILE_CHUNK_TYPE_SQTT_DESC, - SQTT_FILE_CHUNK_TYPE_SQTT_DATA, - SQTT_FILE_CHUNK_TYPE_API_INFO, - SQTT_FILE_CHUNK_TYPE_ISA_DATABASE, - SQTT_FILE_CHUNK_TYPE_QUEUE_EVENT_TIMINGS, - SQTT_FILE_CHUNK_TYPE_CLOCK_CALIBRATION, - SQTT_FILE_CHUNK_TYPE_CPU_INFO, - SQTT_FILE_CHUNK_TYPE_SPM_DB, - SQTT_FILE_CHUNK_TYPE_CODE_OBJECT_DATABASE, - SQTT_FILE_CHUNK_TYPE_CODE_OBJECT_LOADER_EVENTS, - SQTT_FILE_CHUNK_TYPE_PSO_CORRELATION, - SQTT_FILE_CHUNK_TYPE_INSTRUMENTATION_TABLE, - SQTT_FILE_CHUNK_TYPE_COUNT -}; - -struct sqtt_file_chunk_id { - enum sqtt_file_chunk_type type : 8; - int32_t index : 8; - int32_t reserved : 16; -}; - -struct sqtt_file_chunk_header { - struct sqtt_file_chunk_id chunk_id; - uint16_t minor_version; - uint16_t major_version; - int32_t size_in_bytes; - int32_t padding; -}; - -/** - * SQTT file header. - */ -struct sqtt_file_header_flags { - union { - struct { - int32_t is_semaphore_queue_timing_etw : 1; - int32_t no_queue_semaphore_timestamps : 1; - int32_t reserved : 30; - }; - - uint32_t value; - }; -}; - -struct sqtt_file_header { - uint32_t magic_number; - uint32_t version_major; - uint32_t version_minor; - struct sqtt_file_header_flags flags; - int32_t chunk_offset; - int32_t second; - int32_t minute; - int32_t hour; - int32_t day_in_month; - int32_t month; - int32_t year; - int32_t day_in_week; - int32_t day_in_year; - int32_t is_daylight_savings; -}; - -static_assert(sizeof(struct sqtt_file_header) == 56, - "sqtt_file_header doesn't match RGP spec"); - -static void -radv_sqtt_fill_header(struct sqtt_file_header *header) -{ - struct tm *timep, result; - time_t raw_time; - - header->magic_number = SQTT_FILE_MAGIC_NUMBER; - header->version_major = SQTT_FILE_VERSION_MAJOR; - header->version_minor = SQTT_FILE_VERSION_MINOR; - header->flags.value = 0; - header->flags.is_semaphore_queue_timing_etw = 1; - header->flags.no_queue_semaphore_timestamps = 0; - header->chunk_offset = sizeof(*header); - - time(&raw_time); - timep = os_localtime(&raw_time, &result); - - header->second = timep->tm_sec; - header->minute = timep->tm_min; - header->hour = timep->tm_hour; - header->day_in_month = timep->tm_mday; - header->month = timep->tm_mon; - header->year = timep->tm_year; - header->day_in_week = timep->tm_wday; - header->day_in_year = timep->tm_yday; - header->is_daylight_savings = timep->tm_isdst; -} - -/** - * SQTT CPU info. - */ -struct sqtt_file_chunk_cpu_info { - struct sqtt_file_chunk_header header; - uint32_t vendor_id[4]; - uint32_t processor_brand[12]; - uint32_t reserved[2]; - uint64_t cpu_timestamp_freq; - uint32_t clock_speed; - uint32_t num_logical_cores; - uint32_t num_physical_cores; - uint32_t system_ram_size; -}; - -static_assert(sizeof(struct sqtt_file_chunk_cpu_info) == 112, - "sqtt_file_chunk_cpu_info doesn't match RGP spec"); - -static void -radv_sqtt_fill_cpu_info(struct sqtt_file_chunk_cpu_info *chunk) -{ - uint64_t system_ram_size = 0; - - chunk->header.chunk_id.type = SQTT_FILE_CHUNK_TYPE_CPU_INFO; - chunk->header.chunk_id.index = 0; - chunk->header.major_version = 0; - chunk->header.minor_version = 0; - chunk->header.size_in_bytes = sizeof(*chunk); - - chunk->cpu_timestamp_freq = 1000000000; /* tick set to 1ns */ - - /* TODO: fill with real info. */ - - strncpy((char *)chunk->vendor_id, "Unknown", sizeof(chunk->vendor_id)); - strncpy((char *)chunk->processor_brand, "Unknown", sizeof(chunk->processor_brand)); - chunk->clock_speed = 0; - chunk->num_logical_cores = 0; - chunk->num_physical_cores = 0; - - chunk->system_ram_size = 0; - if (os_get_total_physical_memory(&system_ram_size)) - chunk->system_ram_size = system_ram_size / (1024 * 1024); -} - -/** - * SQTT ASIC info. - */ -enum sqtt_file_chunk_asic_info_flags -{ - SQTT_FILE_CHUNK_ASIC_INFO_FLAG_SC_PACKER_NUMBERING = (1 << 0), - SQTT_FILE_CHUNK_ASIC_INFO_FLAG_PS1_EVENT_TOKENS_ENABLED = (1 << 1) -}; - -enum sqtt_gpu_type { - SQTT_GPU_TYPE_UNKNOWN = 0x0, - SQTT_GPU_TYPE_INTEGRATED = 0x1, - SQTT_GPU_TYPE_DISCRETE = 0x2, - SQTT_GPU_TYPE_VIRTUAL = 0x3 -}; - -enum sqtt_gfxip_level { - SQTT_GFXIP_LEVEL_NONE = 0x0, - SQTT_GFXIP_LEVEL_GFXIP_6 = 0x1, - SQTT_GFXIP_LEVEL_GFXIP_7 = 0x2, - SQTT_GFXIP_LEVEL_GFXIP_8 = 0x3, - SQTT_GFXIP_LEVEL_GFXIP_8_1 = 0x4, - SQTT_GFXIP_LEVEL_GFXIP_9 = 0x5, - SQTT_GFXIP_LEVEL_GFXIP_10_1 = 0x7, -}; - -enum sqtt_memory_type { - SQTT_MEMORY_TYPE_UNKNOWN = 0x0, - SQTT_MEMORY_TYPE_DDR = 0x1, - SQTT_MEMORY_TYPE_DDR2 = 0x2, - SQTT_MEMORY_TYPE_DDR3 = 0x3, - SQTT_MEMORY_TYPE_DDR4 = 0x4, - SQTT_MEMORY_TYPE_GDDR3 = 0x10, - SQTT_MEMORY_TYPE_GDDR4 = 0x11, - SQTT_MEMORY_TYPE_GDDR5 = 0x12, - SQTT_MEMORY_TYPE_GDDR6 = 0x13, - SQTT_MEMORY_TYPE_HBM = 0x20, - SQTT_MEMORY_TYPE_HBM2 = 0x21, - SQTT_MEMORY_TYPE_HBM3 = 0x22, -}; - -struct sqtt_file_chunk_asic_info { - struct sqtt_file_chunk_header header; - uint64_t flags; - uint64_t trace_shader_core_clock; - uint64_t trace_memory_clock; - int32_t device_id; - int32_t device_revision_id; - int32_t vgprs_per_simd; - int32_t sgprs_per_simd; - int32_t shader_engines; - int32_t compute_unit_per_shader_engine; - int32_t simd_per_compute_unit; - int32_t wavefronts_per_simd; - int32_t minimum_vgpr_alloc; - int32_t vgpr_alloc_granularity; - int32_t minimum_sgpr_alloc; - int32_t sgpr_alloc_granularity; - int32_t hardware_contexts; - enum sqtt_gpu_type gpu_type; - enum sqtt_gfxip_level gfxip_level; - int32_t gpu_index; - int32_t gds_size; - int32_t gds_per_shader_engine; - int32_t ce_ram_size; - int32_t ce_ram_size_graphics; - int32_t ce_ram_size_compute; - int32_t max_number_of_dedicated_cus; - int64_t vram_size; - int32_t vram_bus_width; - int32_t l2_cache_size; - int32_t l1_cache_size; - int32_t lds_size; - char gpu_name[SQTT_GPU_NAME_MAX_SIZE]; - float alu_per_clock; - float texture_per_clock; - float prims_per_clock; - float pixels_per_clock; - uint64_t gpu_timestamp_frequency; - uint64_t max_shader_core_clock; - uint64_t max_memory_clock; - uint32_t memory_ops_per_clock; - enum sqtt_memory_type memory_chip_type; - uint32_t lds_granularity; - uint16_t cu_mask[SQTT_MAX_NUM_SE][SQTT_SA_PER_SE]; - char reserved1[128]; - char padding[4]; -}; - -static_assert(sizeof(struct sqtt_file_chunk_asic_info) == 720, - "sqtt_file_chunk_asic_info doesn't match RGP spec"); - -static enum sqtt_gfxip_level -radv_chip_class_to_sqtt_gfxip_level(enum chip_class chip_class) -{ - switch (chip_class) { - case GFX6: - return SQTT_GFXIP_LEVEL_GFXIP_6; - case GFX7: - return SQTT_GFXIP_LEVEL_GFXIP_7; - case GFX8: - return SQTT_GFXIP_LEVEL_GFXIP_8; - case GFX9: - return SQTT_GFXIP_LEVEL_GFXIP_9; - case GFX10: - return SQTT_GFXIP_LEVEL_GFXIP_10_1; - default: - unreachable("Invalid chip class"); - } -} - -static enum sqtt_memory_type -radv_vram_type_to_sqtt_memory_type(uint32_t vram_type) -{ - switch (vram_type) { - case AMDGPU_VRAM_TYPE_UNKNOWN: - return SQTT_MEMORY_TYPE_UNKNOWN; - case AMDGPU_VRAM_TYPE_DDR2: - return SQTT_MEMORY_TYPE_DDR2; - case AMDGPU_VRAM_TYPE_DDR3: - return SQTT_MEMORY_TYPE_DDR3; - case AMDGPU_VRAM_TYPE_DDR4: - return SQTT_MEMORY_TYPE_DDR4; - case AMDGPU_VRAM_TYPE_GDDR5: - return SQTT_MEMORY_TYPE_GDDR5; - case AMDGPU_VRAM_TYPE_HBM: - return SQTT_MEMORY_TYPE_HBM; - case AMDGPU_VRAM_TYPE_GDDR6: - return SQTT_MEMORY_TYPE_GDDR6; - case AMDGPU_VRAM_TYPE_GDDR1: - case AMDGPU_VRAM_TYPE_GDDR3: - case AMDGPU_VRAM_TYPE_GDDR4: - default: - unreachable("Invalid vram type"); - } -} - -static void -radv_fill_sqtt_asic_info(struct radv_device *device, - struct sqtt_file_chunk_asic_info *chunk) -{ - struct radeon_info *rad_info = &device->physical_device->rad_info; - bool has_wave32 = rad_info->chip_class >= GFX10; - - chunk->header.chunk_id.type = SQTT_FILE_CHUNK_TYPE_ASIC_INFO; - chunk->header.chunk_id.index = 0; - chunk->header.major_version = 0; - chunk->header.minor_version = 4; - chunk->header.size_in_bytes = sizeof(*chunk); - - chunk->flags = 0; - - /* All chips older than GFX9 are affected by the "SPI not - * differentiating pkr_id for newwave commands" bug. - */ - if (rad_info->chip_class < GFX9) - chunk->flags |= SQTT_FILE_CHUNK_ASIC_INFO_FLAG_SC_PACKER_NUMBERING; - - /* Only FIJI and GFX9+ support PS1 events. */ - if (rad_info->family == CHIP_FIJI || rad_info->chip_class >= GFX9) - chunk->flags |= SQTT_FILE_CHUNK_ASIC_INFO_FLAG_PS1_EVENT_TOKENS_ENABLED; - - chunk->trace_shader_core_clock = rad_info->max_shader_clock * 1000000; - chunk->trace_memory_clock = rad_info->max_memory_clock * 1000000; - - chunk->device_id = rad_info->pci_id; - chunk->device_revision_id = rad_info->pci_rev_id; - chunk->vgprs_per_simd = rad_info->num_physical_wave64_vgprs_per_simd * - (has_wave32 ? 2 : 1); - chunk->sgprs_per_simd = rad_info->num_physical_sgprs_per_simd; - chunk->shader_engines = rad_info->max_se; - chunk->compute_unit_per_shader_engine = rad_info->min_good_cu_per_sa * - rad_info->max_sa_per_se; - chunk->simd_per_compute_unit = rad_info->num_simd_per_compute_unit; - chunk->wavefronts_per_simd = rad_info->max_wave64_per_simd; - - chunk->minimum_vgpr_alloc = rad_info->min_wave64_vgpr_alloc; - chunk->vgpr_alloc_granularity = rad_info->wave64_vgpr_alloc_granularity * - (has_wave32 ? 2 : 1); - chunk->minimum_sgpr_alloc = rad_info->min_sgpr_alloc; - chunk->sgpr_alloc_granularity = rad_info->sgpr_alloc_granularity; - - chunk->hardware_contexts = 8; - chunk->gpu_type = rad_info->has_dedicated_vram ? SQTT_GPU_TYPE_DISCRETE : SQTT_GPU_TYPE_INTEGRATED; - chunk->gfxip_level = radv_chip_class_to_sqtt_gfxip_level(rad_info->chip_class); - chunk->gpu_index = 0; - - chunk->max_number_of_dedicated_cus = 0; - chunk->ce_ram_size = rad_info->ce_ram_size; - chunk->ce_ram_size_graphics = 0; - chunk->ce_ram_size_compute = 0; - - chunk->vram_bus_width = rad_info->vram_bit_width; - chunk->vram_size = rad_info->vram_size; - chunk->l2_cache_size = rad_info->l2_cache_size; - chunk->l1_cache_size = rad_info->l1_cache_size; - chunk->lds_size = rad_info->lds_size_per_workgroup; - - strncpy(chunk->gpu_name, device->physical_device->name, SQTT_GPU_NAME_MAX_SIZE); - - chunk->alu_per_clock = 0.0; - chunk->texture_per_clock = 0.0; - chunk->prims_per_clock = 0.0; - chunk->pixels_per_clock = 0.0; - - chunk->gpu_timestamp_frequency = rad_info->clock_crystal_freq * 1000; - chunk->max_shader_core_clock = rad_info->max_shader_clock * 1000000; - chunk->max_memory_clock = rad_info->max_memory_clock * 1000000; - chunk->memory_ops_per_clock = 0; - chunk->memory_chip_type = radv_vram_type_to_sqtt_memory_type(rad_info->vram_type); - chunk->lds_granularity = rad_info->lds_granularity; - - for (unsigned se = 0; se < 4; se++) { - for (unsigned sa = 0; sa < 2; sa++) { - chunk->cu_mask[se][sa] = rad_info->cu_mask[se][sa]; - } - } -} - -/** - * SQTT API info. - */ -enum sqtt_api_type { - SQTT_API_TYPE_DIRECTX_12, - SQTT_API_TYPE_VULKAN, - SQTT_API_TYPE_GENERIC, - SQTT_API_TYPE_OPENCL -}; - -enum sqtt_instruction_trace_mode -{ - SQTT_INSTRUCTION_TRACE_DISABLED = 0x0, - SQTT_INSTRUCTION_TRACE_FULL_FRAME = 0x1, - SQTT_INSTRUCTION_TRACE_API_PSO = 0x2, -}; - -enum sqtt_profiling_mode { - SQTT_PROFILING_MODE_PRESENT = 0x0, - SQTT_PROFILING_MODE_USER_MARKERS = 0x1, - SQTT_PROFILING_MODE_INDEX = 0x2, - SQTT_PROFILING_MODE_TAG = 0x3, -}; - -union sqtt_profiling_mode_data { - struct { - char start[256]; - char end[256]; - } user_marker_profiling_data; - - struct { - uint32_t start; - uint32_t end; - } index_profiling_data; - - struct { - uint32_t begin_hi; - uint32_t begin_lo; - uint32_t end_hi; - uint32_t end_lo; - } tag_profiling_data; -}; - -union sqtt_instruction_trace_data { - struct { - uint64_t api_pso_filter; - } api_pso_data; - - struct { - char start[256]; - char end[256]; - } user_marker_data; -}; - -struct sqtt_file_chunk_api_info { - struct sqtt_file_chunk_header header; - enum sqtt_api_type api_type; - uint16_t major_version; - uint16_t minor_version; - enum sqtt_profiling_mode profiling_mode; - uint32_t reserved; - union sqtt_profiling_mode_data profiling_mode_data; - enum sqtt_instruction_trace_mode instruction_trace_mode; - uint32_t reserved2; - union sqtt_instruction_trace_data instruction_trace_data; -}; - -static_assert(sizeof(struct sqtt_file_chunk_api_info) == 1064, - "sqtt_file_chunk_api_info doesn't match RGP spec"); - -static void -radv_sqtt_fill_api_info(struct sqtt_file_chunk_api_info *chunk) -{ - chunk->header.chunk_id.type = SQTT_FILE_CHUNK_TYPE_API_INFO; - chunk->header.chunk_id.index = 0; - chunk->header.major_version = 0; - chunk->header.minor_version = 1; - chunk->header.size_in_bytes = sizeof(*chunk); - - chunk->api_type = SQTT_API_TYPE_VULKAN; - chunk->major_version = 0; - chunk->minor_version = 0; - chunk->profiling_mode = SQTT_PROFILING_MODE_PRESENT; - chunk->instruction_trace_mode = SQTT_INSTRUCTION_TRACE_DISABLED; -} - -/** - * SQTT desc info. - */ -struct sqtt_file_chunk_sqtt_desc { - struct sqtt_file_chunk_header header; - int32_t shader_engine_index; - enum sqtt_version sqtt_version; - union { - struct { - int32_t instrumentation_version; - } v0; - struct { - int16_t instrumentation_spec_version; - int16_t instrumentation_api_version; - int32_t compute_unit_index; - } v1; - }; -}; - -static_assert(sizeof(struct sqtt_file_chunk_sqtt_desc) == 32, - "sqtt_file_chunk_sqtt_desc doesn't match RGP spec"); - -static enum sqtt_version -radv_chip_class_to_sqtt_version(enum chip_class chip_class) -{ - switch (chip_class) { - case GFX6: - return SQTT_VERSION_2_0; - case GFX7: - return SQTT_VERSION_2_1; - case GFX8: - return SQTT_VERSION_2_2; - case GFX9: - return SQTT_VERSION_2_3; - case GFX10: - return SQTT_VERSION_2_4; - default: - unreachable("Invalid chip class"); - } -} - -static void -radv_sqtt_fill_sqtt_desc(struct radv_device *device, - struct sqtt_file_chunk_sqtt_desc *chunk, - int32_t chunk_index, - int32_t shader_engine_index, - int32_t compute_unit_index) -{ - chunk->header.chunk_id.type = SQTT_FILE_CHUNK_TYPE_SQTT_DESC; - chunk->header.chunk_id.index = chunk_index; - chunk->header.major_version = 0; - chunk->header.minor_version = 2; - chunk->header.size_in_bytes = sizeof(*chunk); - - chunk->sqtt_version = radv_chip_class_to_sqtt_version(device->physical_device->rad_info.chip_class); - chunk->shader_engine_index = shader_engine_index; - chunk->v1.instrumentation_spec_version = 1; - chunk->v1.instrumentation_api_version = 0; - chunk->v1.compute_unit_index = compute_unit_index; -} - -/** - * SQTT data info. - */ -struct sqtt_file_chunk_sqtt_data { - struct sqtt_file_chunk_header header; - int32_t offset; /* in bytes */ - int32_t size; /* in bytes */ -}; - -static_assert(sizeof(struct sqtt_file_chunk_sqtt_data) == 24, - "sqtt_file_chunk_sqtt_data doesn't match RGP spec"); - -static void -radv_sqtt_fill_sqtt_data(struct sqtt_file_chunk_sqtt_data *chunk, - int32_t chunk_index, int32_t offset, int32_t size) -{ - chunk->header.chunk_id.type = SQTT_FILE_CHUNK_TYPE_SQTT_DATA; - chunk->header.chunk_id.index = chunk_index; - chunk->header.major_version = 0; - chunk->header.minor_version = 0; - chunk->header.size_in_bytes = sizeof(*chunk) + size; - - chunk->offset = sizeof(*chunk) + offset; - chunk->size = size; -} - -static void -radv_sqtt_dump_data(struct radv_device *device, - const struct ac_thread_trace *thread_trace, - FILE *output) -{ - struct sqtt_file_chunk_asic_info asic_info = {0}; - struct sqtt_file_chunk_cpu_info cpu_info = {0}; - struct sqtt_file_chunk_api_info api_info = {0}; - struct sqtt_file_header header = {0}; - size_t file_offset = 0; - - /* SQTT header file. */ - radv_sqtt_fill_header(&header); - file_offset += sizeof(header); - fwrite(&header, sizeof(header), 1, output); - - /* SQTT cpu chunk. */ - radv_sqtt_fill_cpu_info(&cpu_info); - file_offset += sizeof(cpu_info); - fwrite(&cpu_info, sizeof(cpu_info), 1, output); - - /* SQTT asic chunk. */ - radv_fill_sqtt_asic_info(device, &asic_info); - file_offset += sizeof(asic_info); - fwrite(&asic_info, sizeof(asic_info), 1, output); - - /* SQTT api chunk. */ - radv_sqtt_fill_api_info(&api_info); - file_offset += sizeof(api_info); - fwrite(&api_info, sizeof(api_info), 1, output); - - if (thread_trace) { - for (unsigned i = 0; i < thread_trace->num_traces; i++) { - const struct ac_thread_trace_se *se = &thread_trace->traces[i]; - const struct ac_thread_trace_info *info = &se->info; - struct sqtt_file_chunk_sqtt_desc desc = {0}; - struct sqtt_file_chunk_sqtt_data data = {0}; - uint64_t size = info->cur_offset * 32; /* unit of 32 bytes */ - - /* SQTT desc chunk. */ - radv_sqtt_fill_sqtt_desc(device, &desc, i, - se->shader_engine, - se->compute_unit); - file_offset += sizeof(desc); - fwrite(&desc, sizeof(desc), 1, output); - - /* SQTT data chunk. */ - radv_sqtt_fill_sqtt_data(&data, i, file_offset, size); - file_offset += sizeof(data); - fwrite(&data, sizeof(data), 1, output); - - /* Copy thread trace data generated by the hardware. */ - file_offset += size; - fwrite(se->data_ptr, size, 1, output); - } - } -} - -int -radv_dump_thread_trace(struct radv_device *device, - const struct ac_thread_trace *thread_trace) -{ - char filename[2048]; - struct tm now; - time_t t; - FILE *f; - - t = time(NULL); - now = *localtime(&t); - - snprintf(filename, sizeof(filename), "/tmp/%s_%04d.%02d.%02d_%02d.%02d.rgp", - util_get_process_name(), 1900 + now.tm_year, now.tm_mon + 1, - now.tm_mday, now.tm_hour, now.tm_min); - - f = fopen(filename, "w+"); - if (!f) - return -1; - - radv_sqtt_dump_data(device, thread_trace, f); - - fprintf(stderr, "Thread trace capture saved to '%s'\n", filename); - - fclose(f); - return 0; -} -