blob: 8de2b88a6fa1416f4f1fc5e5325ce721ce895e5c [file] [log] [blame]
// Copyright 2023 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include <stdio.h>
#include "iree/base/api.h"
#include "iree/base/internal/file_io.h"
#include "iree/schemas/instruments/dispatch.h"
// NOTE: include order matters:
#include "iree/base/internal/flatcc/parsing.h"
#include "iree/schemas/instruments/dispatch_def_reader.h"
typedef struct {
iree_instruments_DispatchFunctionDef_vec_t functions_def;
iree_instruments_DispatchSiteDef_vec_t dispatch_sites_def;
} iree_dispatch_metadata_t;
static iree_status_t iree_tooling_dump_dispatch_metadata(
const uint8_t* flatbuffer_ptr, iree_host_size_t flatbuffer_size,
iree_dispatch_metadata_t* out_metadata, FILE* stream) {
memset(out_metadata, 0, sizeof(*out_metadata));
iree_instruments_DispatchInstrumentDef_table_t instr_def =
iree_instruments_DispatchInstrumentDef_as_root(flatbuffer_ptr);
iree_instruments_DispatchFunctionDef_vec_t functions_def =
iree_instruments_DispatchInstrumentDef_functions(instr_def);
out_metadata->functions_def = functions_def;
for (iree_host_size_t i = 0;
i < iree_instruments_DispatchFunctionDef_vec_len(functions_def); ++i) {
fprintf(stream, "\n");
iree_instruments_DispatchFunctionDef_table_t function_def =
iree_instruments_DispatchFunctionDef_vec_at(functions_def, i);
flatbuffers_string_t name =
iree_instruments_DispatchFunctionDef_name(function_def);
fprintf(stream,
"//"
"===---------------------------------------------------------------"
"-------===//\n");
fprintf(stream, "// export[%" PRIhsz "]: %s\n", i, name);
fprintf(stream,
"//"
"===---------------------------------------------------------------"
"-------===//\n");
flatbuffers_string_t target =
iree_instruments_DispatchFunctionDef_target(function_def);
if (target) fprintf(stream, "// target: %s\n", target);
flatbuffers_string_t layout =
iree_instruments_DispatchFunctionDef_layout(function_def);
if (layout) fprintf(stream, "// layout: %s\n", layout);
flatbuffers_string_t source =
iree_instruments_DispatchFunctionDef_source(function_def);
if (source) fprintf(stream, "%s\n", source);
fprintf(stream, "\n");
}
fprintf(stream,
"//"
"===---------------------------------------------------------------"
"-------===//\n");
iree_instruments_DispatchSiteDef_vec_t dispatch_sites_def =
iree_instruments_DispatchInstrumentDef_sites(instr_def);
out_metadata->dispatch_sites_def = dispatch_sites_def;
for (iree_host_size_t i = 0;
i < iree_instruments_DispatchSiteDef_vec_len(dispatch_sites_def); ++i) {
iree_instruments_DispatchSiteDef_table_t dispatch_site_def =
iree_instruments_DispatchSiteDef_vec_at(dispatch_sites_def, i);
iree_instruments_DispatchFunctionDef_table_t function_def =
iree_instruments_DispatchFunctionDef_vec_at(
functions_def,
iree_instruments_DispatchSiteDef_function(dispatch_site_def));
flatbuffers_string_t name =
iree_instruments_DispatchFunctionDef_name(function_def);
fprintf(stream, "// dispatch site %" PRIhsz ": %s\n", i, name);
}
fprintf(stream,
"//"
"===---------------------------------------------------------------"
"-------===//\n\n");
return iree_ok_status();
}
static void iree_tooling_dump_print_value(
iree_instrument_dispatch_value_type_t type, uint64_t raw_value,
FILE* stream) {
union {
int8_t i8;
int16_t i16;
int32_t i32;
int64_t i64;
float f32;
double f64;
uint8_t value_storage[sizeof(uint64_t)];
} value = {.i64 = raw_value};
switch (type) {
case IREE_INSTRUMENT_DISPATCH_VALUE_TYPE_SINT_8:
fprintf(stream, "%" PRId8, value.i8);
break;
case IREE_INSTRUMENT_DISPATCH_VALUE_TYPE_UINT_8:
fprintf(stream, "%" PRIu8, value.i8);
break;
case IREE_INSTRUMENT_DISPATCH_VALUE_TYPE_SINT_16:
fprintf(stream, "%" PRId16, value.i16);
break;
case IREE_INSTRUMENT_DISPATCH_VALUE_TYPE_UINT_16:
fprintf(stream, "%" PRIu16, value.i16);
break;
case IREE_INSTRUMENT_DISPATCH_VALUE_TYPE_SINT_32:
fprintf(stream, "%" PRId32, value.i32);
break;
case IREE_INSTRUMENT_DISPATCH_VALUE_TYPE_UINT_32:
fprintf(stream, "%" PRIu32, value.i32);
break;
case IREE_INSTRUMENT_DISPATCH_VALUE_TYPE_SINT_64:
fprintf(stream, "%" PRId64, value.i64);
break;
case IREE_INSTRUMENT_DISPATCH_VALUE_TYPE_UINT_64:
fprintf(stream, "%" PRIu64, value.i64);
break;
case IREE_INSTRUMENT_DISPATCH_VALUE_TYPE_POINTER:
fprintf(stream, "%16" PRIX64, value.i64);
break;
case IREE_INSTRUMENT_DISPATCH_VALUE_TYPE_FLOAT_16:
case IREE_INSTRUMENT_DISPATCH_VALUE_TYPE_BFLOAT_16:
fprintf(stream, "%4" PRIX16, value.i16);
break;
case IREE_INSTRUMENT_DISPATCH_VALUE_TYPE_FLOAT_32:
fprintf(stream, "%e %f", value.f32, value.f32);
break;
case IREE_INSTRUMENT_DISPATCH_VALUE_TYPE_FLOAT_64:
fprintf(stream, "%e %f", value.f64, value.f64);
break;
default:
fprintf(stream, "<<unknown type: %02X>>", (uint32_t)type);
break;
}
}
static iree_status_t iree_tooling_dump_dispatch_ringbuffer(
const uint8_t* data_ptr, iree_host_size_t data_size,
const iree_dispatch_metadata_t* metadata, FILE* stream) {
const uint64_t ring_size = data_size - IREE_INSTRUMENT_DISPATCH_PADDING;
const uint8_t* ring_data = data_ptr;
const uint64_t ring_head = *(const uint64_t*)(ring_data + data_size - 8);
const uint64_t ring_range = iree_min(ring_head, ring_size);
for (iree_host_size_t i = 0; i < ring_range;) {
const iree_instrument_dispatch_header_t* header =
(const iree_instrument_dispatch_header_t*)(ring_data + i);
switch (header->tag) {
case IREE_INSTRUMENT_DISPATCH_TYPE_WORKGROUP: {
const iree_instrument_dispatch_workgroup_t* workgroup =
(const iree_instrument_dispatch_workgroup_t*)header;
iree_instruments_DispatchSiteDef_table_t dispatch_site_def =
iree_instruments_DispatchSiteDef_vec_at(
metadata->dispatch_sites_def, workgroup->dispatch_id);
iree_instruments_DispatchFunctionDef_table_t function_def =
iree_instruments_DispatchFunctionDef_vec_at(
metadata->functions_def,
iree_instruments_DispatchSiteDef_function(dispatch_site_def));
flatbuffers_string_t name_def =
iree_instruments_DispatchFunctionDef_name(function_def);
fprintf(stream,
"%016" PRIX64
" | WORKGROUP dispatch(%u %s %ux%ux%u) %u,%u,%u pid:%u\n",
(uint64_t)i, workgroup->dispatch_id, name_def,
workgroup->workgroup_count_x, workgroup->workgroup_count_y,
workgroup->workgroup_count_z, workgroup->workgroup_id_x,
workgroup->workgroup_id_y, workgroup->workgroup_id_z,
workgroup->processor_id);
i += sizeof(*workgroup);
break;
}
case IREE_INSTRUMENT_DISPATCH_TYPE_PRINT: {
const iree_instrument_dispatch_print_t* print =
(const iree_instrument_dispatch_print_t*)header;
fprintf(stream, "%016" PRIX64 " | PRINT %.*s\n",
(uint64_t)print->workgroup_offset, (int)print->length,
print->data);
i += iree_host_align(sizeof(*print) + print->length, 16);
break;
}
case IREE_INSTRUMENT_DISPATCH_TYPE_VALUE: {
const iree_instrument_dispatch_value_t* value =
(const iree_instrument_dispatch_value_t*)header;
fprintf(stream, "%016" PRIX64 " | VALUE %04u = ",
(uint64_t)value->workgroup_offset, (uint32_t)value->ordinal);
iree_tooling_dump_print_value(value->type, value->bits, stream);
fputc('\n', stream);
i += sizeof(*value);
break;
}
case IREE_INSTRUMENT_DISPATCH_TYPE_MEMORY_LOAD: {
const iree_instrument_dispatch_memory_op_t* op =
(const iree_instrument_dispatch_memory_op_t*)header;
fprintf(stream, "%016" PRIX64 " | LOAD %016" PRIX64 " %u\n",
(uint64_t)op->workgroup_offset, op->address, (int)op->length);
i += sizeof(*op);
break;
}
case IREE_INSTRUMENT_DISPATCH_TYPE_MEMORY_STORE: {
const iree_instrument_dispatch_memory_op_t* op =
(const iree_instrument_dispatch_memory_op_t*)header;
fprintf(stream, "%016" PRIX64 " | STORE %016" PRIX64 " %u\n",
(uint64_t)op->workgroup_offset, op->address, (int)op->length);
i += sizeof(*op);
break;
}
default:
return iree_make_status(IREE_STATUS_UNIMPLEMENTED,
"unimplemented dispatch instr type: %u",
(uint32_t)header->tag);
}
}
return iree_ok_status();
}
static iree_status_t iree_tooling_dump_instrument_file(
iree_const_byte_span_t file_contents, FILE* stream) {
const uint8_t* file_ptr = file_contents.data;
iree_host_size_t file_size = file_contents.data_length;
iree_dispatch_metadata_t dispatch_metadata = {0};
for (iree_host_size_t file_offset = 0; file_offset < file_size;) {
const iree_idbts_chunk_header_t* header =
(const iree_idbts_chunk_header_t*)(file_ptr + file_offset);
const uint8_t* payload = file_ptr + file_offset + sizeof(*header);
switch (header->type) {
case IREE_IDBTS_CHUNK_TYPE_DISPATCH_METADATA: {
IREE_RETURN_IF_ERROR(iree_tooling_dump_dispatch_metadata(
payload, header->content_length, &dispatch_metadata, stream));
break;
}
case IREE_IDBTS_CHUNK_TYPE_DISPATCH_RINGBUFFER: {
IREE_RETURN_IF_ERROR(iree_tooling_dump_dispatch_ringbuffer(
payload, header->content_length, &dispatch_metadata, stream));
break;
}
default:
return iree_make_status(IREE_STATUS_UNIMPLEMENTED,
"unimplemented chunk type: %u",
(uint32_t)header->type);
}
file_offset +=
sizeof(*header) + iree_host_align(header->content_length, 16);
}
return iree_ok_status();
}
int main(int argc, char** argv) {
IREE_TRACE_APP_ENTER();
if (argc < 2) {
fprintf(stderr,
"Syntax: iree-dump-instruments instruments.bin > instruments.txt\n"
"Example usage:\n"
" $ iree-compile \\n"
" --iree-hal-target-backends=llvm-cpu \\n"
" --iree-hal-instrument-dispatches=16mib \\n"
" --iree-llvmcpu-instrument-memory-accesses=false \\n"
" runtime/src/iree/runtime/demo/simple_mul.mlir \\n"
" -o=simple_mul_instr.vmfb\n"
" $ iree-run-module \\n"
" --device=local-sync \\n"
" --module=simple_mul_instr.vmfb \\n"
" --function=simple_mul \\n"
" --input=4xf32=2 \\n"
" --input=4xf32=4 \\n"
" --instrument_file=instrument.bin\n"
" $ iree-dump-instruments instrument.bin\n"
"\n");
IREE_TRACE_APP_EXIT(EXIT_FAILURE);
return EXIT_FAILURE;
}
iree_file_contents_t* file_contents = NULL;
iree_status_t status =
iree_file_read_contents(argv[1], IREE_FILE_READ_FLAG_DEFAULT,
iree_allocator_system(), &file_contents);
if (iree_status_is_ok(status)) {
status =
iree_tooling_dump_instrument_file(file_contents->const_buffer, stdout);
}
iree_file_contents_free(file_contents);
if (!iree_status_is_ok(status)) {
iree_status_fprint(stderr, status);
iree_status_free(status);
IREE_TRACE_APP_EXIT(EXIT_FAILURE);
return EXIT_FAILURE;
}
IREE_TRACE_APP_EXIT(EXIT_SUCCESS);
return EXIT_SUCCESS;
}