Making ATT work with Profilerv2
Change-Id: Ic9334aa80e40faaaf5c1a79ba37dbe52e8d31253
[ROCm/rocprofiler commit: 03c305dbd4]
Этот коммит содержится в:
коммит произвёл
Ammar ELWazir
родитель
f7772fb704
Коммит
4f742d346b
@@ -471,7 +471,7 @@ typedef enum {
|
||||
/**
|
||||
* Represents a ATT tracing record (Not available yet)
|
||||
*/
|
||||
ROCPROFILER_ATT_RECORD = 2,
|
||||
ROCPROFILER_ATT_TRACER_RECORD = 2,
|
||||
/**
|
||||
* Represents a PC sampling record
|
||||
*/
|
||||
@@ -1046,6 +1046,66 @@ typedef struct {
|
||||
|
||||
} rocprofiler_record_spm_t;
|
||||
|
||||
/**
|
||||
* struct to store the trace data from a shader engine.
|
||||
*/
|
||||
typedef struct {
|
||||
void* buffer_ptr;
|
||||
uint32_t buffer_size;
|
||||
} rocprofiler_record_se_att_data_t;
|
||||
|
||||
/**
|
||||
* ATT tracing record structure.
|
||||
* This will represent all the information reported by the
|
||||
* ATT tracer such as the kernel and its thread trace data.
|
||||
* This record can be flushed to the user using
|
||||
* ::rocmtools_buffer_callback_t
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* ROCMtool General Record base header to identify the id and kind of every
|
||||
* record
|
||||
*/
|
||||
rocprofiler_record_header_t header;
|
||||
/**
|
||||
* Kernel Identifier to be used by the user to get the kernel info using
|
||||
* ::rocmtools_query_kernel_info
|
||||
*/
|
||||
rocprofiler_kernel_id_t kernel_id;
|
||||
/**
|
||||
* Agent Identifier to be used by the user to get the Agent Information using
|
||||
* ::rocmtools_query_agent_info
|
||||
*/
|
||||
rocprofiler_agent_id_t gpu_id;
|
||||
/**
|
||||
* Queue Identifier to be used by the user to get the Queue Information using
|
||||
* ::rocmtools_query_agent_info
|
||||
*/
|
||||
rocprofiler_queue_id_t queue_id;
|
||||
/**
|
||||
* kernel properties, including the grid size, work group size,
|
||||
* registers count, wave size and completion signal
|
||||
*/
|
||||
rocprofiler_kernel_properties_t kernel_properties;
|
||||
/**
|
||||
* Thread id
|
||||
*/
|
||||
rocprofiler_thread_id_t thread_id;
|
||||
/**
|
||||
* Queue Index - packet index in the queue
|
||||
*/
|
||||
rocprofiler_queue_index_t queue_idx;
|
||||
/**
|
||||
* ATT data output from each shader engine.
|
||||
*/
|
||||
rocprofiler_record_se_att_data_t* shader_engine_data;
|
||||
/**
|
||||
* The count of the shader engine ATT data
|
||||
*/
|
||||
uint64_t shader_engine_data_count;
|
||||
} rocprofiler_record_att_tracer_t;
|
||||
|
||||
|
||||
|
||||
/** @} */
|
||||
|
||||
@@ -1721,7 +1781,7 @@ typedef enum {
|
||||
/**
|
||||
* ATT Tracing. (Not Yet Supported)
|
||||
*/
|
||||
ROCPROFILER_ATT_TRACE = 4,
|
||||
ROCPROFILER_ATT_TRACE_COLLECTION = 4,
|
||||
/**
|
||||
* SPM collection. (Not Yet Supported)
|
||||
*/
|
||||
@@ -1764,6 +1824,31 @@ typedef enum {
|
||||
typedef const char* rocprofiler_hip_function_name_t;
|
||||
typedef const char* rocprofiler_hsa_function_name_t;
|
||||
|
||||
// ATT tracing parameter names
|
||||
typedef enum {
|
||||
ROCPROFILER_ATT_COMPUTE_UNIT_TARGET = 0,
|
||||
ROCPROFILER_ATT_VM_ID_MASK = 1,
|
||||
ROCPROFILER_ATT_MASK = 2,
|
||||
ROCPROFILER_ATT_TOKEN_MASK = 3,
|
||||
ROCPROFILER_ATT_TOKEN_MASK2 = 4,
|
||||
ROCPROFILER_ATT_SE_MASK = 5,
|
||||
ROCPROFILER_ATT_SAMPLE_RATE = 6,
|
||||
ROCPROFILER_ATT_PERF_MASK = 240,
|
||||
ROCPROFILER_ATT_PERF_CTRL = 241,
|
||||
ROCPROFILER_ATT_PERFCOUNTER = 242,
|
||||
ROCPROFILER_ATT_PERFCOUNTER_NAME = 243,
|
||||
ROCPROFILER_ATT_MAXVALUE
|
||||
} rocprofiler_att_parameter_name_t;
|
||||
|
||||
// att tracing parameters object
|
||||
typedef struct {
|
||||
rocprofiler_att_parameter_name_t parameter_name;
|
||||
union {
|
||||
uint32_t value;
|
||||
const char* counter_name;
|
||||
};
|
||||
} rocprofiler_att_parameter_t;
|
||||
|
||||
/**
|
||||
* Filter Data Type
|
||||
* filter data will be used to report required and optional filters for the
|
||||
@@ -1822,6 +1907,10 @@ typedef union {
|
||||
* Counters to profile
|
||||
*/
|
||||
const char** counters_names;
|
||||
/**
|
||||
* att parameters
|
||||
*/
|
||||
rocprofiler_att_parameter_t* att_parameters;
|
||||
/**
|
||||
* spm counters parameters
|
||||
*/
|
||||
|
||||
@@ -23,3 +23,4 @@
|
||||
add_subdirectory(file)
|
||||
add_subdirectory(perfetto)
|
||||
add_subdirectory(ctf)
|
||||
add_subdirectory(att)
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
# ###############################################################################
|
||||
# # Copyright (c) 2022 Advanced Micro Devices, Inc.
|
||||
# #
|
||||
# # 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 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.
|
||||
# ###############################################################################
|
||||
|
||||
# Building att plugin library
|
||||
file(GLOB ROCMTOOLS_UTIL_SRC_FILES ${PROJECT_SOURCE_DIR}/src/utils/helper.cpp)
|
||||
file(GLOB FILE_SOURCES att.cpp)
|
||||
add_library(att_plugin SHARED ${FILE_SOURCES} ${ROCMTOOLS_UTIL_SRC_FILES})
|
||||
|
||||
set_target_properties(att_plugin PROPERTIES
|
||||
CXX_VISIBILITY_PRESET hidden
|
||||
LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../exportmap
|
||||
LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
|
||||
|
||||
target_compile_definitions(att_plugin
|
||||
PRIVATE HIP_PROF_HIP_API_STRING=1 __HIP_PLATFORM_HCC__=1)
|
||||
|
||||
target_include_directories(att_plugin PRIVATE ${PROJECT_SOURCE_DIR}/inc ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_options(att_plugin PRIVATE -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../exportmap -Wl,--no-undefined)
|
||||
target_link_libraries(att_plugin PRIVATE ${ROCPROFILER_TARGET} systemd hsa-runtime64::hsa-runtime64 stdc++fs)
|
||||
|
||||
install(TARGETS att_plugin LIBRARY
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}
|
||||
COMPONENT runtime)
|
||||
|
||||
configure_file(att.py att/att.py COPYONLY)
|
||||
configure_file(trace_view.py att/trace_view.py COPYONLY)
|
||||
#configure_file(t.db att/t.db COPYONLY)
|
||||
configure_file(ui/index.html att/ui/index.html COPYONLY)
|
||||
configure_file(ui/logo.svg att/ui/logo.svg COPYONLY)
|
||||
configure_file(ui/styles.css att/ui/styles.css COPYONLY)
|
||||
#configure_file(ui/trace.json att/ui/trace.json COPYONLY)
|
||||
install(DIRECTORY
|
||||
${CMAKE_CURRENT_BINARY_DIR}/att
|
||||
DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/rocprofiler
|
||||
USE_SOURCE_PERMISSIONS
|
||||
COMPONENT runtime)
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
/* Copyright (c) 2022 Advanced Micro Devices, Inc.
|
||||
|
||||
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 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 <cxxabi.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <experimental/filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <hsa/hsa.h>
|
||||
#include <mutex>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "rocprofiler.h"
|
||||
#include "rocprofiler_plugin.h"
|
||||
#include "../utils.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class att_plugin_t {
|
||||
public:
|
||||
att_plugin_t() {}
|
||||
|
||||
std::mutex writing_lock;
|
||||
bool is_valid_{true};
|
||||
|
||||
inline bool att_file_exists(const std::string& name) {
|
||||
struct stat buffer;
|
||||
return stat(name.c_str(), &buffer) == 0;
|
||||
}
|
||||
|
||||
bool IsValid() const { return is_valid_; }
|
||||
|
||||
void FlushATTRecord(const rocprofiler_record_att_tracer_t* att_tracer_record,
|
||||
rocprofiler_session_id_t session_id, rocprofiler_buffer_id_t buffer_id) {
|
||||
std::lock_guard<std::mutex> lock(writing_lock);
|
||||
|
||||
if (!att_tracer_record) {
|
||||
printf("No att data buffer received\n");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t name_length;
|
||||
CHECK_ROCMTOOLS(rocprofiler_query_kernel_info_size(ROCPROFILER_KERNEL_NAME,
|
||||
att_tracer_record->kernel_id, &name_length));
|
||||
const char* kernel_name_c = static_cast<const char*>(malloc(name_length * sizeof(char)));
|
||||
CHECK_ROCMTOOLS(rocprofiler_query_kernel_info(ROCPROFILER_KERNEL_NAME,
|
||||
att_tracer_record->kernel_id, &kernel_name_c));
|
||||
|
||||
std::string name_demangled = rocmtools::truncate_name(rocmtools::cxx_demangle(kernel_name_c));
|
||||
|
||||
// Get the number of shader engine traces
|
||||
int se_num = att_tracer_record->shader_engine_data_count;
|
||||
|
||||
// Find if this filename already exists. If so, increment vname.
|
||||
int file_iteration = -1;
|
||||
bool bIncrementVersion = true;
|
||||
while(bIncrementVersion) {
|
||||
file_iteration += 1;
|
||||
std::string fss = name_demangled+"_v"+std::to_string(file_iteration);
|
||||
bIncrementVersion = att_file_exists(fss + "_kernel.txt");
|
||||
}
|
||||
|
||||
std::string fname = name_demangled+"_v"+std::to_string(file_iteration)+"_kernel.txt";
|
||||
std::ofstream(fname.c_str()) << name_demangled << ": " << kernel_name_c << '\n';
|
||||
|
||||
// iterate over each shader engine att trace
|
||||
for (int i = 0; i < se_num; i++) {
|
||||
if (!att_tracer_record->shader_engine_data &&
|
||||
!att_tracer_record->shader_engine_data[i].buffer_ptr)
|
||||
continue;
|
||||
printf("--------------collecting data for shader_engine %d---------------\n", i);
|
||||
rocprofiler_record_se_att_data_t* se_att_trace = &att_tracer_record->shader_engine_data[i];
|
||||
uint32_t size = se_att_trace->buffer_size;
|
||||
const char* data_buffer_ptr = reinterpret_cast<char*>(se_att_trace->buffer_ptr);
|
||||
|
||||
// dump data in binary format
|
||||
std::ostringstream oss;
|
||||
oss << name_demangled << "_v" << file_iteration << "_se" << i << ".att";
|
||||
std::ofstream out(oss.str().c_str(), std::ios::binary);
|
||||
if (out.is_open()) {
|
||||
out.write((char*)data_buffer_ptr, size);
|
||||
out.close();
|
||||
} else {
|
||||
std::cerr << "\t" << __FUNCTION__ << " Failed to open file: " << oss.str().c_str() << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int WriteBufferRecords(const rocprofiler_record_header_t* begin,
|
||||
const rocprofiler_record_header_t* end, rocprofiler_session_id_t session_id,
|
||||
rocprofiler_buffer_id_t buffer_id) {
|
||||
while (begin < end) {
|
||||
if (!begin) return 0;
|
||||
switch (begin->kind) {
|
||||
case ROCPROFILER_PROFILER_RECORD:
|
||||
case ROCPROFILER_TRACER_RECORD:
|
||||
case ROCPROFILER_PC_SAMPLING_RECORD:
|
||||
case ROCPROFILER_SPM_RECORD:
|
||||
printf("Invalid record Kind: %d", begin->kind);
|
||||
break;
|
||||
|
||||
case ROCPROFILER_ATT_TRACER_RECORD: {
|
||||
rocprofiler_record_att_tracer_t* att_record = const_cast<rocprofiler_record_att_tracer_t*>(
|
||||
reinterpret_cast<const rocprofiler_record_att_tracer_t*>(begin));
|
||||
FlushATTRecord(att_record, session_id, buffer_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
rocprofiler_next_record(begin, &begin, session_id, buffer_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
att_plugin_t* att_plugin = nullptr;
|
||||
|
||||
} // namespace
|
||||
|
||||
ROCPROFILER_EXPORT int rocprofiler_plugin_initialize(uint32_t rocprofiler_major_version,
|
||||
uint32_t rocprofiler_minor_version) {
|
||||
if (rocprofiler_major_version != ROCPROFILER_VERSION_MAJOR ||
|
||||
rocprofiler_minor_version < ROCPROFILER_VERSION_MINOR)
|
||||
return -1;
|
||||
|
||||
if (att_plugin != nullptr) return -1;
|
||||
|
||||
att_plugin = new att_plugin_t();
|
||||
if (att_plugin->IsValid()) return 0;
|
||||
|
||||
// The plugin failed to initialied, destroy it and return an error.
|
||||
delete att_plugin;
|
||||
att_plugin = nullptr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ROCPROFILER_EXPORT void rocprofiler_plugin_finalize() {
|
||||
if (!att_plugin) return;
|
||||
delete att_plugin;
|
||||
att_plugin = nullptr;
|
||||
}
|
||||
|
||||
ROCPROFILER_EXPORT int rocprofiler_plugin_write_buffer_records(const rocprofiler_record_header_t* begin,
|
||||
const rocprofiler_record_header_t* end,
|
||||
rocprofiler_session_id_t session_id,
|
||||
rocprofiler_buffer_id_t buffer_id) {
|
||||
if (!att_plugin || !att_plugin->IsValid()) return -1;
|
||||
return att_plugin->WriteBufferRecords(begin, end, session_id, buffer_id);
|
||||
}
|
||||
|
||||
ROCPROFILER_EXPORT int rocprofiler_plugin_write_record(rocprofiler_record_tracer_t record,
|
||||
rocprofiler_session_id_t session_id) {
|
||||
if (!att_plugin || !att_plugin->IsValid()) return -1;
|
||||
if (record.header.id.handle == 0) return 0;
|
||||
return 0;
|
||||
}
|
||||
Исполняемый файл
+523
@@ -0,0 +1,523 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
if sys.version_info[0] < 3:
|
||||
raise Exception("Must be using Python 3")
|
||||
|
||||
import os
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from struct import *
|
||||
from ctypes import *
|
||||
import ctypes
|
||||
from copy import deepcopy
|
||||
from trace_view import view_trace
|
||||
import sys
|
||||
import glob
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import json
|
||||
|
||||
class PerfEvent(ctypes.Structure):
|
||||
_fields_ = [
|
||||
('time', c_uint64),
|
||||
('event0', c_uint16),
|
||||
('event1', c_uint16),
|
||||
('event2', c_uint16),
|
||||
('event3', c_uint16),
|
||||
('cu', c_uint8),
|
||||
('bank', c_uint8),
|
||||
]
|
||||
def toTuple(self):
|
||||
return (int(self.time), int(self.event0), int(self.event1),
|
||||
int(self.event2), int(self.event3), int(self.cu), int(self.bank))
|
||||
|
||||
|
||||
class CodeWrapped(ctypes.Structure):
|
||||
""" Matches CodeWrapped on the python side """
|
||||
_fields_ = [('line', ctypes.c_char_p),
|
||||
('loc', ctypes.c_char_p),
|
||||
('value', ctypes.c_int),
|
||||
('to_line', ctypes.c_int),
|
||||
('index', ctypes.c_int),
|
||||
('line_num', ctypes.c_int)]
|
||||
|
||||
|
||||
class KvPair(ctypes.Structure):
|
||||
""" Matches pair<int, int> = (key, value) on the python side """
|
||||
_fields_ = [('key', ctypes.c_int),
|
||||
('value', ctypes.c_int)]
|
||||
|
||||
|
||||
class ReturnAssemblyInfo(ctypes.Structure):
|
||||
""" Matches ReturnAssemblyInfo on the python side """
|
||||
_fields_ = [('code', POINTER(CodeWrapped)),
|
||||
('jumps', POINTER(KvPair)),
|
||||
('code_len', ctypes.c_int),
|
||||
('jumps_len', ctypes.c_int)]
|
||||
|
||||
|
||||
class Wave(ctypes.Structure):
|
||||
_fields_ = [
|
||||
('simd', ctypes.c_uint64),
|
||||
('wave_id', ctypes.c_uint64),
|
||||
('begin_time', ctypes.c_uint64), # Begin and end cycle
|
||||
('end_time', ctypes.c_uint64),
|
||||
|
||||
# total VMEM/FLAT/LDS/SMEM instructions issued
|
||||
# total issued memory instructions
|
||||
('num_mem_instrs', ctypes.c_uint64),
|
||||
# total issued instructions (compute + memory)
|
||||
('num_issued_instrs', ctypes.c_uint64),
|
||||
('num_valu_instrs', ctypes.c_uint64),
|
||||
('num_valu_stalls', ctypes.c_uint64),
|
||||
# VMEM Pipeline: instrs and stalls
|
||||
('num_vmem_instrs', ctypes.c_uint64),
|
||||
('num_vmem_stalls', ctypes.c_uint64),
|
||||
# FLAT instrs and stalls
|
||||
('num_flat_instrs', ctypes.c_uint64),
|
||||
('num_flat_stalls', ctypes.c_uint64),
|
||||
|
||||
# LDS instr and stalls
|
||||
('num_lds_instrs', ctypes.c_uint64),
|
||||
('num_lds_stalls', ctypes.c_uint64),
|
||||
|
||||
# SCA instrs stalls
|
||||
('num_salu_instrs', ctypes.c_uint64),
|
||||
('num_smem_instrs', ctypes.c_uint64),
|
||||
('num_salu_stalls', ctypes.c_uint64),
|
||||
('num_smem_stalls', ctypes.c_uint64),
|
||||
|
||||
# Branch
|
||||
('num_branch_instrs', ctypes.c_uint64),
|
||||
('num_branch_taken_instrs', ctypes.c_uint64),
|
||||
('num_branch_stalls', ctypes.c_uint64),
|
||||
|
||||
('timeline_string', ctypes.c_char_p),
|
||||
('instructions_string', ctypes.c_char_p)]
|
||||
|
||||
|
||||
class ReturnInfo(ctypes.Structure):
|
||||
_fields_ = [('num_waves', ctypes.c_uint64),
|
||||
('wavedata', POINTER(Wave)),
|
||||
('num_events', ctypes.c_uint64),
|
||||
('perfevents', POINTER(PerfEvent))]
|
||||
|
||||
try: # For build dir
|
||||
path_to_parser = os.path.abspath('/usr/lib/hsa-amd-aqlprofile/librocprofv2_att.so')
|
||||
SO = CDLL(path_to_parser)
|
||||
except: # For installed dir
|
||||
path_to_parser = os.path.abspath('/usr/local/lib/hsa-amd-aqlprofile/librocprofv2_att.so')
|
||||
SO = CDLL(path_to_parser)
|
||||
|
||||
SO.AnalyseBinary.restype = ReturnInfo
|
||||
SO.AnalyseBinary.argtypes = [ctypes.c_char_p, ctypes.c_int, ctypes.c_bool]
|
||||
SO.wrapped_parse_binary.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
|
||||
SO.wrapped_parse_binary.restype = ReturnAssemblyInfo
|
||||
|
||||
def parse_binary(filename, kernel=None):
|
||||
if kernel is None or kernel == '':
|
||||
kernel = ctypes.c_char_p(0)
|
||||
print('Parsing all kernels')
|
||||
else:
|
||||
with open(glob.glob(kernel)[0], 'r') as file:
|
||||
kernel = file.readlines()
|
||||
print('Parsing kernel:', kernel[0].split(': ')[0])
|
||||
kernel = kernel[0].split(': ')[1].split('.kd')[0]
|
||||
kernel = str(kernel).encode('utf-8')
|
||||
info = SO.wrapped_parse_binary(str(filename).encode('utf-8'), kernel)
|
||||
|
||||
code = []
|
||||
for k in range(info.code_len):
|
||||
code_entry = info.code[k]
|
||||
|
||||
# copy string memory from C++
|
||||
line = deepcopy(code_entry.line.decode("utf-8"))
|
||||
loc = deepcopy(code_entry.loc.decode("utf-8"))
|
||||
|
||||
# Transform empty entries back to python's None
|
||||
to_line = int(code_entry.to_line) if (code_entry.to_line >= 0) else None
|
||||
loc = loc if len(loc) > 0 else None
|
||||
|
||||
code.append((line, int(code_entry.value), to_line, loc,
|
||||
int(code_entry.index), int(code_entry.line_num)))
|
||||
|
||||
jumps = {}
|
||||
for k in range(info.jumps_len):
|
||||
jumps[info.jumps[k].key] = info.jumps[k].value
|
||||
|
||||
return code, jumps
|
||||
|
||||
|
||||
def getWaves(filename, target_cu, verbose):
|
||||
info = SO.AnalyseBinary(filename.encode('utf-8'), target_cu, verbose)
|
||||
|
||||
waves = [info.wavedata[k] for k in range(info.num_waves)]
|
||||
events = [deepcopy(info.perfevents[k]) for k in range(info.num_events)]
|
||||
|
||||
for wave in waves:
|
||||
wave.timeline = deepcopy(wave.timeline_string.decode("utf-8"))
|
||||
wave.instructions = deepcopy(wave.instructions_string.decode("utf-8"))
|
||||
|
||||
return waves, events
|
||||
|
||||
|
||||
def persist(output_ui, trace_file, SIMD):
|
||||
trace = Path(trace_file).name
|
||||
simds, waves = [], []
|
||||
begin_time, end_time, timeline, instructions = [], [], [], []
|
||||
mem_ins, issued_ins, valu_ins, valu_stalls = [], [], [], []
|
||||
vmem_ins, vmem_stalls, flat_ins, flat_stalls = [], [], [], []
|
||||
lds_ins, lds_stalls, salu_ins, salu_stalls = [], [], [], []
|
||||
smem_ins, smem_stalls, br_ins, br_taken_ins, br_stalls = [], [], [], [], []
|
||||
|
||||
for wave in SIMD:
|
||||
simds.append(wave.simd)
|
||||
waves.append(wave.wave_id)
|
||||
begin_time.append(wave.begin_time)
|
||||
end_time.append(wave.end_time)
|
||||
mem_ins.append(wave.num_mem_instrs)
|
||||
issued_ins.append(wave.num_issued_instrs)
|
||||
valu_ins.append(wave.num_valu_instrs)
|
||||
valu_stalls.append(wave.num_valu_stalls)
|
||||
vmem_ins.append(wave.num_vmem_instrs)
|
||||
vmem_stalls.append(wave.num_vmem_stalls)
|
||||
flat_ins.append(wave.num_flat_instrs)
|
||||
flat_stalls.append(wave.num_flat_stalls)
|
||||
lds_ins.append(wave.num_lds_instrs)
|
||||
lds_stalls.append(wave.num_lds_stalls)
|
||||
salu_ins.append(wave.num_salu_instrs)
|
||||
salu_stalls.append(wave.num_salu_stalls)
|
||||
smem_ins.append(wave.num_smem_instrs)
|
||||
smem_stalls.append(wave.num_smem_stalls)
|
||||
br_ins.append(wave.num_branch_instrs)
|
||||
br_taken_ins.append(wave.num_branch_taken_instrs)
|
||||
br_stalls.append(wave.num_branch_stalls)
|
||||
timeline.append(wave.timeline)
|
||||
instructions.append(wave.instructions)
|
||||
|
||||
#df = pd.DataFrame({
|
||||
df = {
|
||||
'name': [trace for _ in range(len(begin_time))],
|
||||
'id': [i for i in range(len(begin_time))],
|
||||
'simd': simds,
|
||||
'wave_slot': waves,
|
||||
'begin_time': begin_time,
|
||||
'end_time': end_time,
|
||||
'mem_ins': mem_ins,
|
||||
'issued_ins': issued_ins,
|
||||
'valu_ins': valu_ins,
|
||||
'valu_stalls': valu_stalls,
|
||||
'vmem_ins': vmem_ins,
|
||||
'vmem_stalls': vmem_stalls,
|
||||
'flat_ins': flat_ins,
|
||||
'flat_stalls': flat_stalls,
|
||||
'lds_ins': lds_ins,
|
||||
'lds_stalls': lds_stalls,
|
||||
'salu_ins': salu_ins,
|
||||
'salu_stalls': salu_stalls,
|
||||
'smem_ins': smem_ins,
|
||||
'smem_stalls': smem_stalls,
|
||||
'br_ins': br_ins,
|
||||
'br_taken_ins': br_taken_ins,
|
||||
'br_stalls': br_stalls,
|
||||
'timeline': timeline,
|
||||
'instructions': instructions,
|
||||
}#)
|
||||
#[print(d) for c, d in df.iterrows()]; quit()
|
||||
return df
|
||||
|
||||
|
||||
def mem_max(array):
|
||||
mem_dict = {}
|
||||
for SE in array:
|
||||
for wave in SE:
|
||||
for inst in wave:
|
||||
try:
|
||||
mem_dict[inst[0]][0] = max(mem_dict[inst[0]][0], inst[1])
|
||||
except:
|
||||
mem_dict[inst[0]] = inst[1:]
|
||||
assert(mem_dict[inst[0]][1] == inst[2])
|
||||
|
||||
return mem_dict
|
||||
|
||||
def lgk(count):
|
||||
return 'lgkmcnt({0})'.format(count)
|
||||
def vmc(count):
|
||||
return 'vmcnt({0})'.format(count)
|
||||
def both_cnt(count):
|
||||
return lgk(count)+' '+vmc(count)
|
||||
|
||||
def insert_waitcnt(flight_count, assembly_code):
|
||||
flight_count = mem_max(flight_count)
|
||||
for key in sorted(flight_count):
|
||||
line_n = key
|
||||
issue_amount, waitcnt_amount, = flight_count[key]
|
||||
if 'vmcnt' in assembly_code[line_n] and 'lgkmcnt' in assembly_code[line_n]:
|
||||
counter_type = both_cnt
|
||||
elif 'vmcnt' in assembly_code[line_n]:
|
||||
counter_type = vmc
|
||||
elif 'lgkmcnt' in assembly_code[line_n]:
|
||||
counter_type = lgk
|
||||
else:
|
||||
print('Error: Line mismatch')
|
||||
exit(-1)
|
||||
|
||||
for count in range(waitcnt_amount+1, issue_amount):
|
||||
print('Inserted line: '+str(line_n))
|
||||
as_index = line_n - count/(issue_amount+1)
|
||||
assembly_code[as_index] = \
|
||||
'\ts_waitcnt {0}\t\t; Timing analysis.'.format(counter_type(count))
|
||||
as_index += 0.5/(issue_amount+1)
|
||||
assembly_code[as_index] = '\ts_nop 0\t\t\t\t\t\t; Counters: '+str(issue_amount)
|
||||
|
||||
return assembly_code
|
||||
|
||||
|
||||
def Copy_Files(output_ui):
|
||||
curpath = os.path.dirname(os.path.abspath(__file__))
|
||||
outpath = output_ui+'/ui/'
|
||||
|
||||
os.makedirs(outpath, exist_ok=True)
|
||||
os.system('cp '+curpath+'/ui/* '+outpath)
|
||||
|
||||
|
||||
def get_delta_time(events):
|
||||
for begin in range(len(events)):
|
||||
tg_cu = events[begin].cu
|
||||
for e in range(begin+1,len(events)):
|
||||
if events[e].cu == tg_cu:
|
||||
return events[e].time-events[begin].time
|
||||
return 1
|
||||
|
||||
|
||||
def num_cus(EVENTS):
|
||||
cus = 0
|
||||
for events in EVENTS:
|
||||
for e in events:
|
||||
cus = max(cus, e.cu)
|
||||
return cus+1
|
||||
|
||||
|
||||
def draw_wave_metrics(selections, normalize):
|
||||
global PIC_SAVE_FOLDER
|
||||
global EVENTS
|
||||
global EVENT_NAMES
|
||||
|
||||
#event_names = ['Busy CUs', 'Occupancy', 'Eligible waves', 'Waves waiting']
|
||||
with open(PIC_SAVE_FOLDER+'counters.json', 'w') as f:
|
||||
f.write(json.dumps({"counters": EVENT_NAMES}))
|
||||
|
||||
plt.figure(figsize=(15,3))
|
||||
|
||||
delta_time = int(0.5+np.mean([get_delta_time(events) for events in EVENTS]))
|
||||
maxtime = np.max([np.max([e.time for e in events]) for events in EVENTS])+1
|
||||
event_timeline = np.zeros((16, maxtime), dtype=np.int32)
|
||||
print('Delta:', delta_time)
|
||||
print('Max_cycles:', maxtime)
|
||||
|
||||
kernsize = 2*(delta_time//8)+1
|
||||
trim = max(maxtime//5000,1)
|
||||
cycles = 4*np.arange(maxtime)[::trim]
|
||||
|
||||
kernel = np.asarray([np.exp(-abs(k/kernsize)**2) for k in range(-kernsize*3,kernsize*3+1)])
|
||||
kernel /= np.sum(kernel)*len(EVENTS)*delta_time#*5.12 # SEslots/100%
|
||||
|
||||
for events in EVENTS:
|
||||
for e in range(len(events)-1):
|
||||
bk = events[e].bank*4
|
||||
start = events[e].time
|
||||
end = start+delta_time
|
||||
event_timeline[bk:bk+4, start:end] += np.asarray(events[e].toTuple()[1:5])[:, None]
|
||||
start = events[-1].time
|
||||
event_timeline[bk:bk+4, start:start+delta_time] += \
|
||||
np.asarray(events[-1].toTuple()[1:5])[:, None]
|
||||
|
||||
event_timeline = [np.convolve(e, kernel)[3*kernsize:-3*kernsize] for e in event_timeline]
|
||||
|
||||
if normalize:
|
||||
event_timeline = [100*e/max(e.max(), 1E-5) for e in event_timeline]
|
||||
#event_timeline[0] = np.clip(event_timeline[0]*8.5, 0, 100) #CC rate
|
||||
|
||||
colors = ['blue', 'green', 'gray', 'red', 'orange', 'cyan', 'black', 'darkviolet',
|
||||
'yellow', 'darkred', 'pink', 'lime', 'gold', 'tan', 'aqua', 'olive']
|
||||
[plt.plot(cycles, e[::trim], '-', label=n, color=c)
|
||||
for e, n, c, sel in zip(event_timeline, EVENT_NAMES, colors, selections) if sel]
|
||||
|
||||
plt.legend()
|
||||
if normalize:
|
||||
plt.ylabel('As % of maximum')
|
||||
else:
|
||||
plt.ylabel('Value')
|
||||
plt.subplots_adjust(left=0.05, right=1, top=1, bottom=0.07)
|
||||
plt.savefig(PIC_SAVE_FOLDER+'timeline.png', dpi=150)
|
||||
#plt.show()
|
||||
|
||||
|
||||
def draw_wave_states(selections, normalize):
|
||||
global TIMELINES
|
||||
global PIC_SAVE_FOLDER
|
||||
plot_indices = [1, 2, 3, 4]
|
||||
STATES = [['Empty', 'Idle', 'Exec', 'Wait', 'Stall'][k] for k in plot_indices]
|
||||
colors = [['gray', 'orange', 'green', 'red', 'blue'][k] for k in plot_indices]
|
||||
|
||||
plt.figure(figsize=(15,3))
|
||||
|
||||
maxtime = max([np.max((TIMELINES[k]!=0)*np.arange(0,TIMELINES[k].size)) for k in plot_indices])
|
||||
timelines = [deepcopy(TIMELINES[k][:maxtime]) for k in plot_indices]
|
||||
timelines = [np.pad(t, [0, maxtime-t.size]) for t in timelines]
|
||||
|
||||
if normalize:
|
||||
timelines = np.array(timelines) / np.maximum(np.sum(timelines,0)*1E-2,1E-7)
|
||||
|
||||
kernsize = maxtime//120+3
|
||||
trim = max(maxtime//5000,1)
|
||||
cycles = np.arange(timelines[0].size)[::trim]
|
||||
|
||||
kernel = np.asarray([np.exp(-abs(10*k/kernsize)) for k in range(-kernsize//2,kernsize//2+1)])
|
||||
kernel /= np.sum(kernel)
|
||||
|
||||
timelines = [np.convolve(time, kernel)[kernsize//2:-kernsize//2][::trim] for time in timelines]
|
||||
|
||||
with open(PIC_SAVE_FOLDER+'counters.json', 'w') as f:
|
||||
f.write(json.dumps({"counters": STATES}))
|
||||
|
||||
[plt.plot(cycles, t, label='State '+s, linewidth=1.1, color=c)
|
||||
for t, s, c, sel in zip(timelines, STATES, colors, selections) if sel]
|
||||
|
||||
plt.legend()
|
||||
if normalize:
|
||||
plt.ylabel('Waves state %')
|
||||
else:
|
||||
plt.ylabel('Waves state total')
|
||||
plt.ylim(-1)
|
||||
plt.xlim(-maxtime//200, maxtime+maxtime//200)
|
||||
plt.subplots_adjust(left=0.05, right=1, top=1, bottom=0.07)
|
||||
plt.savefig(PIC_SAVE_FOLDER+'timeline.png', dpi=150)
|
||||
|
||||
|
||||
def GeneratePIC(selections=[True for k in range(4)], normalize=True):
|
||||
if len(EVENTS) > 0 and np.sum([len(e) for e in EVENTS]) > 32:
|
||||
draw_wave_metrics(selections, normalize)
|
||||
else:
|
||||
draw_wave_states(selections, normalize)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("assembly_code", help="Path of the assembly code")
|
||||
parser.add_argument("--trace_file", help="Filter for trace files", default=None, type=str)
|
||||
parser.add_argument("-o", "--output_ui", help="Output Folder", default='/dev/shm/attplugin/')
|
||||
parser.add_argument("-k", "--att_kernel", help="Kernel file", type=str, default='*_kernel.txt')
|
||||
parser.add_argument("-w", "--wave_id", help="wave id")
|
||||
parser.add_argument("-p", "--ports", help="Server and websocket ports, default: 8000,18000")
|
||||
parser.add_argument("--target_cu", help="Collected target CU id{0-15}", type=int, default=None)
|
||||
parser.add_argument("-v", "--verbose", action="store_true")
|
||||
parser.add_argument("-g", "--genasm",
|
||||
help="Generate post-processed asm file at this path", type=str, default="")
|
||||
args = parser.parse_args()
|
||||
|
||||
global EVENT_NAMES
|
||||
with open(os.getenv("COUNTERS_PATH"), 'r') as f:
|
||||
lines = [l.split('//')[0] for l in f.readlines()]
|
||||
|
||||
EVENT_NAMES = []
|
||||
clean = lambda x: x.split('=')[1].split(' ')[0].split('\n')[0]
|
||||
|
||||
for line in lines:
|
||||
if 'PERFCOUNTER_ID=' in line:
|
||||
EVENT_NAMES += ['id: '+clean(line)]
|
||||
elif args.target_cu is None and 'att: TARGET_CU' in line:
|
||||
args.target_cu = int(clean(line))
|
||||
print('Target CU set to:', args.target_cu)
|
||||
for line in lines:
|
||||
if 'PERFCOUNTER=' in line:
|
||||
EVENT_NAMES += [clean(line).split('SQ_')[1].lower()]
|
||||
|
||||
if args.target_cu is None:
|
||||
args.target_cu = 1
|
||||
|
||||
# Assembly parsing
|
||||
path = Path(args.assembly_code)
|
||||
if not path.is_file():
|
||||
print("Invalid assembly_code('{0}')!".format(args.assembly_code))
|
||||
sys.exit(1)
|
||||
|
||||
att_kernel = glob.glob(args.att_kernel)
|
||||
|
||||
if len(att_kernel) == 0:
|
||||
print('Could not find att output kernel:', args.att_kernel)
|
||||
exit(1)
|
||||
elif len(att_kernel) > 1:
|
||||
print('Found multiple kernel matching given filters:')
|
||||
for n, k in enumerate(att_kernel):
|
||||
print('\t', n, '->', k)
|
||||
|
||||
bValid = False
|
||||
while bValid == False:
|
||||
try:
|
||||
args.att_kernel = att_kernel[int(input("Please select number: "))]
|
||||
bValid = True
|
||||
except KeyboardInterrupt:
|
||||
exit(0)
|
||||
except:
|
||||
print('Invalid option.')
|
||||
else:
|
||||
args.att_kernel = att_kernel[0]
|
||||
|
||||
print('Att kernel:', args.att_kernel)
|
||||
code, jumps = parse_binary(args.assembly_code, args.att_kernel)
|
||||
|
||||
# Trace Parsing
|
||||
if args.trace_file is None:
|
||||
filenames = glob.glob(args.att_kernel.split('_kernel.txt')[0]+'*.att')
|
||||
assert(len(filenames) > 0)
|
||||
else:
|
||||
filenames = glob.glob(args.trace_file)
|
||||
|
||||
print('Trace filenames:', filenames)
|
||||
|
||||
Copy_Files(args.output_ui)
|
||||
DBFILES = []
|
||||
global TIMELINES
|
||||
global EVENTS
|
||||
TIMELINES = [np.zeros(int(1E4),dtype=np.int32) for k in range(5)]
|
||||
EVENTS = []
|
||||
for name in filenames:
|
||||
SIMD, perfevents = getWaves(name, args.target_cu, args.verbose)
|
||||
EVENTS.append(perfevents)
|
||||
DBFILES.append( persist(args.output_ui, name, SIMD) )
|
||||
for wave in SIMD:
|
||||
time_acc = 0
|
||||
tuples1 = wave.timeline.split('(')
|
||||
tuples2 = [t.split(')')[0].split(',') for t in tuples1 if t != '']
|
||||
tuples3 = [(int(t[0]),int(t[1])) for t in tuples2]
|
||||
|
||||
for state in tuples3:
|
||||
if state[1] > 1E7:
|
||||
print('Warning: Time limit reached for ',state[0], state[1])
|
||||
break
|
||||
|
||||
if time_acc+state[1] > TIMELINES[state[0]].size:
|
||||
TIMELINES[state[0]] = np.hstack([
|
||||
TIMELINES[state[0]],
|
||||
np.zeros_like(TIMELINES[state[0]])
|
||||
])
|
||||
TIMELINES[state[0]][time_acc:time_acc+state[1]] += 1
|
||||
time_acc += state[1]
|
||||
|
||||
if args.genasm and len(args.genasm) > 0:
|
||||
flight_count = view_trace(args, 0, code, jumps, DBFILES, filenames, True, None)
|
||||
|
||||
with open(args.assembly_code, 'r') as file:
|
||||
lines = file.readlines()
|
||||
assembly_code = {l+1.0: lines[l][:-1] for l in range(len(lines))}
|
||||
assembly_code = insert_waitcnt(flight_count, assembly_code)
|
||||
|
||||
with open(args.genasm, 'w') as file:
|
||||
keys = sorted(assembly_code.keys())
|
||||
for k in keys:
|
||||
file.write(assembly_code[k]+'\n')
|
||||
else:
|
||||
global PIC_SAVE_FOLDER
|
||||
PIC_SAVE_FOLDER = args.output_ui+"/ui/"
|
||||
view_trace(args, 0, code, jumps, DBFILES, filenames, False, GeneratePIC)
|
||||
Исполняемый файл
+465
@@ -0,0 +1,465 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
if sys.version_info[0] < 3:
|
||||
raise Exception("Must be using Python 3")
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import socket
|
||||
from pathlib import Path
|
||||
from struct import *
|
||||
from collections import defaultdict
|
||||
import json
|
||||
import time
|
||||
import webbrowser
|
||||
import http.server
|
||||
import socketserver
|
||||
import socket
|
||||
import asyncio
|
||||
import websockets
|
||||
from multiprocessing import *
|
||||
from copy import deepcopy
|
||||
|
||||
PORT, WebSocketPort = 8000, 18000
|
||||
SP = '\u00A0'
|
||||
|
||||
RS_TRACE_DEBUG = "RS_TRACE_DEBUG" in os.environ
|
||||
if RS_TRACE_DEBUG:
|
||||
LOG = open('./att_viewer.log', 'w')
|
||||
|
||||
|
||||
def get_ip():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.settimeout(0)
|
||||
try:
|
||||
hostname = socket.gethostname()
|
||||
IPAddr = socket.gethostbyname(hostname)
|
||||
s.connect(({IPAddr}, 1))
|
||||
except Exception:
|
||||
IPAddr = '127.0.0.1'
|
||||
finally:
|
||||
return IPAddr
|
||||
|
||||
|
||||
IPAddr = get_ip()
|
||||
|
||||
|
||||
def debug_log(msg, last=False):
|
||||
if RS_TRACE_DEBUG:
|
||||
LOG.write(msg)
|
||||
|
||||
if last:
|
||||
LOG.close()
|
||||
|
||||
|
||||
def try_match_swapped(insts, code, i, line):
|
||||
return insts[i+1][1] == code[line][1] and insts[i][1] == code[line+1][1]
|
||||
|
||||
|
||||
def stitch(insts, code, jumps):
|
||||
result, i, line, loopCount, N = [], 0, 0, defaultdict(int), len(insts)
|
||||
|
||||
SMEM_INST = []
|
||||
VMEM_INST = []
|
||||
FLAT_INST = []
|
||||
NUM_SMEM = 0
|
||||
NUM_VMEM = 0
|
||||
NUM_FLAT = 0
|
||||
|
||||
mem_unroll = []
|
||||
flight_count = []
|
||||
|
||||
ordering = 0 # 0 for in order, 1 for ongoing flats and 2 for SMEM
|
||||
while i < N:
|
||||
inst = insts[i]
|
||||
if line >= len(code):
|
||||
break
|
||||
|
||||
as_line = code[line]
|
||||
if inst[1] == as_line[1]:
|
||||
if line in jumps:
|
||||
loopCount[line-1] += 1 # label is the previous line
|
||||
matched, next = True, line + 1
|
||||
|
||||
num_inflight = NUM_FLAT + NUM_SMEM + NUM_VMEM
|
||||
|
||||
if inst[1] == 1 or inst[1] == 5: # SMEM, LDS
|
||||
ordering = 2 if inst[1] == 1 else ordering
|
||||
SMEM_INST.append([line, num_inflight])
|
||||
NUM_SMEM += 1
|
||||
elif inst[1] == 3 or (inst[1] == 4 and 'global_' in as_line[0]): # VMEM R/W
|
||||
VMEM_INST.append([line, num_inflight])
|
||||
NUM_VMEM += 1
|
||||
elif inst[1] == 4: # FLAT
|
||||
ordering = max(ordering, 1)
|
||||
FLAT_INST.append([line, num_inflight])
|
||||
NUM_FLAT += 1
|
||||
elif inst[1] == 9 and 'waitcnt' in as_line[0]:
|
||||
|
||||
if 'lgkmcnt' in as_line[0]:
|
||||
wait_N = int(as_line[0].split('lgkmcnt(')[1].split(')')[0])
|
||||
flight_count.append([as_line[-1], num_inflight, wait_N])
|
||||
if wait_N == 0:
|
||||
ordering = 0
|
||||
if ordering == 0:
|
||||
offset = len(SMEM_INST)-wait_N
|
||||
mem_unroll.append( [line, SMEM_INST[:offset]+FLAT_INST] )
|
||||
SMEM_INST = SMEM_INST[offset:]
|
||||
FLAT_INST = []
|
||||
NUM_FLAT = 0
|
||||
NUM_SMEM = 0
|
||||
else:
|
||||
NUM_SMEM = min(max(wait_N-NUM_FLAT, 0), NUM_SMEM)
|
||||
NUM_FLAT = min(max(wait_N-NUM_SMEM, 0), NUM_FLAT)
|
||||
|
||||
if 'vmcnt' in as_line[0]:
|
||||
wait_N = int(as_line[0].split('vmcnt(')[1].split(')')[0])
|
||||
flight_count.append([as_line[-1], num_inflight, wait_N])
|
||||
if wait_N == 0 and ordering != 2:
|
||||
ordering = 0
|
||||
if ordering == 0:
|
||||
offset = len(VMEM_INST)-wait_N
|
||||
mem_unroll.append( [line, VMEM_INST[:offset]+FLAT_INST] )
|
||||
VMEM_INST = VMEM_INST[offset:]
|
||||
FLAT_INST = []
|
||||
NUM_FLAT = 0
|
||||
NUM_VMEM = 0
|
||||
else:
|
||||
NUM_VMEM = min(max(wait_N-NUM_FLAT, 0), NUM_VMEM)
|
||||
NUM_FLAT = min(max(wait_N-NUM_VMEM, 0), NUM_FLAT)
|
||||
|
||||
|
||||
elif inst[1] == 7 and as_line[1] == 10: # jump
|
||||
matched, next = True, as_line[2]
|
||||
elif inst[1] == 8 and as_line[1] == 10: # next
|
||||
matched, next = True, line + 1
|
||||
else:
|
||||
# instructions with almost same timestamp swapped
|
||||
# if i+1 < N and line+1 < len(code) and inst[0] == insts[i+1][0]:
|
||||
matched = False
|
||||
next = line + 1
|
||||
if i+1 < N and line+1 < len(code):
|
||||
if try_match_swapped(insts, code, i, line):
|
||||
#print('Swap:', code[line])
|
||||
#print('For:', code[line+1])
|
||||
#result += (*(insts[i+1]), line),
|
||||
#result += (*inst, line+1),
|
||||
#i, next = i+2, line+2
|
||||
temp = insts[i]
|
||||
insts[i] = insts[i+1]
|
||||
insts[i+1] = temp
|
||||
next = line
|
||||
#else:
|
||||
# print('Could not parse tokens:', insts[i], as_line)
|
||||
|
||||
if matched:
|
||||
new_res = inst + (line,)
|
||||
result.append(new_res)
|
||||
i += 1
|
||||
line = next
|
||||
|
||||
N = max(N, 1)
|
||||
if len(result) != N:
|
||||
print('Warning - Stitching rate: {'+str(len(result) * 100 / N)+'% matched')
|
||||
|
||||
return result, loopCount, mem_unroll, flight_count
|
||||
|
||||
|
||||
def extract_tuple(content, num):
|
||||
vals = content.split(',')
|
||||
assert (len(vals) == num)
|
||||
last_val = vals[-1][:-1] if vals[-1].endswith(')') else vals[-1]
|
||||
vals = [vals[0][1:]] + vals[1:-1] + [last_val]
|
||||
return tuple(int(val) for val in vals)
|
||||
|
||||
|
||||
def get_top_n(stitched):
|
||||
TOP_N = 10
|
||||
by_line_num = defaultdict(lambda: [0, 0, 0])
|
||||
for (_, _, s2i, run_time, line_num) in stitched:
|
||||
entry = by_line_num[line_num]
|
||||
entry[0] += 1
|
||||
entry[1] += s2i
|
||||
entry[2] += run_time
|
||||
top_n = sorted(
|
||||
[(line_num, v[0], v[1], v[2])
|
||||
for (line_num, v) in by_line_num.items()],
|
||||
key=lambda x: x[2] + x[3],
|
||||
reverse=True)
|
||||
return top_n[:TOP_N]
|
||||
|
||||
|
||||
def rjust_html(s, n):
|
||||
s = str(s)
|
||||
return SP * (n-len(s)) + s if len(s) < n else s
|
||||
|
||||
|
||||
def rjust_html_format(msg, n1, inst, n2, n3, stall):
|
||||
return str(rjust_html(msg,n1)) + str(rjust_html(inst,n2)) + str(SP*n3) + str(stall)
|
||||
|
||||
|
||||
def wave_info(df, id):
|
||||
issued_ins, mem_ins = df['issued_ins'][id], df['mem_ins'][id]
|
||||
valu_ins, valu_stalls = df['valu_ins'][id], df['valu_stalls'][id]
|
||||
salu_ins, salu_stalls = df['salu_ins'][id], df['salu_stalls'][id]
|
||||
vmem_ins, vmem_stalls = df['vmem_ins'][id], df['vmem_stalls'][id]
|
||||
smem_ins, smem_stalls = df['smem_ins'][id], df['smem_stalls'][id]
|
||||
flat_ins, flat_stalls = df['flat_ins'][id], df['flat_stalls'][id]
|
||||
lds_ins, lds_stalls = df['lds_ins'][id], df['lds_stalls'][id]
|
||||
br_ins, br_stalls = df['br_ins'][id], df['br_stalls'][id]
|
||||
|
||||
return 'Issued:' + str(rjust_html(issued_ins,8)) + str(SP*2) + 'Mem:' + str(mem_ins) \
|
||||
+ "-" * 26 + rjust_html_format("VALU:",6,valu_ins,8,4,valu_stalls) \
|
||||
+ rjust_html_format("SALU:",6,salu_ins,8,4,salu_stalls) \
|
||||
+ rjust_html_format("VMEM:",6,vmem_ins,8,4,vmem_stalls) \
|
||||
+ rjust_html_format("SMEM:",6,smem_ins,8,4,smem_stalls) \
|
||||
+ rjust_html_format("FLAT:",6,flat_ins,8,4,flat_stalls) \
|
||||
+ rjust_html_format("LDS:",6,lds_ins,8,4,lds_stalls) \
|
||||
+ rjust_html_format("BR:",6,br_ins,8,4,br_stalls)
|
||||
|
||||
|
||||
def extract_waves(waves):
|
||||
result, slot2seq = [], {}
|
||||
for id in waves['id']:
|
||||
row = {key: waves[key][id] for key in waves.keys()}
|
||||
|
||||
insts, timeline = [], []
|
||||
for x in row['instructions'].split('),'):
|
||||
if len(x) > 0:
|
||||
insts.append(extract_tuple(x, 4))
|
||||
for x in row['timeline'].split('),'):
|
||||
if len(x) > 0:
|
||||
timeline.append(extract_tuple(x, 2))
|
||||
|
||||
# aggregate per wave slot
|
||||
if (row['simd'], row['wave_slot']) in slot2seq:
|
||||
slot = result[slot2seq[(row['simd'], row['wave_slot'])]]
|
||||
last_end_time = slot[2][-1][-1]
|
||||
slot[2] += (row['id'], row['begin_time'], row['end_time']),
|
||||
slot[3] += insts
|
||||
# filler between waves
|
||||
slot[4] += (0, row['begin_time'] - last_end_time),
|
||||
slot[4] += timeline
|
||||
else:
|
||||
slot2seq[row['simd'], row['wave_slot']] = len(result)
|
||||
result.append([row['simd'], row['wave_slot'],
|
||||
[(row['id'], row['begin_time'], row['end_time'])],
|
||||
insts,
|
||||
timeline])
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def extract_data(df, output_ui, se_number, code, jumps):
|
||||
if len(df['id']) == 0 or len(df['instructions']) == 0 or len(df['timeline']) == 0:
|
||||
return None
|
||||
|
||||
cu_waves = extract_waves(df)
|
||||
all_filenames = []
|
||||
flight_count = []
|
||||
|
||||
for wave_id in df['id']:
|
||||
insts, timeline = [], []
|
||||
if len(df['instructions'][wave_id]) == 0 or len(df['timeline'][wave_id]) == 0:
|
||||
continue
|
||||
|
||||
for x in df['instructions'][wave_id].split('),'):
|
||||
insts.append(extract_tuple(x, 4))
|
||||
for x in df['timeline'][wave_id].split('),'):
|
||||
timeline.append(extract_tuple(x, 2))
|
||||
|
||||
stitched, loopCount, mem_unroll, count = stitch(insts, code, jumps)
|
||||
flight_count.append(count)
|
||||
|
||||
wave_entry = {
|
||||
"id": int(df['id'][wave_id]),
|
||||
"simd": int(df['simd'][wave_id]),
|
||||
"slot": int(df['wave_slot'][wave_id]),
|
||||
"begin": int(df['begin_time'][wave_id]),
|
||||
"end": int(df['end_time'][wave_id]),
|
||||
"info": wave_info(df, wave_id),
|
||||
"instructions": stitched,
|
||||
"timeline": timeline,
|
||||
"code": code,
|
||||
"waitcnt": mem_unroll
|
||||
}
|
||||
data_obj = {
|
||||
"name": 'SE'.format(se_number),
|
||||
"kernel": code[0][0],
|
||||
"duration": sum(dur for (_, dur) in timeline),
|
||||
"wave": wave_entry,
|
||||
"simd_waves": [],
|
||||
"cu_waves": cu_waves,
|
||||
"loop_count": loopCount,
|
||||
"top_n": get_top_n(stitched),
|
||||
"websocket_port": WebSocketPort,
|
||||
"generation_time": time.ctime()
|
||||
}
|
||||
if len(data_obj["cu_waves"]) == 0:
|
||||
continue
|
||||
|
||||
OUT = output_ui+'/ui/se'+str(se_number)+'_sm'+str(df['simd'][wave_id])+\
|
||||
'_wv'+str(df['wave_slot'][wave_id])+'.json'
|
||||
|
||||
with open(OUT, 'w') as f:
|
||||
f.write(json.dumps(data_obj))
|
||||
all_filenames.append(OUT.split('/')[-1])
|
||||
|
||||
return flight_count, all_filenames
|
||||
|
||||
def open_browser():
|
||||
time.sleep(0.1)
|
||||
webbrowser.open_new_tab('http://{0}:{1}'.format(IPAddr, PORT))
|
||||
|
||||
|
||||
class NoCacheHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
|
||||
def end_headers(self):
|
||||
self.send_my_headers()
|
||||
http.server.SimpleHTTPRequestHandler.end_headers(self)
|
||||
|
||||
def send_my_headers(self):
|
||||
self.send_header("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||
self.send_header("Pragma", "no-cache")
|
||||
self.send_header("Expires", "0")
|
||||
|
||||
def do_GET(self):
|
||||
global PICTURE_CALLBACK
|
||||
if 'timeline.png?' in self.path:
|
||||
selections = [int(s)!=0 for s in self.path.split('timeline.png?')[1]]
|
||||
print('Sel:', selections)
|
||||
PICTURE_CALLBACK(selections[1:], selections[0])
|
||||
http.server.SimpleHTTPRequestHandler.do_GET(self)
|
||||
|
||||
class RocTCPServer(socketserver.TCPServer):
|
||||
def server_bind(self):
|
||||
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self.socket.bind(self.server_address)
|
||||
|
||||
|
||||
def run_server():
|
||||
global RS_HOME
|
||||
Handler = NoCacheHTTPRequestHandler
|
||||
|
||||
os.chdir(RS_HOME+'/ui')
|
||||
try:
|
||||
with RocTCPServer((IPAddr, PORT), Handler) as httpd:
|
||||
httpd.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
|
||||
def fix_space(line):
|
||||
line = line.replace(' ', SP)
|
||||
line = line.replace('\t', SP*4)
|
||||
return line
|
||||
|
||||
|
||||
def WebSocketserver(websocket, path):
|
||||
data = websocket.recv()
|
||||
print(354, data)
|
||||
cpp, ln, _ = data.split(':')
|
||||
ln = int(ln)
|
||||
HL, EMP = 'highlight', ''
|
||||
content = None
|
||||
print("loading...")
|
||||
try:
|
||||
f = open(cpp, 'r', errors='replace')
|
||||
content = ''.join('<li class=\"line_'+str(i)+
|
||||
str(HL if i==ln else EMP)+'">'+str(i).ljust(5)+fix_space(l)+'</li>'
|
||||
for i, l in enumerate(f.readlines(), 1))
|
||||
except FileNotFoundError:
|
||||
content = cpp + ' not found!'
|
||||
websocket.send(content)
|
||||
|
||||
|
||||
def run_websocket():
|
||||
start_server = websockets.serve(WebSocketserver, IPAddr, WebSocketPort)
|
||||
try:
|
||||
asyncio.get_event_loop().run_until_complete(start_server)
|
||||
asyncio.get_event_loop().run_forever()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
|
||||
def assign_ports(ports):
|
||||
ps = [int(port) for port in ports.split(',')]
|
||||
if ps[0] <= 5000 or ps[1] <= 5000:
|
||||
print('Need to have port values > 5000')
|
||||
sys.exit(1)
|
||||
elif ps[0] == ps[1]:
|
||||
print('Can not use the same port for both web server and websocket server: '+ps[0])
|
||||
sys.exit(1)
|
||||
global IPAddr, PORT, WebSocketPort
|
||||
PORT, WebSocketPort = ps[0], ps[1]
|
||||
|
||||
|
||||
def view_trace(args, wait, code, jumps, dbnames, att_filenames, bReturnLoc, pic_callback):
|
||||
global PICTURE_CALLBACK
|
||||
PICTURE_CALLBACK = pic_callback
|
||||
pic_thread = Process(target=pic_callback)
|
||||
pic_thread.start()
|
||||
|
||||
assert(len(dbnames) > 0)
|
||||
global RS_HOME
|
||||
output_ui = args.output_ui
|
||||
RS_HOME = output_ui
|
||||
|
||||
att_filenames = [Path(f).name for f in att_filenames]
|
||||
se_numbers = [int(a.split('_se')[1].split('.att')[0]) for a in att_filenames]
|
||||
flight_count = []
|
||||
simd_wave_filenames = {}
|
||||
|
||||
for se_number, dbname in zip(se_numbers, dbnames):
|
||||
if len(dbname['id']) == 0:
|
||||
continue
|
||||
|
||||
count, wv_filenames = extract_data(dbname, output_ui, se_number, code, jumps)
|
||||
|
||||
if count is not None:
|
||||
flight_count.append(count)
|
||||
simd_wave_filenames[se_number] = wv_filenames
|
||||
|
||||
if bReturnLoc:
|
||||
return flight_count
|
||||
|
||||
for key in simd_wave_filenames.keys():
|
||||
wv_array = [[
|
||||
int(s.split('_sm')[1].split('_wv')[0]),
|
||||
int(s.split('_wv')[1][0]),
|
||||
s
|
||||
] for s in simd_wave_filenames[key]]
|
||||
|
||||
wv_dict = {}
|
||||
for wv in wv_array:
|
||||
try:
|
||||
wv_dict[wv[0]][wv[1]] = wv[2]
|
||||
except:
|
||||
try:
|
||||
wv_dict[wv[0]] = {wv[1]: wv[2]}
|
||||
except:
|
||||
exit(-1)
|
||||
|
||||
simd_wave_filenames[key] = wv_dict
|
||||
|
||||
with open(output_ui+'/ui/filenames.json', 'w') as f:
|
||||
f.write(json.dumps({"filenames": simd_wave_filenames}))
|
||||
|
||||
if args.ports:
|
||||
assign_ports(args.ports)
|
||||
print('serving at ports: {0},{1}'.format(PORT, WebSocketPort))
|
||||
|
||||
if wait == 0:
|
||||
try:
|
||||
PROCS = [Process(target=run_server),
|
||||
Process(target=open_browser),
|
||||
Process(target=run_websocket)]
|
||||
if pic_thread is not None:
|
||||
pic_thread.join()
|
||||
|
||||
for p in PROCS:
|
||||
p.start()
|
||||
for p in PROCS:
|
||||
p.join()
|
||||
except KeyboardInterrupt:
|
||||
print("Exitting.")
|
||||
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@@ -0,0 +1,132 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="240"
|
||||
height="26"
|
||||
viewBox="0 0 68.974872 7.4722778"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||
sodipodi:docname="logo.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
inkscape:zoom="5.1659481"
|
||||
inkscape:cx="147.89154"
|
||||
inkscape:cy="75.10722"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2066"
|
||||
inkscape:window-x="-11"
|
||||
inkscape:window-y="-11"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs2" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<rect
|
||||
style="fill:#217844;stroke:#00000f;stroke-width:0.0610255;stroke-miterlimit:1"
|
||||
id="rect864"
|
||||
width="37.346996"
|
||||
height="6.0453367"
|
||||
x="26.672634"
|
||||
y="0.91105449" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:6.35px;font-family:Calibri;-inkscape-font-specification:Calibri;fill:#165016;stroke:#00000f;stroke-width:0.0539999;stroke-miterlimit:1;stroke-dasharray:none"
|
||||
x="82.180176"
|
||||
y="95.625328"
|
||||
id="text3303"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3301"
|
||||
style="fill:#165016;stroke-width:0.054"
|
||||
x="82.180176"
|
||||
y="95.625328" /></text>
|
||||
<!-- <g
|
||||
id="g5730"
|
||||
transform="matrix(0.57568164,0,0,0.53998363,-62.239348,-52.859622)">
|
||||
<g
|
||||
aria-label="AMD"
|
||||
id="text954"
|
||||
style="font-size:6.35px;font-family:Calibri;-inkscape-font-specification:Calibri;fill:#000080;stroke:#00000f;stroke-width:0.0539999;stroke-miterlimit:1"
|
||||
transform="translate(27.503837,13.598552)">
|
||||
<path
|
||||
d="m 89.87666,89.436026 q 0.04779,0.05463 0.06348,0.09511 0.01746,0.03646 0.0022,0.06566 -0.01528,0.0292 -0.06797,0.05628 -0.0498,0.02596 -0.139412,0.0607 -0.08962,0.03475 -0.146787,0.05026 -0.05316,0.01729 -0.08543,0.01982 -0.0305,-0.0015 -0.05168,-0.01322 -0.01829,-0.01286 -0.03994,-0.0344 l -0.673965,-0.786215 -1.555301,0.60303 0.04216,1.017881 q 0.0014,0.02938 -0.0052,0.05522 -0.0077,0.02295 -0.03103,0.04861 -0.02154,0.02165 -0.07133,0.04761 -0.0469,0.02484 -0.127848,0.05622 -0.08384,0.0325 -0.142126,0.04513 -0.05428,0.01439 -0.08525,0.0031 -0.02808,-0.01239 -0.04265,-0.04997 -0.0128,-0.04159 -0.01433,-0.11416 l -0.09264,-3.961315 q -7.66e-4,-0.03628 0.0087,-0.06324 0.01239,-0.02808 0.0426,-0.0531 0.0331,-0.02613 0.08691,-0.05032 0.05558,-0.0282 0.142303,-0.06183 0.09251,-0.03587 0.155459,-0.05362 0.06183,-0.02065 0.103895,-0.02366 0.04206,-0.003 0.07127,0.01227 0.02808,0.01239 0.05198,0.03971 z m -2.799476,-2.442912 -0.0029,0.0011 0.07829,2.114582 1.300903,-0.504394 z"
|
||||
style="stroke-width:0.054"
|
||||
id="path4984" />
|
||||
<path
|
||||
d="m 94.99296,89.362526 q -2.68e-4,0.0248 -0.01287,0.04327 -0.0126,0.01847 -0.04374,0.03054 -0.0311,0.009 -0.08078,0.01463 -0.04661,0.0088 -0.124117,0.008 -0.07131,-7.69e-4 -0.123916,-0.01064 -0.04954,-0.0067 -0.08044,-0.01637 -0.02777,-0.0127 -0.03997,-0.03144 -0.0122,-0.01874 -0.01193,-0.04354 l 0.03766,-3.494157 -0.0062,-6.7e-5 -1.467119,3.494252 q -0.0095,0.0216 -0.0283,0.0369 -0.01567,0.01533 -0.04991,0.02737 -0.0311,0.009 -0.07764,0.01157 -0.04347,0.0057 -0.105481,0.0051 -0.06511,-7.02e-4 -0.111547,-0.0074 -0.04644,-0.0067 -0.07734,-0.01634 -0.03087,-0.01274 -0.04931,-0.02844 -0.01533,-0.01567 -0.02133,-0.03434 l -1.329447,-3.524398 -0.0031,-3.4e-5 -0.03767,3.494158 q -2.67e-4,0.0248 -0.01287,0.04327 -0.0126,0.01847 -0.04374,0.03054 -0.0311,0.009 -0.08078,0.01463 -0.04971,0.0088 -0.127216,0.0079 -0.07441,-8.02e-4 -0.123916,-0.01064 -0.04954,-0.0067 -0.08044,-0.01637 -0.02777,-0.0127 -0.03997,-0.03144 -0.0091,-0.0187 -0.0088,-0.04351 l 0.03977,-3.689482 q 0.0014,-0.130217 0.07022,-0.18529 0.06881,-0.05507 0.152521,-0.05417 l 0.322442,0.0035 q 0.09921,0.0011 0.173422,0.02047 0.07421,0.0194 0.129582,0.06031 0.05537,0.04091 0.09191,0.103316 0.03654,0.06241 0.06354,0.146421 l 1.131337,2.917613 0.0155,1.67e-4 1.240374,-2.882745 q 0.03511,-0.09265 0.07611,-0.157319 0.04101,-0.06467 0.08791,-0.101377 0.05004,-0.03977 0.109116,-0.05464 0.05911,-0.01797 0.136618,-0.01713 l 0.337944,0.0036 q 0.04651,5.01e-4 0.08665,0.01644 0.04327,0.01287 0.07084,0.04417 0.0307,0.02824 0.04881,0.07494 0.01813,0.04361 0.01743,0.108714 z"
|
||||
style="stroke-width:0.054"
|
||||
id="path4986" />
|
||||
<path
|
||||
d="m 99.688647,89.106481 q -0.202131,0.480082 -0.476607,0.788407 -0.273273,0.305468 -0.610318,0.442789 -0.332985,0.135666 -0.72523,0.10845 -0.392245,-0.02722 -0.866611,-0.22694 l -0.78299,-0.329666 q -0.06573,-0.02767 -0.107689,-0.0958 -0.0379,-0.06979 0.009,-0.181233 l 1.388446,-3.297704 q 0.04692,-0.111447 0.122123,-0.130248 0.07926,-0.02046 0.144986,0.0072 l 0.837285,0.352526 q 0.480082,0.202131 0.758628,0.467433 0.279749,0.262444 0.403985,0.590616 0.128297,0.326518 0.103035,0.706129 -0.0224,0.380814 -0.198064,0.798028 z m -0.525653,-0.197768 q 0.126331,-0.300051 0.160317,-0.58852 0.03519,-0.291326 -0.04543,-0.547307 -0.07776,-0.254777 -0.276143,-0.462778 -0.198382,-0.208 -0.581304,-0.369224 l -0.500085,-0.210553 -1.211581,2.877633 0.505801,0.212959 q 0.354346,0.149191 0.634542,0.162873 0.280196,0.01368 0.520083,-0.100626 0.239887,-0.114308 0.435404,-0.354952 0.199578,-0.242298 0.358396,-0.619505 z"
|
||||
style="stroke-width:0.054"
|
||||
id="path4988" />
|
||||
</g>
|
||||
<g
|
||||
aria-label="Research"
|
||||
id="text3463"
|
||||
style="font-size:6.35px;font-family:Calibri;-inkscape-font-specification:Calibri;fill:#165016;stroke:#00000f;stroke-width:0.0539999;stroke-miterlimit:1"
|
||||
transform="translate(28.562171,13.598552)">
|
||||
<path
|
||||
d="m 83.86747,96.36485 q 0,0.02481 -0.0093,0.04341 -0.0093,0.0186 -0.04031,0.03101 -0.031,0.0124 -0.08682,0.0186 -0.05581,0.0062 -0.148828,0.0062 -0.08062,0 -0.133325,-0.0062 -0.04961,-0.0062 -0.08062,-0.0186 -0.031,-0.0155 -0.04961,-0.04031 -0.0155,-0.0248 -0.0279,-0.06201 l -0.36897,-0.945679 q -0.06511,-0.161231 -0.136426,-0.294556 -0.06821,-0.136426 -0.164331,-0.232544 -0.09612,-0.09922 -0.226343,-0.151928 -0.130224,-0.05581 -0.313159,-0.05581 h -0.356567 v 1.708423 q 0,0.02481 -0.0155,0.04341 -0.0124,0.0186 -0.04341,0.03101 -0.02791,0.0093 -0.08062,0.0155 -0.04961,0.0093 -0.127124,0.0093 -0.07752,0 -0.130225,-0.0093 -0.04961,-0.0062 -0.08062,-0.0155 -0.03101,-0.0124 -0.04341,-0.03101 -0.0124,-0.0186 -0.0124,-0.04341 v -3.714502 q 0,-0.120923 0.06201,-0.167432 0.06511,-0.04961 0.136426,-0.04961 h 0.852661 q 0.151928,0 0.251147,0.0093 0.10232,0.0062 0.182935,0.0155 0.232544,0.04031 0.409277,0.127124 0.179834,0.08682 0.300757,0.220141 0.120923,0.133325 0.179834,0.306958 0.06201,0.170532 0.06201,0.378272 0,0.201538 -0.05581,0.362768 -0.05271,0.15813 -0.155029,0.282154 -0.10232,0.120922 -0.244947,0.210839 -0.142626,0.08992 -0.31936,0.151929 0.09922,0.04341 0.179834,0.111621 0.08061,0.06511 0.148828,0.15813 0.07131,0.09302 0.133325,0.213941 0.06201,0.120922 0.124024,0.272851 l 0.359668,0.883667 q 0.04341,0.111621 0.05581,0.15813 0.0124,0.04341 0.0124,0.06821 z m -0.803052,-2.818433 q 0,-0.235644 -0.10542,-0.396875 -0.10542,-0.164331 -0.353467,-0.235644 -0.07751,-0.0217 -0.176733,-0.03101 -0.09612,-0.0093 -0.254248,-0.0093 h -0.449585 v 1.351856 h 0.520898 q 0.21084,0 0.362769,-0.04961 0.155029,-0.05271 0.257348,-0.142627 0.10232,-0.09302 0.148829,-0.217041 0.04961,-0.124023 0.04961,-0.269751 z"
|
||||
style="stroke-width:0.054"
|
||||
id="path4967" />
|
||||
<path
|
||||
d="m 86.850233,94.851764 q 0,0.120923 -0.06201,0.173633 -0.05891,0.04961 -0.136426,0.04961 H 84.82245 q 0,0.232544 0.04651,0.418579 0.04651,0.186035 0.155029,0.319361 0.108521,0.133325 0.282154,0.204638 0.173633,0.07131 0.42478,0.07131 0.198437,0 0.353467,-0.03101 0.155029,-0.03411 0.26665,-0.07441 0.114722,-0.04031 0.186035,-0.07131 0.07441,-0.03411 0.111621,-0.03411 0.0217,0 0.03721,0.0124 0.0186,0.0093 0.02791,0.03101 0.0093,0.0217 0.0124,0.06201 0.0062,0.03721 0.0062,0.09302 0,0.04031 -0.0031,0.07131 -0.0031,0.02791 -0.0093,0.05271 -0.0031,0.0217 -0.0155,0.04031 -0.0093,0.0186 -0.0279,0.03721 -0.0155,0.0155 -0.09922,0.05581 -0.08372,0.03721 -0.217041,0.07441 -0.133325,0.03721 -0.310059,0.06511 -0.173633,0.03101 -0.37207,0.03101 -0.344165,0 -0.604614,-0.09612 -0.257349,-0.09612 -0.434082,-0.285254 -0.176734,-0.189136 -0.266651,-0.474389 -0.08992,-0.285254 -0.08992,-0.663526 0,-0.359668 0.09302,-0.644922 0.09302,-0.288354 0.26665,-0.486792 0.176734,-0.201538 0.424781,-0.306958 0.248046,-0.10852 0.555004,-0.10852 0.328663,0 0.558106,0.10542 0.232544,0.10542 0.381372,0.285254 0.148828,0.176733 0.217041,0.418579 0.07131,0.238745 0.07131,0.511596 z m -0.514697,-0.151929 q 0.0093,-0.403076 -0.179834,-0.632519 -0.186035,-0.229444 -0.555005,-0.229444 -0.189135,0 -0.331762,0.07131 -0.142627,0.07131 -0.238745,0.189136 -0.09612,0.117822 -0.148829,0.275952 -0.05271,0.155029 -0.05891,0.325561 z"
|
||||
style="stroke-width:0.054"
|
||||
id="path4969" />
|
||||
<path
|
||||
d="m 89.380312,95.608307 q 0,0.21394 -0.08062,0.381372 -0.07751,0.167432 -0.223242,0.282153 -0.145727,0.114722 -0.347265,0.173633 -0.201539,0.05891 -0.443384,0.05891 -0.148828,0 -0.285254,-0.0248 -0.133325,-0.02171 -0.241846,-0.05581 -0.10542,-0.03721 -0.179834,-0.07441 -0.07441,-0.04031 -0.10852,-0.07131 -0.03411,-0.031 -0.04961,-0.08682 -0.0155,-0.05581 -0.0155,-0.151929 0,-0.05891 0.0062,-0.09922 0.0062,-0.04031 0.0155,-0.06511 0.0093,-0.0248 0.02481,-0.03411 0.0186,-0.0124 0.04031,-0.0124 0.03411,0 0.09922,0.04341 0.06821,0.04031 0.164332,0.08992 0.09922,0.04961 0.232543,0.09302 0.133326,0.04031 0.306958,0.04031 0.130225,0 0.235645,-0.02791 0.10542,-0.02791 0.182935,-0.08062 0.07751,-0.05581 0.117822,-0.139526 0.04341,-0.08372 0.04341,-0.198437 0,-0.117823 -0.06201,-0.198438 -0.05891,-0.08061 -0.15813,-0.142627 -0.09922,-0.06201 -0.223242,-0.10852 -0.124023,-0.04961 -0.257348,-0.10232 -0.130225,-0.05271 -0.257349,-0.117822 -0.124023,-0.06821 -0.223242,-0.164331 -0.09922,-0.09612 -0.161231,-0.229443 -0.05891,-0.133326 -0.05891,-0.319361 0,-0.164331 0.06201,-0.313159 0.06511,-0.151929 0.192236,-0.26355 0.127124,-0.114721 0.31626,-0.182934 0.192236,-0.06821 0.446484,-0.06821 0.111621,0 0.223243,0.0186 0.111621,0.0186 0.201538,0.04651 0.08992,0.0279 0.151928,0.06201 0.06511,0.03101 0.09612,0.05581 0.03411,0.02481 0.04341,0.04341 0.0124,0.0186 0.0155,0.04341 0.0062,0.0217 0.0093,0.05581 0.0062,0.03411 0.0062,0.08372 0,0.05271 -0.0062,0.09302 -0.0031,0.03721 -0.0155,0.06201 -0.0093,0.02481 -0.0248,0.03721 -0.0155,0.0093 -0.03411,0.0093 -0.02791,0 -0.08062,-0.03411 -0.05271,-0.03411 -0.136426,-0.07131 -0.08371,-0.04031 -0.198437,-0.07441 -0.111621,-0.03411 -0.257349,-0.03411 -0.130224,0 -0.229443,0.03101 -0.09922,0.0279 -0.164331,0.08371 -0.06201,0.05271 -0.09612,0.127124 -0.03101,0.07442 -0.03101,0.161231 0,0.120923 0.06201,0.204639 0.06201,0.08061 0.16123,0.142627 0.09922,0.06201 0.226343,0.111621 0.127124,0.04961 0.257348,0.102319 0.133326,0.05271 0.26045,0.117822 0.130224,0.06511 0.229443,0.15813 0.09922,0.09302 0.15813,0.223242 0.06201,0.130225 0.06201,0.310059 z"
|
||||
style="stroke-width:0.054"
|
||||
id="path4971" />
|
||||
<path
|
||||
d="m 92.4933,94.851764 q 0,0.120923 -0.06201,0.173633 -0.05891,0.04961 -0.136426,0.04961 h -1.829346 q 0,0.232544 0.04651,0.418579 0.04651,0.186035 0.15503,0.319361 0.10852,0.133325 0.282153,0.204638 0.173633,0.07131 0.42478,0.07131 0.198438,0 0.353467,-0.03101 0.155029,-0.03411 0.26665,-0.07441 0.114722,-0.04031 0.186035,-0.07131 0.07442,-0.03411 0.111622,-0.03411 0.0217,0 0.03721,0.0124 0.0186,0.0093 0.02791,0.03101 0.0093,0.0217 0.0124,0.06201 0.0062,0.03721 0.0062,0.09302 0,0.04031 -0.0031,0.07131 -0.0031,0.02791 -0.0093,0.05271 -0.0031,0.0217 -0.0155,0.04031 -0.0093,0.0186 -0.02791,0.03721 -0.0155,0.0155 -0.09922,0.05581 -0.08372,0.03721 -0.217041,0.07441 -0.133325,0.03721 -0.310059,0.06511 -0.173632,0.03101 -0.37207,0.03101 -0.344165,0 -0.604614,-0.09612 -0.257349,-0.09612 -0.434082,-0.285254 -0.176734,-0.189136 -0.26665,-0.474389 -0.08992,-0.285254 -0.08992,-0.663526 0,-0.359668 0.09302,-0.644922 0.09302,-0.288354 0.26665,-0.486792 0.176734,-0.201538 0.424781,-0.306958 0.248047,-0.10852 0.555005,-0.10852 0.328662,0 0.558105,0.10542 0.232544,0.10542 0.381372,0.285254 0.148828,0.176733 0.217041,0.418579 0.07131,0.238745 0.07131,0.511596 z m -0.514698,-0.151929 q 0.0093,-0.403076 -0.179834,-0.632519 -0.186035,-0.229444 -0.555004,-0.229444 -0.189136,0 -0.331763,0.07131 -0.142627,0.07131 -0.238745,0.189136 -0.09612,0.117822 -0.148828,0.275952 -0.05271,0.155029 -0.05891,0.325561 z"
|
||||
style="stroke-width:0.054"
|
||||
id="path4973" />
|
||||
<path
|
||||
d="m 95.373744,96.371051 q 0,0.03721 -0.02481,0.05581 -0.0248,0.0186 -0.06821,0.02791 -0.04341,0.0093 -0.127124,0.0093 -0.08062,0 -0.130225,-0.0093 -0.04651,-0.0093 -0.06821,-0.02791 -0.0217,-0.0186 -0.0217,-0.05581 v -0.279053 q -0.182935,0.195337 -0.409277,0.303858 -0.223243,0.10852 -0.47439,0.10852 -0.220142,0 -0.399976,-0.05891 -0.176733,-0.05581 -0.303857,-0.164331 -0.124023,-0.10852 -0.195337,-0.26665 -0.06821,-0.15813 -0.06821,-0.359668 0,-0.235645 0.09612,-0.409278 0.09612,-0.173632 0.275952,-0.288354 0.179834,-0.114722 0.440284,-0.170532 0.260449,-0.05891 0.58601,-0.05891 h 0.384473 v -0.217042 q 0,-0.16123 -0.03411,-0.285253 -0.03411,-0.124024 -0.111621,-0.204639 -0.07442,-0.08372 -0.195337,-0.124024 -0.120923,-0.04341 -0.297657,-0.04341 -0.189135,0 -0.341064,0.04651 -0.148828,0.04341 -0.26355,0.09922 -0.111621,0.05271 -0.189136,0.09922 -0.07441,0.04341 -0.111621,0.04341 -0.0248,0 -0.04341,-0.0124 -0.0186,-0.0124 -0.03411,-0.03721 -0.0124,-0.0248 -0.0186,-0.06201 -0.0062,-0.04031 -0.0062,-0.08682 0,-0.07751 0.0093,-0.120923 0.0124,-0.04651 0.05271,-0.08682 0.04341,-0.04031 0.145727,-0.09302 0.10232,-0.05581 0.235645,-0.09922 0.133325,-0.04651 0.291455,-0.07441 0.15813,-0.03101 0.31936,-0.03101 0.300757,0 0.511597,0.06821 0.21084,0.06821 0.341064,0.201538 0.130225,0.130224 0.189136,0.325561 0.05891,0.195337 0.05891,0.455786 z M 94.865248,95.09671 h -0.437183 q -0.210839,0 -0.365869,0.03721 -0.155029,0.03411 -0.257348,0.10542 -0.10232,0.06821 -0.151929,0.167432 -0.04651,0.09612 -0.04651,0.223242 0,0.217041 0.136426,0.347266 0.139526,0.127124 0.387573,0.127124 0.201538,0 0.372071,-0.10232 0.173632,-0.102319 0.362768,-0.313159 z"
|
||||
style="stroke-width:0.054"
|
||||
id="path4975" />
|
||||
<path
|
||||
d="m 97.94413,93.760358 q 0,0.06821 -0.0031,0.114721 -0.0031,0.04651 -0.0124,0.07441 -0.0093,0.02481 -0.02481,0.04031 -0.0124,0.0124 -0.03721,0.0124 -0.02481,0 -0.06201,-0.0124 -0.03411,-0.0155 -0.08061,-0.02791 -0.04341,-0.0155 -0.09922,-0.0279 -0.05581,-0.0124 -0.120922,-0.0124 -0.07751,0 -0.151929,0.03101 -0.07441,0.03101 -0.15813,0.102319 -0.08061,0.07131 -0.170532,0.189136 -0.08992,0.117822 -0.198438,0.288355 v 1.835546 q 0,0.02481 -0.0124,0.04341 -0.0124,0.0155 -0.04031,0.0279 -0.02791,0.0124 -0.07751,0.0186 -0.04961,0.0062 -0.127124,0.0062 -0.07441,0 -0.124024,-0.0062 -0.04961,-0.0062 -0.08061,-0.0186 -0.02791,-0.0124 -0.04031,-0.0279 -0.0093,-0.0186 -0.0093,-0.04341 v -2.790527 q 0,-0.02481 0.0093,-0.04031 0.0093,-0.0186 0.03721,-0.03101 0.02791,-0.0155 0.07131,-0.0186 0.04341,-0.0062 0.114721,-0.0062 0.06821,0 0.111622,0.0062 0.04651,0.0031 0.07131,0.0186 0.02481,0.0124 0.03411,0.03101 0.0124,0.0155 0.0124,0.04031 V 93.9836 q 0.114722,-0.167432 0.21394,-0.272852 0.10232,-0.10542 0.192237,-0.164331 0.08992,-0.06201 0.176733,-0.08372 0.08992,-0.0248 0.179834,-0.0248 0.04031,0 0.08992,0.0062 0.05271,0.0031 0.10852,0.0155 0.05581,0.0124 0.09922,0.0279 0.04651,0.0155 0.06511,0.03101 0.0186,0.0155 0.0248,0.03101 0.0062,0.0124 0.0093,0.03411 0.0062,0.0217 0.0062,0.06511 0.0031,0.04031 0.0031,0.111621 z"
|
||||
style="stroke-width:0.054"
|
||||
id="path4977" />
|
||||
<path
|
||||
d="m 100.4401,95.94317 q 0,0.05271 -0.003,0.09302 -0.003,0.03721 -0.0124,0.06511 -0.006,0.02481 -0.0186,0.04651 -0.009,0.0186 -0.0496,0.05891 -0.0372,0.03721 -0.13023,0.09612 -0.093,0.05581 -0.21084,0.102319 -0.11472,0.04341 -0.251146,0.07131 -0.136426,0.0279 -0.282153,0.0279 -0.300757,0 -0.533301,-0.09922 -0.232544,-0.09922 -0.390674,-0.288354 -0.155029,-0.192236 -0.238745,-0.468188 -0.08061,-0.279053 -0.08061,-0.641822 0,-0.412378 0.09922,-0.706933 0.10232,-0.297657 0.275952,-0.486792 0.176734,-0.189136 0.412378,-0.279053 0.238746,-0.09302 0.514698,-0.09302 0.133325,0 0.257348,0.02481 0.127124,0.02481 0.232543,0.06511 0.10542,0.04031 0.18604,0.09302 0.0837,0.05271 0.12092,0.08992 0.0372,0.03721 0.0496,0.05891 0.0155,0.0217 0.0248,0.05271 0.009,0.02791 0.0124,0.06511 0.003,0.03721 0.003,0.09302 0,0.120923 -0.0279,0.170532 -0.0279,0.04651 -0.0682,0.04651 -0.0465,0 -0.10852,-0.04961 -0.0589,-0.05271 -0.15193,-0.114722 -0.09302,-0.06201 -0.226344,-0.111621 -0.130225,-0.05271 -0.310058,-0.05271 -0.36897,0 -0.567408,0.285254 -0.195337,0.282153 -0.195337,0.821655 0,0.269751 0.04961,0.47439 0.05271,0.201538 0.151928,0.337963 0.09922,0.136426 0.241846,0.204639 0.145728,0.06511 0.331763,0.06511 0.176733,0 0.310058,-0.05581 0.133326,-0.05581 0.229442,-0.120923 0.0992,-0.06821 0.16434,-0.120923 0.0682,-0.05581 0.10542,-0.05581 0.0217,0 0.0372,0.0124 0.0155,0.0124 0.0248,0.04341 0.0124,0.02791 0.0155,0.07441 0.006,0.04341 0.006,0.10542 z"
|
||||
style="stroke-width:0.054"
|
||||
id="path4979" />
|
||||
<path
|
||||
d="m 103.52208,96.36795 q 0,0.02481 -0.0124,0.04341 -0.0124,0.0155 -0.0403,0.0279 -0.0279,0.0124 -0.0775,0.0186 -0.0496,0.0062 -0.12402,0.0062 -0.0775,0 -0.12713,-0.0062 -0.0496,-0.0062 -0.0775,-0.0186 -0.0279,-0.0124 -0.0403,-0.0279 -0.0124,-0.0186 -0.0124,-0.04341 v -1.634008 q 0,-0.238745 -0.0372,-0.384473 -0.0372,-0.145728 -0.10852,-0.251147 -0.0713,-0.10542 -0.18603,-0.161231 -0.11163,-0.05581 -0.26045,-0.05581 -0.19224,0 -0.38448,0.136425 -0.19223,0.136426 -0.40307,0.399976 v 1.950268 q 0,0.02481 -0.0124,0.04341 -0.0124,0.0155 -0.0403,0.0279 -0.0279,0.0124 -0.0775,0.0186 -0.0496,0.0062 -0.12712,0.0062 -0.0744,0 -0.12402,-0.0062 -0.0496,-0.0062 -0.0806,-0.0186 -0.0279,-0.0124 -0.0403,-0.0279 -0.009,-0.0186 -0.009,-0.04341 v -4.142382 q 0,-0.02481 0.009,-0.04341 0.0124,-0.0186 0.0403,-0.031 0.031,-0.0124 0.0806,-0.0186 0.0496,-0.0062 0.12402,-0.0062 0.0775,0 0.12712,0.0062 0.0496,0.0062 0.0775,0.0186 0.0279,0.0124 0.0403,0.031 0.0124,0.0186 0.0124,0.04341 v 1.671215 q 0.22014,-0.232543 0.44338,-0.344165 0.22324,-0.114721 0.44959,-0.114721 0.27905,0 0.46818,0.09612 0.19224,0.09302 0.31006,0.251147 0.11783,0.15813 0.16743,0.372071 0.0527,0.21084 0.0527,0.511596 z"
|
||||
style="stroke-width:0.054"
|
||||
id="path4981" />
|
||||
</g>
|
||||
</g> -->
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:6.1311px;font-family:Calibri;-inkscape-font-specification:Calibri;fill:#f9f9f9;stroke:#00000f;stroke-width:0.0586557;stroke-miterlimit:1"
|
||||
x="27.642879"
|
||||
y="5.8916035"
|
||||
id="text1590"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan1588"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:6.1311px;font-family:Calibri;-inkscape-font-specification:Calibri;fill:#f9f9f9;stroke-width:0.0586558"
|
||||
x="27.642879"
|
||||
y="5.8916035">MI Trace View</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
После Ширина: | Высота: | Размер: 20 KiB |
@@ -0,0 +1,106 @@
|
||||
h2,h3,h4 {
|
||||
text-align: center;
|
||||
font-family: Calibri, Candara, Optima, Arial, 'Trebuchet MS', sans-serif;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 20px 5px;
|
||||
/*font-family: Calibri, Candara, Segoe, "Segoe UI", Optima, Arial, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; */
|
||||
font-family: 'Courier New', monospace; font-size: 15px; font-style: normal;
|
||||
}
|
||||
|
||||
a {
|
||||
color: royalblue;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div#flexbox {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
div#flexbox > div {
|
||||
flex: 50%;
|
||||
}
|
||||
|
||||
div#minimap {
|
||||
position: absolute;
|
||||
width: 350px;
|
||||
top: 340px;
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
div#wave, div#cu_wave {
|
||||
overflow:scroll;
|
||||
overflow-y:hidden;
|
||||
}
|
||||
|
||||
div#ma_code {
|
||||
height: calc(100vh - 180px);
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
display: block;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
nav {
|
||||
padding-right: 8px;
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
background: #FFFDE3;
|
||||
z-index: 5;
|
||||
margin-left: 10px;
|
||||
width:330px;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background-color: lightgray;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
font-weight: 180;
|
||||
}
|
||||
|
||||
ul li {
|
||||
border-bottom: 1px dotted black;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
display: none;
|
||||
position: relative;
|
||||
left: 10px;
|
||||
z-index: 100;
|
||||
background: #333;
|
||||
border: 1px solid #c0c0c0;
|
||||
opacity: 0.8;
|
||||
color: white;
|
||||
}
|
||||
li:hover .tooltip {
|
||||
display: inline-block; /*block;*/
|
||||
}
|
||||
.loop {
|
||||
margin-left: 30px;
|
||||
background: lightseagreen;
|
||||
}
|
||||
|
||||
.btn {
|
||||
border: 1px solid black;
|
||||
background-color: #D7D7D7;
|
||||
color: black;
|
||||
padding: 3px 4px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
border-style: ridge;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
color: blue;
|
||||
}
|
||||
@@ -403,6 +403,9 @@ class file_plugin_t {
|
||||
FlushTracerRecord(*tracer_record, session_id, buffer_id);
|
||||
break;
|
||||
}
|
||||
case ROCPROFILER_ATT_TRACER_RECORD: {
|
||||
break;
|
||||
}
|
||||
case ROCPROFILER_PC_SAMPLING_RECORD: {
|
||||
const rocprofiler_record_pc_sample_t *pc_sampling_record =
|
||||
reinterpret_cast<const rocprofiler_record_pc_sample_t *>(begin);
|
||||
|
||||
@@ -11,7 +11,7 @@ elif [[ $ROCPROFV2_DIR == *"/rocprofiler"* ]]; then
|
||||
fi
|
||||
|
||||
usage() {
|
||||
echo -e "ROCProfiler Run Script Usage:"
|
||||
echo -e "ROCProfilerV2 Run Script Usage:"
|
||||
echo -e "-h | --help For showing this message"
|
||||
echo -e "--list-counters For showing all available counters for the current GPUs"
|
||||
if [ $RUN_FROM_BUILD == 1 ]; then
|
||||
@@ -21,8 +21,8 @@ usage() {
|
||||
echo -e "-ct | --clean-build-test For Running the tests after a clean build"
|
||||
echo -e "-mt | --mem-test For Running the Memory Leak tests. This run requires building using -acb | --asan-clean-build option"
|
||||
echo -e "-acb | --asan-clean-build For compiling with ASAN library attached"
|
||||
echo -e "--install For installing rocprofiler without clean build in the default installation folder (review build.sh to know more about the default paths)"
|
||||
echo -e "--clean-install For installing rocprofiler with new clean build in the default installation folder (review build.sh to know more about the default paths)"
|
||||
echo -e "--install For installing ROCProfilerV2 without clean build in the default installation folder (review build.sh to know more about the default paths)"
|
||||
echo -e "--clean-install For installing ROCProfilerV2 with new clean build in the default installation folder (review build.sh to know more about the default paths)"
|
||||
fi
|
||||
echo -e "--hip-api For Collecting HIP API Traces"
|
||||
echo -e "--hip-activity For Collecting HSA API Activities Traces"
|
||||
@@ -31,11 +31,18 @@ usage() {
|
||||
echo -e "--roctx-trace For Collecting ROCTx Traces"
|
||||
echo -e "--kernel-trace For Collecting Kernel dispatch Traces"
|
||||
echo -e "--sys-trace For Collecting HIP and HSA APIs and their Activities Traces along ROCTX and Kernel Dispatch traces"
|
||||
echo -e "--plugin PLUGIN_NAME For enabling a plugin (file/perfetto)"
|
||||
echo -e "--plugin PLUGIN_NAME For enabling a plugin (file/perfetto/att)"
|
||||
echo -e "-i | --input For adding counters file path (every line in the text file represents a counter)"
|
||||
echo -e "-o | --output-file For the output file name"
|
||||
echo -e "-d | --output-directory For adding output path where the output files will be saved"
|
||||
echo -e "-fi | --flush-interval For adding a flush interval in milliseconds, every \"flush interval\" the buffers will be flushed"
|
||||
echo -e "\n###ATT Plugin options: ###"
|
||||
if [ $RUN_FROM_BUILD == 1 ]; then
|
||||
ATT_PATH=$ROCPROFV2_DIR/build/plugin/att/att/att.py
|
||||
else
|
||||
ATT_PATH=$ROCPROFV2_DIR/../libexec/rocprofiler/att/att.py
|
||||
fi
|
||||
eval "python3 $ATT_PATH --help"
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -199,6 +206,35 @@ while [ 1 ] ; do
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [ "$2" = "att" ] ; then
|
||||
#if [ $RUN_FROM_BUILD == 1 ]; then
|
||||
# export ROCMTOOLS_ATT_PARSER=build/libatt_parser.so
|
||||
#else
|
||||
# export ROCMTOOLS_ATT_PARSER=$ROCPROFV2_DIR/../lib/rocprofiler/libatt_parser.so
|
||||
#fi
|
||||
ATT_ARGV=$3
|
||||
shift
|
||||
|
||||
ATT_OPTIONS="Not done"
|
||||
while [ "$ATT_OPTIONS" = "Not done" ]; do
|
||||
if [[ "$3" = "--trace_file" ]]; then
|
||||
ATT_ARGV="$ATT_ARGV $3 \"$4\""
|
||||
shift
|
||||
shift
|
||||
elif [[ "$3" = "--genasm" || "$3" = "--target_cu" || "$3" = "-o" || "$3" == "-k" || "$3" == "--att_kernel" ]]; then
|
||||
ATT_ARGV="$ATT_ARGV $3 $4"
|
||||
shift
|
||||
shift
|
||||
else
|
||||
ATT_OPTIONS="Done"
|
||||
fi
|
||||
done
|
||||
if [ $RUN_FROM_BUILD == 1 ]; then
|
||||
ATT_PATH=$ROCPROFV2_DIR/build/plugin/att/att/att.py
|
||||
else
|
||||
ATT_PATH=$ROCPROFV2_DIR/../libexec/rocprofiler/att/att.py
|
||||
fi
|
||||
fi
|
||||
shift
|
||||
shift
|
||||
elif [[ "$1" = "-"* || "$1" = "--"* ]] ; then
|
||||
@@ -214,7 +250,10 @@ PMC_LINES=()
|
||||
if [ -n "$COUNTERS_PATH" ]; then
|
||||
input=$COUNTERS_PATH
|
||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||
# if in att mode, only add the first line
|
||||
if [[ ! -n "$PMC_LINES" ]] || [[ ! -n "$ATT_ARGV" ]]; then
|
||||
PMC_LINES+=( "$line" )
|
||||
fi
|
||||
done < $input
|
||||
fi
|
||||
|
||||
@@ -236,7 +275,7 @@ if [ -n "$PMC_LINES" ]; then
|
||||
LD_PRELOAD=$LD_PRELOAD:$ROCM_DIR/lib/librocprofiler_tool.so $*
|
||||
fi
|
||||
done
|
||||
else
|
||||
elif [ ! -n "$ATT_ARGV" ]; then
|
||||
if [ $RUN_FROM_BUILD == 1 ]; then
|
||||
LD_PRELOAD=$LD_PRELOAD:$ROCM_DIR/build/librocprofiler_tool.so $*
|
||||
else
|
||||
@@ -244,4 +283,10 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
if [ -n "$ATT_PATH" ]; then
|
||||
if [ -n "$ATT_ARGV" ]; then
|
||||
eval "python3 $ATT_PATH $ATT_ARGV"
|
||||
elif [ ! -n "$PMC_LINES" ]; then
|
||||
echo "ATT File is required!"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
att: TARGET_CU=1
|
||||
@@ -150,6 +150,7 @@ file(GLOB ROCPROFILER_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
||||
file(GLOB ROCPROFILER_PROFILER_SRC_FILES ${PROJECT_SOURCE_DIR}/src/core/session/profiler/profiler.cpp)
|
||||
file(GLOB ROCPROFILER_TRACER_SRC_FILES ${PROJECT_SOURCE_DIR}/src/core/session/tracer/*.cpp)
|
||||
file(GLOB ROCPROFILER_ROCTRACER_SRC_FILES ${PROJECT_SOURCE_DIR}/src/core/session/tracer/src/*.cpp)
|
||||
file(GLOB ROCMTOOLS_ATT_SRC_FILES ${PROJECT_SOURCE_DIR}/src/core/session/att/att.cpp)
|
||||
file(GLOB ROCMTOOL_CLASS_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rocmtool.cpp)
|
||||
file(GLOB ROCPROFILER_SPM_SRC_FILES ${PROJECT_SOURCE_DIR}/src/core/session/spm/spm.cpp)
|
||||
|
||||
@@ -189,6 +190,7 @@ add_library(${ROCPROFILER_TARGET} SHARED
|
||||
${ROCPROFILER_SRC_FILES}
|
||||
${ROCMTOOL_CLASS_SRC_FILES}
|
||||
${ROCPROFILER_PROFILER_SRC_FILES}
|
||||
${ROCMTOOLS_ATT_SRC_FILES}
|
||||
${CORE_HARDWARE_SRC_FILES}
|
||||
${CORE_HSA_SRC_FILES}
|
||||
${ROCPROFILER_SPM_SRC_FILES}
|
||||
|
||||
@@ -486,4 +486,146 @@ hsa_ven_amd_aqlprofile_profile_t* InitializeDeviceProfilingAqlPackets(
|
||||
return profile;
|
||||
}
|
||||
|
||||
// ATT
|
||||
uint32_t g_output_buffer_size = 0x8000000; // 128M x 16 = 2GB
|
||||
bool g_output_buffer_local = true;
|
||||
|
||||
// Allocate system memory accessible by both CPU and GPU
|
||||
uint8_t* AllocateSysMemory(hsa_agent_t gpu_agent, size_t size, hsa_amd_memory_pool_t* cpu_pool) {
|
||||
hsa_status_t status = HSA_STATUS_ERROR;
|
||||
uint8_t* buffer = NULL;
|
||||
size = (size + MEM_PAGE_MASK) & ~MEM_PAGE_MASK;
|
||||
// if (!cpu_agents_.empty()) {
|
||||
status = hsa_amd_memory_pool_allocate(*cpu_pool, size, 0, reinterpret_cast<void**>(&buffer));
|
||||
// Both the CPU and GPU can access the memory
|
||||
if (status == HSA_STATUS_SUCCESS) {
|
||||
hsa_agent_t ag_list[1] = {gpu_agent};
|
||||
status = hsa_amd_agents_allow_access(1, ag_list, NULL, buffer);
|
||||
}
|
||||
// }
|
||||
uint8_t* ptr = (status == HSA_STATUS_SUCCESS) ? buffer : NULL;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// Allocate memory for use by a kernel of specified size
|
||||
uint8_t* AllocateLocalMemory(size_t size, hsa_amd_memory_pool_t* gpu_pool) {
|
||||
hsa_status_t status = HSA_STATUS_ERROR;
|
||||
uint8_t* buffer = NULL;
|
||||
size = (size + MEM_PAGE_MASK) & ~MEM_PAGE_MASK;
|
||||
status = hsa_amd_memory_pool_allocate(*gpu_pool, size, 0, reinterpret_cast<void**>(&buffer));
|
||||
uint8_t* ptr = (status == HSA_STATUS_SUCCESS) ? buffer : NULL;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
hsa_status_t Allocate(hsa_agent_t gpu_agent, hsa_ven_amd_aqlprofile_profile_t* profile,
|
||||
hsa_amd_memory_pool_t* cpu_pool, hsa_amd_memory_pool_t* gpu_pool) {
|
||||
profile->command_buffer.ptr =
|
||||
AllocateSysMemory(gpu_agent, profile->command_buffer.size, cpu_pool);
|
||||
profile->output_buffer.size = g_output_buffer_size;
|
||||
profile->output_buffer.ptr = (g_output_buffer_local)
|
||||
? AllocateLocalMemory(profile->output_buffer.size, gpu_pool)
|
||||
: AllocateSysMemory(gpu_agent, profile->output_buffer.size, cpu_pool);
|
||||
return (profile->command_buffer.ptr && profile->output_buffer.ptr) ? HSA_STATUS_SUCCESS
|
||||
: HSA_STATUS_ERROR;
|
||||
}
|
||||
|
||||
bool AllocateMemoryPools(hsa_agent_t cpu_agent, hsa_agent_t gpu_agent,
|
||||
hsa_amd_memory_pool_t* cpu_pool, hsa_amd_memory_pool_t* gpu_pool) {
|
||||
hsa_status_t status = hsa_amd_agent_iterate_memory_pools(cpu_agent, FindStandardPool, cpu_pool);
|
||||
CHECK_HSA_STATUS("hsa_amd_agent_iterate_memory_pools(cpu_pool)", status);
|
||||
|
||||
status = hsa_amd_agent_iterate_memory_pools(gpu_agent, FindStandardPool, gpu_pool);
|
||||
CHECK_HSA_STATUS("hsa_amd_agent_iterate_memory_pools(gpu_pool)", status);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// map between gpu agent handle and att_memory_pools_t
|
||||
typedef std::map<uint64_t, att_memory_pools_t*> att_mem_pools_map_t;
|
||||
|
||||
att_mem_pools_map_t* agent_att_mem_pools_map = nullptr;
|
||||
std::atomic<bool> att_map_init{false};
|
||||
|
||||
att_mem_pools_map_t* GetAttMemPoolsMap() {
|
||||
if (!att_map_init.load(std::memory_order_relaxed)) {
|
||||
agent_att_mem_pools_map = new att_mem_pools_map_t();
|
||||
att_map_init.exchange(true, std::memory_order_release);
|
||||
}
|
||||
|
||||
return agent_att_mem_pools_map;
|
||||
}
|
||||
|
||||
|
||||
att_memory_pools_t* GetAttMemPools(hsa_agent_t gpu_agent) {
|
||||
auto it = GetAttMemPoolsMap()->find(gpu_agent.handle);
|
||||
if (it != GetAttMemPoolsMap()->end()) {
|
||||
return it->second;
|
||||
}
|
||||
printf("Error: att_memory_pools_t instance not found for given gpu agent handle: %lu\n",
|
||||
gpu_agent.handle);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Generate start and stop packets for collecting ATT traces
|
||||
// Also generate and return the profile object which has the PM4
|
||||
// command buffer and the output buffer for retrieving the traces
|
||||
hsa_ven_amd_aqlprofile_profile_t* GenerateATTPackets(
|
||||
hsa_agent_t cpu_agent, hsa_agent_t gpu_agent,
|
||||
std::vector<hsa_ven_amd_aqlprofile_parameter_t>& att_params, packet_t* start_packet,
|
||||
packet_t* stop_packet) {
|
||||
att_memory_pools_t* att_mem_pools = NULL;
|
||||
auto it = GetAttMemPoolsMap()->find(gpu_agent.handle);
|
||||
if (it == GetAttMemPoolsMap()->end()) {
|
||||
att_mem_pools = new att_memory_pools_t;
|
||||
|
||||
// Allocate memory pools for cpu and gpu
|
||||
AllocateMemoryPools(cpu_agent, gpu_agent, &att_mem_pools->cpu_mem_pool,
|
||||
&att_mem_pools->gpu_mem_pool);
|
||||
|
||||
GetAttMemPoolsMap()->emplace(gpu_agent.handle, att_mem_pools);
|
||||
} else
|
||||
att_mem_pools = it->second;
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wconversion-null"
|
||||
// Preparing the profile structure to get the packets
|
||||
hsa_ven_amd_aqlprofile_profile_t* profile =
|
||||
new hsa_ven_amd_aqlprofile_profile_t{gpu_agent,
|
||||
HSA_VEN_AMD_AQLPROFILE_EVENT_TYPE_TRACE,
|
||||
nullptr,
|
||||
0,
|
||||
&att_params[0],
|
||||
(uint32_t)att_params.size(),
|
||||
NULL,
|
||||
NULL};
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
// Check the profile buffer sizes
|
||||
hsa_status_t status = hsa_ven_amd_aqlprofile_start(profile, NULL);
|
||||
if (status != HSA_STATUS_SUCCESS) printf("Error: aqlprofile_start(NULL)");
|
||||
// // Double output buffer size if concurrent
|
||||
// if (is_concurrent) profile.output_buffer.size *= 2;
|
||||
|
||||
// TODO: create a separate class for memory allocations
|
||||
// Maintain pools per device
|
||||
// handle allocation and resource cleanup
|
||||
|
||||
|
||||
// Allocate command and output buffers
|
||||
// command buffer -> from CPU memory pool
|
||||
// output buffer -> from GPU memory pool
|
||||
status =
|
||||
Allocate(gpu_agent, profile, &att_mem_pools->cpu_mem_pool, &att_mem_pools->gpu_mem_pool);
|
||||
if (status != HSA_STATUS_SUCCESS) printf("Error: Allocate()");
|
||||
|
||||
// Generate start/stop/read profiling packets
|
||||
status = hsa_ven_amd_aqlprofile_start(profile, start_packet);
|
||||
if (status != HSA_STATUS_SUCCESS) printf("Error: aqlprofile_start");
|
||||
status = hsa_ven_amd_aqlprofile_stop(profile, stop_packet);
|
||||
if (status != HSA_STATUS_SUCCESS) printf("Error: aqlprofile_stop");
|
||||
if (status == HSA_STATUS_ERROR) return nullptr;
|
||||
return profile;
|
||||
}
|
||||
|
||||
} // namespace Packet
|
||||
|
||||
@@ -55,5 +55,25 @@ hsa_amd_memory_pool_t& GetCommandPool();
|
||||
hsa_amd_memory_pool_t& GetOutputPool();
|
||||
|
||||
|
||||
hsa_ven_amd_aqlprofile_profile_t* GenerateATTPackets(
|
||||
hsa_agent_t cpu_agent, hsa_agent_t gpu_agent,
|
||||
std::vector<hsa_ven_amd_aqlprofile_parameter_t>& att_params, packet_t* start_packet,
|
||||
packet_t* stop_packet);
|
||||
|
||||
|
||||
uint8_t* AllocateSysMemory(hsa_agent_t gpu_agent, size_t size, hsa_amd_memory_pool_t* cpu_pool);
|
||||
|
||||
void get_command_buffer_map(std::map<size_t, uint8_t*> );
|
||||
void get_outbuffer_map(std::map<size_t, uint8_t*> );
|
||||
void initialize_pools(hsa_agent_t cpu_agent);
|
||||
|
||||
typedef struct {
|
||||
hsa_amd_memory_pool_t cpu_mem_pool;
|
||||
hsa_amd_memory_pool_t gpu_mem_pool;
|
||||
} att_memory_pools_t;
|
||||
|
||||
att_memory_pools_t* GetAttMemPools(hsa_agent_t gpu_agent);
|
||||
|
||||
|
||||
} // namespace Packet
|
||||
#endif // SRC_CORE_HSA_PACKETS_PACKETS_GENERATOR_H_
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
#include "src/utils/helper.h"
|
||||
|
||||
#define __NR_gettid 186
|
||||
#define MAX_ATT_PROFILES 16
|
||||
|
||||
std::mutex sessions_pending_signal_lock;
|
||||
|
||||
namespace rocmtools {
|
||||
@@ -52,6 +54,8 @@ static inline bool IsEventMatch(const hsa_ven_amd_aqlprofile_event_t& event1,
|
||||
(event1.counter_id == event2.counter_id);
|
||||
}
|
||||
|
||||
typedef std::vector<hsa_ven_amd_aqlprofile_info_data_t> att_trace_callback_data_t;
|
||||
|
||||
static std::mutex ksymbol_map_lock;
|
||||
static std::map<uint64_t, std::string>* ksymbols;
|
||||
static std::atomic<bool> ksymbols_flag{true};
|
||||
@@ -234,6 +238,17 @@ hsa_status_t pmcCallback(hsa_ven_amd_aqlprofile_info_type_t info_type,
|
||||
return status;
|
||||
}
|
||||
|
||||
hsa_status_t attTraceDataCallback(hsa_ven_amd_aqlprofile_info_type_t info_type,
|
||||
hsa_ven_amd_aqlprofile_info_data_t* info_data, void* data) {
|
||||
hsa_status_t status = HSA_STATUS_SUCCESS;
|
||||
att_trace_callback_data_t* passed_data = reinterpret_cast<att_trace_callback_data_t*>(data);
|
||||
passed_data->push_back(*info_data);
|
||||
// TODO: clear output buffers after copying
|
||||
// either copy here or in AddattRecord
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void AddRecordCounters(rocprofiler_record_profiler_t* record, const pending_signal_t& pending) {
|
||||
rocmtools::metrics::GetCounterData(pending.profile, pending.context->results_list);
|
||||
rocmtools::metrics::GetMetricsData(pending.context->results_map, pending.context->metrics_list);
|
||||
@@ -260,6 +275,47 @@ void AddRecordCounters(rocprofiler_record_profiler_t* record, const pending_sign
|
||||
record->counters_count = rocprofiler_record_counters_instances_count_t{counters_vec.size()};
|
||||
}
|
||||
|
||||
void AddAttRecord(rocprofiler_record_att_tracer_t* record, hsa_agent_t gpu_agent,
|
||||
att_pending_signal_t& pending) {
|
||||
att_trace_callback_data_t data;
|
||||
hsa_ven_amd_aqlprofile_iterate_data(pending.profile, attTraceDataCallback, &data);
|
||||
|
||||
// Get CPU and GPU memory pools
|
||||
Packet::att_memory_pools_t* att_mem_pools = Packet::GetAttMemPools(gpu_agent);
|
||||
|
||||
// Allocate memory for shader_engine_data
|
||||
record->shader_engine_data = static_cast<rocprofiler_record_se_att_data_t*>(
|
||||
malloc(data.size() * sizeof(rocprofiler_record_se_att_data_t)));
|
||||
|
||||
att_trace_callback_data_t::iterator trace_data_it;
|
||||
|
||||
uint32_t se_index = 0;
|
||||
// iterate over the trace data collected from each shader engine
|
||||
for (trace_data_it = data.begin(); trace_data_it != data.end(); trace_data_it++) {
|
||||
const void* data_ptr = trace_data_it->trace_data.ptr;
|
||||
const uint32_t data_size = trace_data_it->trace_data.size;
|
||||
// fprintf(arg->file, " SE(%u) size(%u)\n", data.sample_id, data_size);
|
||||
|
||||
void* buffer = NULL;
|
||||
if (data_size != 0) {
|
||||
// Allocate buffer on CPU to copy out trace data
|
||||
buffer = Packet::AllocateSysMemory(gpu_agent, data_size, &att_mem_pools->cpu_mem_pool);
|
||||
if (buffer == NULL) fatal("Trace data buffer allocation failed");
|
||||
|
||||
auto status =
|
||||
rocmtools::hsa_support::GetCoreApiTable().hsa_memory_copy_fn(buffer, data_ptr, data_size);
|
||||
if (status != HSA_STATUS_SUCCESS) fatal("Trace data memcopy to host failed");
|
||||
|
||||
record->shader_engine_data[se_index].buffer_ptr = buffer;
|
||||
record->shader_engine_data[se_index].buffer_size = data_size;
|
||||
++se_index;
|
||||
|
||||
// TODO: clear output buffers after copying
|
||||
}
|
||||
}
|
||||
record->shader_engine_data_count = data.size();
|
||||
}
|
||||
|
||||
// static const size_t MEM_PAGE_BYTES = 0x1000;
|
||||
// static const size_t MEM_PAGE_MASK = MEM_PAGE_BYTES - 1;
|
||||
// static std::mutex begin_signal_lock;
|
||||
@@ -418,6 +474,67 @@ bool AsyncSignalHandler(hsa_signal_value_t signal_value, void* data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AsyncSignalHandlerATT(hsa_signal_value_t /* signal */, void* data) {
|
||||
// TODO: finish implementation to iterate trace data and add it to rocmtools record
|
||||
// and generic buffer
|
||||
|
||||
auto queue_info_session = static_cast<queue_info_session_t*>(data);
|
||||
if (!queue_info_session || !GetROCMToolObj() ||
|
||||
!GetROCMToolObj()->GetSession(queue_info_session->session_id) ||
|
||||
!GetROCMToolObj()->GetSession(queue_info_session->session_id)->GetAttTracer())
|
||||
return true;
|
||||
rocmtools::Session* session = GetROCMToolObj()->GetSession(queue_info_session->session_id);
|
||||
rocmtools::att::AttTracer* att_tracer = session->GetAttTracer();
|
||||
std::vector<att_pending_signal_t>& pending_signals =
|
||||
const_cast<std::vector<att_pending_signal_t>&>(
|
||||
att_tracer->GetPendingSignals(queue_info_session->writer_id));
|
||||
|
||||
if (!pending_signals.empty()) {
|
||||
for (auto it = pending_signals.begin(); it != pending_signals.end();
|
||||
it = pending_signals.erase(it)) {
|
||||
auto& pending = *it;
|
||||
std::lock_guard<std::mutex> lock(session->GetSessionLock());
|
||||
if (hsa_support::GetCoreApiTable().hsa_signal_load_relaxed_fn(pending.signal)) return true;
|
||||
rocprofiler_record_att_tracer_t record{};
|
||||
record.kernel_id = rocprofiler_kernel_id_t{pending.kernel_descriptor};
|
||||
record.gpu_id = rocprofiler_agent_id_t{
|
||||
(uint64_t)hsa_support::GetAgentInfo(queue_info_session->agent.handle).getIndex()};
|
||||
record.kernel_properties = pending.kernel_properties;
|
||||
record.thread_id = rocprofiler_thread_id_t{pending.thread_id};
|
||||
record.queue_idx = rocprofiler_queue_index_t{pending.queue_index};
|
||||
record.queue_id = rocprofiler_queue_id_t{queue_info_session->queue_id};
|
||||
if (/*pending.counters_count > 0 && */ pending.profile) {
|
||||
AddAttRecord(&record, queue_info_session->agent, pending);
|
||||
}
|
||||
record.header = {ROCPROFILER_ATT_TRACER_RECORD,
|
||||
rocprofiler_record_id_t{GetROCMToolObj()->GetUniqueRecordId()}};
|
||||
|
||||
if (pending.session_id.handle == 0) {
|
||||
pending.session_id = GetROCMToolObj()->GetCurrentSessionId();
|
||||
}
|
||||
if (session->FindBuffer(pending.buffer_id)) {
|
||||
Memory::GenericBuffer* buffer = session->GetBuffer(pending.buffer_id);
|
||||
record.header.id = rocprofiler_record_id_t{GetROCMToolObj()->GetUniqueRecordId()};
|
||||
buffer->AddRecord(record);
|
||||
}
|
||||
hsa_status_t status = rocmtools::hsa_support::GetAmdExtTable().hsa_amd_memory_pool_free_fn(
|
||||
(pending.profile->output_buffer.ptr));
|
||||
if (status != HSA_STATUS_SUCCESS) {
|
||||
printf("Error: Couldn't free output buffer memory\n");
|
||||
}
|
||||
status = rocmtools::hsa_support::GetAmdExtTable().hsa_amd_memory_pool_free_fn(
|
||||
(pending.profile->command_buffer.ptr));
|
||||
if (status != HSA_STATUS_SUCCESS) {
|
||||
printf("Error: Couldn't free command buffer memory\n");
|
||||
}
|
||||
delete pending.profile;
|
||||
}
|
||||
}
|
||||
delete queue_info_session;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CreateBarrierPacket(const hsa_signal_t& packet_completion_signal,
|
||||
std::vector<Packet::packet_t>* transformed_packets) {
|
||||
hsa_barrier_and_packet_t barrier{0};
|
||||
@@ -439,6 +556,12 @@ void SignalAsyncHandler(const hsa_signal_t& signal, void* data) {
|
||||
if (status != HSA_STATUS_SUCCESS) fatal("hsa_amd_signal_async_handler failed");
|
||||
}
|
||||
|
||||
void signalAsyncHandlerATT(const hsa_signal_t& signal, void* data) {
|
||||
hsa_status_t status = hsa_support::GetAmdExtTable().hsa_amd_signal_async_handler_fn(
|
||||
signal, HSA_SIGNAL_CONDITION_EQ, 0, AsyncSignalHandlerATT, data);
|
||||
if (status != HSA_STATUS_SUCCESS) fatal("hsa_amd_signal_async_handler failed");
|
||||
}
|
||||
|
||||
void CreateSignal(uint32_t attribute, hsa_signal_t* signal) {
|
||||
hsa_status_t status =
|
||||
hsa_support::GetAmdExtTable().hsa_amd_signal_create_fn(1, 0, nullptr, attribute, signal);
|
||||
@@ -459,6 +582,7 @@ template <typename Integral> constexpr Integral bit_extract(Integral x, int firs
|
||||
return (x >> first) & bit_mask<Integral>(0, last - first);
|
||||
}
|
||||
|
||||
static int KernelInterceptCount = 0;
|
||||
std::atomic<uint32_t> WRITER_ID{0};
|
||||
/**
|
||||
* @brief This function is a queue write interceptor. It intercepts the
|
||||
@@ -487,9 +611,12 @@ void WriteInterceptor(const void* packets, uint64_t pkt_count, uint64_t user_pkt
|
||||
|
||||
bool is_counter_collection_mode = false;
|
||||
bool is_timestamp_collection_mode = false;
|
||||
bool is_att_collection_mode = false;
|
||||
bool is_pc_sampling_collection_mode = false;
|
||||
|
||||
std::vector<rocprofiler_att_parameter_t> att_parameters_data;
|
||||
uint32_t replay_mode_count = 0;
|
||||
std::vector<std::string> kernel_profile_names;
|
||||
std::vector<std::string> att_counters_names;
|
||||
|
||||
rocmtools::Session* session = nullptr;
|
||||
|
||||
@@ -509,6 +636,17 @@ void WriteInterceptor(const void* packets, uint64_t pkt_count, uint64_t user_pkt
|
||||
session->GetFilterIdWithKind(ROCPROFILER_DISPATCH_TIMESTAMPS_COLLECTION);
|
||||
rocmtools::Filter* filter = session->GetFilter(filter_id);
|
||||
buffer_id = filter->GetBufferId();
|
||||
} else if (session && session->FindFilterWithKind(ROCPROFILER_ATT_TRACE_COLLECTION)) {
|
||||
rocprofiler_filter_id_t filter_id =
|
||||
session->GetFilterIdWithKind(ROCPROFILER_ATT_TRACE_COLLECTION);
|
||||
rocmtools::Filter* filter = session->GetFilter(filter_id);
|
||||
att_parameters_data = filter->GetAttParametersData();
|
||||
is_att_collection_mode = true;
|
||||
buffer_id = session->GetFilter(session->GetFilterIdWithKind(ROCPROFILER_ATT_TRACE_COLLECTION))
|
||||
->GetBufferId();
|
||||
|
||||
att_counters_names = filter->GetCounterData();
|
||||
kernel_profile_names = std::get<std::vector<std::string>>(filter->GetProperty(ROCPROFILER_FILTER_KERNEL_NAMES));
|
||||
} else if (session && session->FindFilterWithKind(ROCPROFILER_PC_SAMPLING_COLLECTION)) {
|
||||
is_pc_sampling_collection_mode = true;
|
||||
}
|
||||
@@ -527,10 +665,12 @@ void WriteInterceptor(const void* packets, uint64_t pkt_count, uint64_t user_pkt
|
||||
std::vector<std::pair<rocmtools::profiling_context_t*, hsa_ven_amd_aqlprofile_profile_t*>>*
|
||||
profiles = nullptr;
|
||||
|
||||
|
||||
// Searching accross all the packets given during this write
|
||||
for (size_t i = 0; i < pkt_count; ++i) {
|
||||
auto& original_packet = static_cast<const hsa_barrier_and_packet_t*>(packets)[i];
|
||||
|
||||
// +Skip kernel dispatch IDs not wanted
|
||||
// Skip packets other than kernel dispatch packets.
|
||||
if (bit_extract(original_packet.header, HSA_PACKET_HEADER_TYPE,
|
||||
HSA_PACKET_HEADER_TYPE + HSA_PACKET_HEADER_WIDTH_TYPE - 1) !=
|
||||
@@ -659,6 +799,185 @@ void WriteInterceptor(const void* packets, uint64_t pkt_count, uint64_t user_pkt
|
||||
}
|
||||
/* Write the transformed packets to the hardware queue. */
|
||||
writer(&transformed_packets[0], transformed_packets.size());
|
||||
} else if (session_id.handle > 0 && pkt_count > 0 && is_att_collection_mode && session) {
|
||||
// att start
|
||||
// Getting Queue Data and Information
|
||||
auto& queue_info = *static_cast<Queue*>(data);
|
||||
std::lock_guard<std::mutex> lk(queue_info.qw_mutex);
|
||||
Agent::AgentInfo* agentInfo = &(hsa_support::GetAgentInfo(queue_info.GetGPUAgent().handle));
|
||||
|
||||
if (agentInfo->getName().substr(0, 4) != "gfx9") {
|
||||
printf("ATT collection is only supported for gfx9 at the moment!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Preparing att Packets
|
||||
Packet::packet_t start_packet{};
|
||||
Packet::packet_t stop_packet{};
|
||||
hsa_ven_amd_aqlprofile_profile_t* profile = nullptr;
|
||||
|
||||
if (att_parameters_data.size() > 0 && is_att_collection_mode) {
|
||||
// TODO sauverma: convert att_parameters_data to pass to generateattPackets
|
||||
std::vector<hsa_ven_amd_aqlprofile_parameter_t> att_params;
|
||||
int num_att_counters = 0;
|
||||
|
||||
for (rocprofiler_att_parameter_t& param : att_parameters_data) {
|
||||
att_params.push_back({
|
||||
static_cast<hsa_ven_amd_aqlprofile_parameter_name_t>(int(param.parameter_name)),
|
||||
param.value
|
||||
});
|
||||
num_att_counters += param.parameter_name == ROCPROFILER_ATT_PERFCOUNTER;
|
||||
}
|
||||
|
||||
if (att_counters_names.size() > 0) {
|
||||
MetricsDict* metrics_dict_ = MetricsDict::Create(agentInfo);
|
||||
|
||||
for (const std::string& counter_name : att_counters_names) {
|
||||
const Metric* metric = metrics_dict_->Get(counter_name);
|
||||
const BaseMetric* base = dynamic_cast<const BaseMetric*>(metric);
|
||||
if (!base) {
|
||||
printf("Invalid base metric value: %s\n", counter_name.c_str());
|
||||
exit(1);
|
||||
}
|
||||
std::vector<const counter_t*> counters;
|
||||
base->GetCounters(counters);
|
||||
hsa_ven_amd_aqlprofile_event_t event = counters[0]->event;
|
||||
if (event.block_name != HSA_VEN_AMD_AQLPROFILE_BLOCK_NAME_SQ) {
|
||||
printf("Only events from the SQ block can be selected for ATT.");
|
||||
exit(1);
|
||||
}
|
||||
att_params.push_back({
|
||||
static_cast<hsa_ven_amd_aqlprofile_parameter_name_t>(int(ROCPROFILER_ATT_PERFCOUNTER)),
|
||||
event.counter_id | (event.counter_id ? (0xF<<24) : 0)
|
||||
});
|
||||
num_att_counters += 1;
|
||||
}
|
||||
|
||||
hsa_ven_amd_aqlprofile_parameter_t zero_perf = {
|
||||
static_cast<hsa_ven_amd_aqlprofile_parameter_name_t>(int(ROCPROFILER_ATT_PERFCOUNTER)), 0};
|
||||
|
||||
// Fill other perfcounters with 0's
|
||||
for(; num_att_counters<16; num_att_counters++) att_params.push_back(zero_perf);
|
||||
}
|
||||
|
||||
// Get the PM4 Packets using packets_generator
|
||||
profile = Packet::GenerateATTPackets(queue_info.GetCPUAgent(), queue_info.GetGPUAgent(),
|
||||
att_params, &start_packet, &stop_packet);
|
||||
}
|
||||
|
||||
|
||||
// Searching across all the packets given during this write
|
||||
for (size_t i = 0; i < pkt_count; ++i) {
|
||||
auto& original_packet = static_cast<const hsa_barrier_and_packet_t*>(packets)[i];
|
||||
|
||||
// Skip packets other than kernel dispatch packets.
|
||||
if (bit_extract(original_packet.header, HSA_PACKET_HEADER_TYPE,
|
||||
HSA_PACKET_HEADER_TYPE + HSA_PACKET_HEADER_WIDTH_TYPE - 1) !=
|
||||
HSA_PACKET_TYPE_KERNEL_DISPATCH) {
|
||||
transformed_packets.emplace_back(packets_arr[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& kdispatch = static_cast<const hsa_kernel_dispatch_packet_s*>(packets)[i];
|
||||
uint64_t kernel_object = kdispatch.kernel_object;
|
||||
bool b_profile_this_object = false;
|
||||
|
||||
// Try to match the mangled kernel name with given matches in input.txt
|
||||
try {
|
||||
std::lock_guard<std::mutex> lock(ksymbol_map_lock);
|
||||
assert(ksymbols);
|
||||
const std::string& kernel_name = ksymbols->at(kernel_object);
|
||||
|
||||
// We want to initiate att profiling only if a match exists
|
||||
for(const std::string& kernel_matches : kernel_profile_names) {
|
||||
if (kernel_name.find(kernel_matches) != std::string::npos) {
|
||||
b_profile_this_object = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!b_profile_this_object) printf("Skipping: %s\n", kernel_name.c_str());
|
||||
} catch (...) {
|
||||
printf("Warning: Unknown name for object %lu\n", kernel_object);
|
||||
}
|
||||
|
||||
// If no match was found or intercept count > maximum desired profiles, skip this kernel.
|
||||
if (!b_profile_this_object || KernelInterceptCount >= MAX_ATT_PROFILES) {
|
||||
printf("Skipping: %lu\n", kernel_object);
|
||||
transformed_packets.emplace_back(packets_arr[i]);
|
||||
continue;
|
||||
}
|
||||
KernelInterceptCount += 1;
|
||||
|
||||
uint32_t writer_id = WRITER_ID.fetch_add(1, std::memory_order_release);
|
||||
|
||||
|
||||
if (att_parameters_data.size() > 0 && is_att_collection_mode && profile) {
|
||||
// Adding start packet and its barrier with a dummy signal
|
||||
hsa_signal_t dummy_signal{};
|
||||
dummy_signal.handle = 0;
|
||||
start_packet.header = HSA_PACKET_TYPE_VENDOR_SPECIFIC << HSA_PACKET_HEADER_TYPE;
|
||||
AddVendorSpecificPacket(&start_packet, &transformed_packets, dummy_signal);
|
||||
CreateBarrierPacket(start_packet.completion_signal, &transformed_packets);
|
||||
}
|
||||
|
||||
auto& packet = transformed_packets.emplace_back(packets_arr[i]);
|
||||
auto& dispatch_packet = reinterpret_cast<hsa_kernel_dispatch_packet_t&>(packet);
|
||||
|
||||
CreateSignal(HSA_AMD_SIGNAL_AMD_GPU_ONLY, &packet.completion_signal);
|
||||
// Adding the dispatch packet newly created signal to the pending signals
|
||||
// list to be processed by the signal interrupt
|
||||
rocprofiler_kernel_properties_t kernel_properties =
|
||||
set_kernel_properties(dispatch_packet, queue_info.GetGPUAgent());
|
||||
if (session && profile) {
|
||||
session->GetAttTracer()->AddPendingSignals(
|
||||
writer_id, dispatch_packet.kernel_object, dispatch_packet.completion_signal, session_id,
|
||||
buffer_id, profile, kernel_properties, (uint32_t)syscall(__NR_gettid), user_pkt_index);
|
||||
} else {
|
||||
session->GetAttTracer()->AddPendingSignals(
|
||||
writer_id, dispatch_packet.kernel_object, dispatch_packet.completion_signal, session_id,
|
||||
buffer_id, nullptr, kernel_properties, (uint32_t)syscall(__NR_gettid), user_pkt_index);
|
||||
}
|
||||
|
||||
// Make a copy of the original packet, adding its signal to a barrier packet
|
||||
if (original_packet.completion_signal.handle) {
|
||||
hsa_barrier_and_packet_t barrier{0};
|
||||
barrier.header = HSA_PACKET_TYPE_BARRIER_AND << HSA_PACKET_HEADER_TYPE;
|
||||
Packet::packet_t* __attribute__((__may_alias__)) pkt =
|
||||
(reinterpret_cast<Packet::packet_t*>(&barrier));
|
||||
transformed_packets.emplace_back(*pkt).completion_signal =
|
||||
original_packet.completion_signal;
|
||||
}
|
||||
|
||||
// Adding a barrier packet with the original packet's completion signal.
|
||||
hsa_signal_t interrupt_signal;
|
||||
CreateSignal(0, &interrupt_signal);
|
||||
|
||||
// Adding Stop PM4 Packets
|
||||
if (att_parameters_data.size() > 0 && is_att_collection_mode && profile) {
|
||||
stop_packet.header = HSA_PACKET_TYPE_VENDOR_SPECIFIC << HSA_PACKET_HEADER_TYPE;
|
||||
AddVendorSpecificPacket(&stop_packet, &transformed_packets, interrupt_signal);
|
||||
|
||||
// Added Interrupt Signal with barrier and provided handler for it
|
||||
CreateBarrierPacket(interrupt_signal, &transformed_packets);
|
||||
} else {
|
||||
hsa_barrier_and_packet_t barrier{0};
|
||||
barrier.header = HSA_PACKET_TYPE_BARRIER_AND << HSA_PACKET_HEADER_TYPE;
|
||||
barrier.completion_signal = interrupt_signal;
|
||||
Packet::packet_t* __attribute__((__may_alias__)) pkt =
|
||||
(reinterpret_cast<Packet::packet_t*>(&barrier));
|
||||
transformed_packets.emplace_back(*pkt);
|
||||
}
|
||||
|
||||
// Creating Async Handler to be called every time the interrupt signal is
|
||||
// marked complete
|
||||
signalAsyncHandlerATT(
|
||||
interrupt_signal,
|
||||
new queue_info_session_t{queue_info.GetGPUAgent(), session_id, queue_info.GetQueueID(),
|
||||
writer_id, interrupt_signal});
|
||||
}
|
||||
/* Write the transformed packets to the hardware queue. */
|
||||
writer(&transformed_packets[0], transformed_packets.size());
|
||||
// ATT end
|
||||
} else {
|
||||
/* Write the original packets to the hardware queue if no profiling session
|
||||
* is active */
|
||||
|
||||
@@ -43,7 +43,8 @@ GenericBuffer::GenericBuffer(rocprofiler_session_id_t session_id, rocprofiler_bu
|
||||
// pointer moves to the other buffer. Each buffer should be large enough to
|
||||
// hold at least 2 activity records, as record pairs may be written when
|
||||
// external correlation ids are used.
|
||||
const size_t allocation_size = 2 * std::max(2 * sizeof(rocprofiler_record_header_t), buffer_size);
|
||||
const size_t allocation_size =
|
||||
2 * std::max(2 * sizeof(rocprofiler_record_header_t), buffer_size);
|
||||
pool_begin_ = nullptr;
|
||||
AllocateMemory(&pool_begin_, allocation_size);
|
||||
assert(pool_begin_ != nullptr && "pool allocator failed");
|
||||
@@ -213,6 +214,12 @@ bool GetNextRecord(const rocprofiler_record_header_t* record,
|
||||
// break;
|
||||
*next = reinterpret_cast<const rocprofiler_record_header_t*>(tracer_record + 1);
|
||||
}
|
||||
case ROCPROFILER_ATT_TRACER_RECORD: {
|
||||
const rocprofiler_record_att_tracer_t* att_tracer_record =
|
||||
reinterpret_cast<const rocprofiler_record_att_tracer_t*>(record);
|
||||
*next = reinterpret_cast<const rocprofiler_record_header_t*>(att_tracer_record + 1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
const rocprofiler_record_tracer_t* tracer_record =
|
||||
reinterpret_cast<const rocprofiler_record_tracer_t*>(record);
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/* Copyright (c) 2022 Advanced Micro Devices, Inc.
|
||||
|
||||
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 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 "att.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace rocmtools {
|
||||
|
||||
namespace att {
|
||||
|
||||
AttTracer::AttTracer(rocprofiler_buffer_id_t buffer_id, rocprofiler_filter_id_t filter_id,
|
||||
rocprofiler_session_id_t session_id)
|
||||
: buffer_id_(buffer_id), filter_id_(filter_id), session_id_(session_id) {}
|
||||
AttTracer::~AttTracer() {}
|
||||
|
||||
void AttTracer::AddPendingSignals(uint32_t writer_id, uint64_t kernel_object,
|
||||
const hsa_signal_t& completion_signal,
|
||||
rocprofiler_session_id_t session_id,
|
||||
rocprofiler_buffer_id_t buffer_id,
|
||||
hsa_ven_amd_aqlprofile_profile_t* profile,
|
||||
rocprofiler_kernel_properties_t kernel_properties,
|
||||
uint32_t thread_id, uint64_t queue_index) {
|
||||
std::lock_guard<std::mutex> lock(sessions_pending_signals_lock_);
|
||||
if (sessions_pending_signals_.find(writer_id) == sessions_pending_signals_.end())
|
||||
sessions_pending_signals_.emplace(writer_id, std::vector<att_pending_signal_t>());
|
||||
sessions_pending_signals_.at(writer_id).emplace_back(
|
||||
att_pending_signal_t{kernel_object, completion_signal, session_id_, buffer_id, profile,
|
||||
kernel_properties, thread_id, queue_index});
|
||||
}
|
||||
|
||||
const std::vector<att_pending_signal_t>& AttTracer::GetPendingSignals(uint32_t writer_id) {
|
||||
std::lock_guard<std::mutex> lock(sessions_pending_signals_lock_);
|
||||
assert(sessions_pending_signals_.find(writer_id) != sessions_pending_signals_.end() &&
|
||||
"writer_id is not found in the pending_signals");
|
||||
return sessions_pending_signals_.at(writer_id);
|
||||
}
|
||||
|
||||
} // namespace att
|
||||
|
||||
} // namespace rocmtools
|
||||
@@ -0,0 +1,76 @@
|
||||
/* Copyright (c) 2022 Advanced Micro Devices, Inc.
|
||||
|
||||
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 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. */
|
||||
|
||||
#ifndef SRC_CORE_SESSION_ATT_ATT_H_
|
||||
#define SRC_CORE_SESSION_ATT_ATT_H_
|
||||
|
||||
#include <hsa/hsa_ven_amd_aqlprofile.h>
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "inc/rocprofiler.h"
|
||||
|
||||
namespace rocmtools {
|
||||
|
||||
typedef struct {
|
||||
uint64_t kernel_descriptor;
|
||||
hsa_signal_t signal;
|
||||
rocprofiler_session_id_t session_id;
|
||||
rocprofiler_buffer_id_t buffer_id;
|
||||
hsa_ven_amd_aqlprofile_profile_t* profile;
|
||||
rocprofiler_kernel_properties_t kernel_properties;
|
||||
uint32_t thread_id;
|
||||
uint64_t queue_index;
|
||||
} att_pending_signal_t;
|
||||
|
||||
namespace att {
|
||||
|
||||
class AttTracer {
|
||||
public:
|
||||
AttTracer(rocprofiler_buffer_id_t buffer_id, rocprofiler_filter_id_t filter_id,
|
||||
rocprofiler_session_id_t session_id);
|
||||
~AttTracer();
|
||||
|
||||
void AddPendingSignals(uint32_t writer_id, uint64_t kernel_object,
|
||||
const hsa_signal_t& completion_signal, rocprofiler_session_id_t session_id,
|
||||
rocprofiler_buffer_id_t buffer_id, hsa_ven_amd_aqlprofile_profile_t* profile,
|
||||
rocprofiler_kernel_properties_t kernel_properties, uint32_t thread_id,
|
||||
uint64_t queue_index);
|
||||
|
||||
const std::vector<att_pending_signal_t>& GetPendingSignals(uint32_t writer_id);
|
||||
|
||||
private:
|
||||
rocprofiler_buffer_id_t buffer_id_;
|
||||
rocprofiler_filter_id_t filter_id_;
|
||||
rocprofiler_session_id_t session_id_;
|
||||
|
||||
std::mutex sessions_pending_signals_lock_;
|
||||
std::map<uint32_t, std::vector<att_pending_signal_t>> sessions_pending_signals_;
|
||||
};
|
||||
|
||||
} // namespace att
|
||||
|
||||
} // namespace rocmtools
|
||||
|
||||
|
||||
#endif // SRC_CORE_SESSION_ATT_ATT_H_
|
||||
@@ -35,12 +35,25 @@ Filter::Filter(rocprofiler_filter_id_t id, rocprofiler_filter_kind_t filter_kind
|
||||
}
|
||||
case ROCPROFILER_COUNTERS_COLLECTION: {
|
||||
profiler_counter_names_.clear();
|
||||
for (uint32_t j = 0; j < data_count; j++)
|
||||
for (uint32_t j = 0; j < data_count; j++) {
|
||||
profiler_counter_names_.emplace_back(filter_data.counters_names[j]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ROCPROFILER_PC_SAMPLING_COLLECTION:
|
||||
case ROCPROFILER_ATT_TRACE: {
|
||||
case ROCPROFILER_PC_SAMPLING_COLLECTION:{
|
||||
break;
|
||||
}
|
||||
case ROCPROFILER_ATT_TRACE_COLLECTION: {
|
||||
att_parameters_.clear();
|
||||
profiler_counter_names_.clear();
|
||||
|
||||
for (uint32_t j = 0; j < data_count; j++) {
|
||||
if (filter_data.att_parameters[j].parameter_name != ROCPROFILER_ATT_PERFCOUNTER_NAME) {
|
||||
att_parameters_.emplace_back(filter_data.att_parameters[j]);
|
||||
} else {
|
||||
profiler_counter_names_.emplace_back(filter_data.att_parameters[j].counter_name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ROCPROFILER_SPM_COLLECTION: {
|
||||
@@ -49,8 +62,9 @@ Filter::Filter(rocprofiler_filter_id_t id, rocprofiler_filter_kind_t filter_kind
|
||||
}
|
||||
case ROCPROFILER_API_TRACE: {
|
||||
tracer_apis_.clear();
|
||||
for (uint32_t j = 0; j < data_count; j++)
|
||||
tracer_apis_.emplace_back(filter_data.trace_apis[j]);
|
||||
for (uint32_t j = 0; j < data_count; j++){
|
||||
tracer_apis_.emplace_back(filter_data.trace_apis[j]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -73,7 +87,7 @@ rocprofiler_filter_kind_t Filter::GetKind() { return kind_; }
|
||||
|
||||
std::mutex counter_data_lock;
|
||||
std::vector<std::string> Filter::GetCounterData() {
|
||||
if (kind_ == ROCPROFILER_COUNTERS_COLLECTION) {
|
||||
if (kind_ == ROCPROFILER_COUNTERS_COLLECTION || kind_ == ROCPROFILER_ATT_TRACE_COLLECTION) {
|
||||
std::lock_guard<std::mutex> lock(counter_data_lock);
|
||||
return profiler_counter_names_;
|
||||
}
|
||||
@@ -90,6 +104,16 @@ std::vector<rocprofiler_tracer_activity_domain_t> Filter::GetTraceData() {
|
||||
"Error: ROCMtools filter specified is not supported for "
|
||||
"profiler mode!\n");
|
||||
}
|
||||
|
||||
std::vector<rocprofiler_att_parameter_t> Filter::GetAttParametersData() {
|
||||
if (kind_ == ROCPROFILER_ATT_TRACE_COLLECTION) {
|
||||
return att_parameters_;
|
||||
}
|
||||
fatal(
|
||||
"Error: ROCMtools filter specified is not supported for "
|
||||
"ATT tracing mode!\n");
|
||||
}
|
||||
|
||||
rocprofiler_spm_parameter_t* Filter::GetSpmParameterData() {
|
||||
if (kind_ == ROCPROFILER_SPM_COLLECTION) {
|
||||
return spm_parameter_;
|
||||
@@ -143,7 +167,8 @@ void Filter::SetProperty(rocprofiler_filter_property_t property) {
|
||||
}
|
||||
case ROCPROFILER_FILTER_KERNEL_NAMES: {
|
||||
if (kind_ == ROCPROFILER_COUNTERS_COLLECTION ||
|
||||
kind_ == ROCPROFILER_DISPATCH_TIMESTAMPS_COLLECTION) {
|
||||
kind_ == ROCPROFILER_DISPATCH_TIMESTAMPS_COLLECTION ||
|
||||
kind_ == ROCPROFILER_ATT_TRACE_COLLECTION) {
|
||||
kernel_names_.clear();
|
||||
for (uint32_t j = 0; j < property.data_count; j++)
|
||||
kernel_names_.emplace_back(property.name_regex[j]);
|
||||
@@ -166,23 +191,29 @@ std::variant<std::vector<std::string>, uint32_t*> Filter::GetProperty(
|
||||
switch (kind) {
|
||||
case ROCPROFILER_FILTER_GPU_NAME: {
|
||||
property = agent_names_;
|
||||
break;
|
||||
}
|
||||
case ROCPROFILER_FILTER_RANGE: {
|
||||
property = static_cast<uint32_t*>(dispatch_range_);
|
||||
break;
|
||||
}
|
||||
case ROCPROFILER_FILTER_KERNEL_NAMES: {
|
||||
property = kernel_names_;
|
||||
break;
|
||||
}
|
||||
case ROCPROFILER_FILTER_HSA_TRACER_API_FUNCTIONS: {
|
||||
property = hsa_tracer_api_calls_;
|
||||
break;
|
||||
}
|
||||
case ROCPROFILER_FILTER_HIP_TRACER_API_FUNCTIONS: {
|
||||
property = hip_tracer_api_calls_;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fatal(
|
||||
"Error: ROCMtools filter specified is not supported for the given "
|
||||
"kind!");
|
||||
break;
|
||||
}
|
||||
return property;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ class Filter {
|
||||
|
||||
std::vector<std::string> GetCounterData();
|
||||
std::vector<rocprofiler_tracer_activity_domain_t> GetTraceData();
|
||||
|
||||
std::vector<rocprofiler_att_parameter_t> GetAttParametersData();
|
||||
void SetCallback(rocprofiler_sync_callback_t& callback);
|
||||
rocprofiler_sync_callback_t& GetCallback();
|
||||
|
||||
@@ -71,6 +71,7 @@ class Filter {
|
||||
std::vector<std::string> profiler_counter_names_; // Counter Names to collect
|
||||
std::vector<rocprofiler_tracer_activity_domain_t> tracer_apis_; // ROCTX/HIP/HSA API
|
||||
rocprofiler_spm_parameter_t* spm_parameter_; // spm parameter
|
||||
std::vector<rocprofiler_att_parameter_t> att_parameters_; // ATT Parameters
|
||||
|
||||
rocprofiler_sync_callback_t callback_;
|
||||
};
|
||||
|
||||
@@ -54,6 +54,10 @@ Session::~Session() {
|
||||
// delete tracer_;
|
||||
// tracer_started_.exchange(false, std::memory_order_release);
|
||||
// }
|
||||
if (att_tracer_started_.load(std::memory_order_release)) {
|
||||
delete att_tracer_;
|
||||
att_tracer_started_.exchange(false, std::memory_order_release);
|
||||
}
|
||||
// {
|
||||
// std::lock_guard<std::mutex> lock(filters_lock_);
|
||||
// buffers_.clear();
|
||||
@@ -99,6 +103,13 @@ void Session::Start() {
|
||||
GetFilter(GetFilterIdWithKind(ROCPROFILER_COUNTERS_COLLECTION))->GetId(), session_id_);
|
||||
profiler_started_.exchange(true, std::memory_order_release);
|
||||
}
|
||||
if (FindFilterWithKind(ROCPROFILER_ATT_TRACE_COLLECTION)) {
|
||||
if (att_tracer_started_.load(std::memory_order_release)) delete att_tracer_;
|
||||
att_tracer_ = new att::AttTracer(
|
||||
GetFilter(GetFilterIdWithKind(ROCPROFILER_ATT_TRACE_COLLECTION))->GetBufferId(),
|
||||
GetFilter(GetFilterIdWithKind(ROCPROFILER_ATT_TRACE_COLLECTION))->GetId(), session_id_);
|
||||
att_tracer_started_.exchange(true, std::memory_order_release);
|
||||
}
|
||||
|
||||
if (FindFilterWithKind(ROCPROFILER_SPM_COLLECTION)) {
|
||||
if (spm_started_.load(std::memory_order_release)) delete spmcounter_;
|
||||
@@ -176,6 +187,7 @@ rocprofiler_session_id_t Session::GetId() { return session_id_; }
|
||||
bool Session::IsActive() { return is_active_; }
|
||||
|
||||
profiler::Profiler* Session::GetProfiler() { return profiler_; }
|
||||
att::AttTracer* Session::GetAttTracer() { return att_tracer_; }
|
||||
tracer::Tracer* Session::GetTracer() { return tracer_; }
|
||||
spm::SpmCounters* Session::GetSpmCounter() { return spmcounter_; }
|
||||
pc_sampler::PCSampler* Session::GetPCSampler() { return pc_sampler_; }
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "src/core/session/filter.h"
|
||||
#include "profiler/profiler.h"
|
||||
#include "tracer/tracer.h"
|
||||
#include "att/att.h"
|
||||
#include "spm/spm.h"
|
||||
#include "src/pcsampler/session/pc_sampler.h"
|
||||
|
||||
@@ -58,6 +59,7 @@ class Session {
|
||||
|
||||
profiler::Profiler* GetProfiler();
|
||||
tracer::Tracer* GetTracer();
|
||||
att::AttTracer* GetAttTracer();
|
||||
spm::SpmCounters* GetSpmCounter();
|
||||
pc_sampler::PCSampler* GetPCSampler();
|
||||
|
||||
@@ -104,6 +106,8 @@ class Session {
|
||||
|
||||
std::atomic<bool> profiler_started_{false};
|
||||
std::atomic<bool> tracer_started_{false};
|
||||
std::atomic<bool> att_tracer_started_{false};
|
||||
att::AttTracer* att_tracer_;
|
||||
std::atomic<bool> spm_started_{false};
|
||||
|
||||
profiler::Profiler* profiler_;
|
||||
|
||||
@@ -172,6 +172,134 @@ std::vector<std::string> GetCounterNames() {
|
||||
return counters;
|
||||
}
|
||||
|
||||
typedef std::tuple<
|
||||
std::vector<std::pair<rocprofiler_att_parameter_name_t, uint32_t>>,
|
||||
std::vector<std::string>, std::vector<std::string>
|
||||
> att_parsed_input_t;
|
||||
|
||||
att_parsed_input_t GetATTParams() {
|
||||
std::vector<std::pair<rocprofiler_att_parameter_name_t, uint32_t>> parameters;
|
||||
std::vector<std::string> kernel_names;
|
||||
std::vector<std::string> counters_names;
|
||||
const char* path = getenv("COUNTERS_PATH");
|
||||
|
||||
// List of parameters the user can set. Maxvalue is unused.
|
||||
std::unordered_map<std::string, rocprofiler_att_parameter_name_t> ATT_PARAM_NAMES{};
|
||||
|
||||
ATT_PARAM_NAMES["att: TARGET_CU"] = ROCPROFILER_ATT_COMPUTE_UNIT_TARGET;
|
||||
ATT_PARAM_NAMES["SIMD_MASK"] = ROCPROFILER_ATT_MAXVALUE;
|
||||
ATT_PARAM_NAMES["PERFCOUNTER_ID"] = ROCPROFILER_ATT_PERFCOUNTER;
|
||||
ATT_PARAM_NAMES["PERFCOUNTER"] = ROCPROFILER_ATT_PERFCOUNTER_NAME;
|
||||
ATT_PARAM_NAMES["PERFCOUNTERS_COL_PERIOD"] = ROCPROFILER_ATT_MAXVALUE;
|
||||
ATT_PARAM_NAMES["KERNEL"] = ROCPROFILER_ATT_MAXVALUE;
|
||||
ATT_PARAM_NAMES["REDUCED_MEMORY"] = ROCPROFILER_ATT_MAXVALUE;
|
||||
/*
|
||||
ATT_PARAM_NAMES["ATT_MASK"] = ROCMTOOLS_ATT_MASK;
|
||||
ATT_PARAM_NAMES["TOKEN_MASK"] = ROCMTOOLS_ATT_TOKEN_MASK;
|
||||
ATT_PARAM_NAMES["TOKEN_MASK2"] = ROCMTOOLS_ATT_TOKEN_MASK2;
|
||||
ATT_PARAM_NAMES["SE_MASK"] = ROCMTOOLS_ATT_SE_MASK;
|
||||
ATT_PARAM_NAMES["PERF_MASK"] = ROCMTOOLS_ATT_PERF_MASK;
|
||||
ATT_PARAM_NAMES["PERF_CTRL"] = ROCMTOOLS_ATT_PERF_CTRL;
|
||||
*/
|
||||
|
||||
// Default values used for token generation.
|
||||
std::unordered_map<std::string, uint32_t> default_params = {
|
||||
{"ATT_MASK", 0x3F01},
|
||||
{"TOKEN_MASK", 0x344B},
|
||||
{"TOKEN_MASK2", 0x3FFFF}
|
||||
};
|
||||
|
||||
bool started_att_counters = false;
|
||||
|
||||
if (!path) return {parameters, kernel_names, counters_names};
|
||||
|
||||
std::string line;
|
||||
std::ifstream trace_file(path);
|
||||
if (!trace_file.is_open()) {
|
||||
std::cout << "Unable to open att trace file." << std::endl;
|
||||
return {parameters, kernel_names, counters_names};
|
||||
}
|
||||
|
||||
while (getline(trace_file, line)) {
|
||||
if (line.find("//") != std::string::npos)
|
||||
line = line.substr(0, line.find("//")); // Remove comments
|
||||
|
||||
auto pos = line.find('=');
|
||||
if (pos == std::string::npos)
|
||||
continue;
|
||||
|
||||
std::string param_name = line.substr(0, pos);
|
||||
uint32_t param_value;
|
||||
|
||||
if (param_name == "att: TARGET_CU") started_att_counters = true;
|
||||
if (!started_att_counters) continue;
|
||||
|
||||
if (param_name == "KERNEL") {
|
||||
kernel_names.push_back(line.substr(pos+1));
|
||||
continue;
|
||||
} else if (param_name == "PERFCOUNTER") {
|
||||
counters_names.push_back(line.substr(pos+1));
|
||||
continue;
|
||||
} else { // param_value is a number
|
||||
try {
|
||||
auto hexa_pos = line.find("0x", pos); // Is it hex?
|
||||
if (hexa_pos != std::string::npos)
|
||||
param_value = stoi(line.substr(hexa_pos+2), 0, 16); // hexadecimal
|
||||
else
|
||||
param_value = stoi(line.substr(pos+1), 0, 10); // decimal
|
||||
} catch(...) {
|
||||
printf("Error: Invalid parameter value %s - (%s)\n",
|
||||
line.substr(pos+1, line.size()).c_str(), line.c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (param_name == "PERFCOUNTERS_COL_PERIOD") {
|
||||
default_params["TOKEN_MASK"] |= 0x4000;
|
||||
param_value = ((param_value & 0x1F) << 8) | 0x007F;
|
||||
parameters.push_back(std::make_pair(ROCPROFILER_ATT_PERF_CTRL, param_value));
|
||||
continue;
|
||||
} else if (param_name == "SIMD_MASK") {
|
||||
default_params["ATT_MASK"] &= ~0xF00;
|
||||
default_params["ATT_MASK"] |= (param_value<<8) & 0xF00;
|
||||
continue;
|
||||
} else if (param_name == "att: TARGET_CU") {
|
||||
default_params["ATT_MASK"] &= ~0xF;
|
||||
default_params["ATT_MASK"] |= param_value & 0xF;
|
||||
} else if (param_name == "PERFCOUNTER_ID") {
|
||||
param_value = param_value | (param_value ? (0xF<<24) : 0);
|
||||
} else if (param_name == "REDUCED_MEMORY") {
|
||||
default_params["TOKEN_MASK2"] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ATT_PARAM_NAMES.find(param_name) != ATT_PARAM_NAMES.end()) {
|
||||
parameters.push_back(std::make_pair(ATT_PARAM_NAMES[param_name], param_value));
|
||||
try { default_params.erase(param_name); } catch(...) {};
|
||||
} else {
|
||||
printf("Error: Invalid parameter name: %s - (%s)\nList of available params:\n",
|
||||
param_name.c_str(), line.c_str());
|
||||
for (auto& name : ATT_PARAM_NAMES) printf("%s\n", name.first.c_str());
|
||||
}
|
||||
}
|
||||
trace_file.close();
|
||||
|
||||
if (!started_att_counters) return {parameters, kernel_names, counters_names};
|
||||
|
||||
ATT_PARAM_NAMES["ATT_MASK"] = ROCPROFILER_ATT_MASK;
|
||||
ATT_PARAM_NAMES["TOKEN_MASK"] = ROCPROFILER_ATT_TOKEN_MASK;
|
||||
ATT_PARAM_NAMES["TOKEN_MASK2"] = ROCPROFILER_ATT_TOKEN_MASK2;
|
||||
|
||||
for (auto& param : default_params)
|
||||
parameters.push_back(std::make_pair(ATT_PARAM_NAMES[param.first], param.second));
|
||||
|
||||
// If no kernel names were provided, collect them all.
|
||||
// Empty string always returns true for "str.find()".
|
||||
if (kernel_names.size() == 0) kernel_names.push_back("");
|
||||
|
||||
return {parameters, kernel_names, counters_names};
|
||||
}
|
||||
|
||||
void finish() {
|
||||
if (amd_sys_handler.load(std::memory_order_release)) {
|
||||
amd_sys_handler.exchange(false, std::memory_order_release);
|
||||
@@ -335,19 +463,34 @@ ROCPROFILER_EXPORT bool OnLoad(HsaApiTable* table, uint64_t runtime_version,
|
||||
std::vector<const char*> counters_;
|
||||
|
||||
if (counters.size() > 0) {
|
||||
printf("ROCMTools: Collecting the following counters:\n");
|
||||
printf("ROCProfilerV2: Collecting the following counters:\n");
|
||||
for (size_t i = 0; i < counters.size(); i++) {
|
||||
counters_.emplace_back(counters.at(i).c_str());
|
||||
printf("- %s\n", counters_.back());
|
||||
}
|
||||
}
|
||||
// ATT Parameters
|
||||
std::vector<rocprofiler_att_parameter_t> parameters;
|
||||
std::vector<std::pair<rocprofiler_att_parameter_name_t, uint32_t>> params;
|
||||
std::vector<std::string> kernel_names;
|
||||
std::vector<std::string> att_counters_names;
|
||||
std::tie(params, kernel_names, att_counters_names) = GetATTParams();
|
||||
|
||||
for (auto& kv_pair : params)
|
||||
parameters.emplace_back(rocprofiler_att_parameter_t{kv_pair.first, kv_pair.second});
|
||||
for (std::string& name : att_counters_names) {
|
||||
rocprofiler_att_parameter_t param;
|
||||
param.parameter_name = ROCPROFILER_ATT_PERFCOUNTER_NAME;
|
||||
param.counter_name = name.c_str();
|
||||
parameters.emplace_back(param);
|
||||
}
|
||||
|
||||
CHECK_ROCMTOOLS(rocprofiler_create_session(ROCPROFILER_KERNEL_REPLAY_MODE, &session_id));
|
||||
|
||||
bool want_pc_sampling = getenv("ROCPROFILER_PC_SAMPLING");
|
||||
|
||||
std::vector<rocprofiler_filter_kind_t> filters_requested;
|
||||
if ((counters.size() == 0 && (apis_requested.size() == 0 || getenv("ROCPROFILER_KERNEL_TRACE")))
|
||||
if (((counters.size() == 0 && parameters.size() == 0) && (apis_requested.size() == 0 || getenv("ROCPROFILER_KERNEL_TRACE")))
|
||||
|| want_pc_sampling /* PC sampling needs a profiler, even it's doing
|
||||
nothing */)
|
||||
filters_requested.emplace_back(ROCPROFILER_DISPATCH_TIMESTAMPS_COLLECTION);
|
||||
@@ -356,6 +499,7 @@ ROCPROFILER_EXPORT bool OnLoad(HsaApiTable* table, uint64_t runtime_version,
|
||||
}
|
||||
if (counters.size() > 0) filters_requested.emplace_back(ROCPROFILER_COUNTERS_COLLECTION);
|
||||
if (apis_requested.size() > 0) filters_requested.emplace_back(ROCPROFILER_API_TRACE);
|
||||
if (parameters.size() > 0) filters_requested.emplace_back(ROCPROFILER_ATT_TRACE_COLLECTION);
|
||||
|
||||
rocprofiler_buffer_id_t buffer_id;
|
||||
CHECK_ROCMTOOLS(rocprofiler_create_buffer(
|
||||
@@ -364,7 +508,7 @@ ROCPROFILER_EXPORT bool OnLoad(HsaApiTable* table, uint64_t runtime_version,
|
||||
rocprofiler_session_id_t session_id, rocprofiler_buffer_id_t buffer_id) {
|
||||
if (plugin) plugin->write_buffer_records(record, end_record, session_id, buffer_id);
|
||||
},
|
||||
0x9999, &buffer_id));
|
||||
1<<20, &buffer_id));
|
||||
buffer_ids.emplace_back(buffer_id);
|
||||
|
||||
rocprofiler_buffer_id_t buffer_id_1;
|
||||
@@ -374,7 +518,7 @@ ROCPROFILER_EXPORT bool OnLoad(HsaApiTable* table, uint64_t runtime_version,
|
||||
rocprofiler_session_id_t session_id, rocprofiler_buffer_id_t buffer_id_1) {
|
||||
if (plugin) plugin->write_buffer_records(record, end_record, session_id, buffer_id_1);
|
||||
},
|
||||
0x9999, &buffer_id_1));
|
||||
1<<20, &buffer_id_1));
|
||||
buffer_ids.emplace_back(buffer_id_1);
|
||||
|
||||
for (rocprofiler_filter_kind_t filter_kind : filters_requested) {
|
||||
@@ -412,6 +556,26 @@ ROCPROFILER_EXPORT bool OnLoad(HsaApiTable* table, uint64_t runtime_version,
|
||||
filter_ids.emplace_back(filter_id);
|
||||
break;
|
||||
}
|
||||
case ROCPROFILER_ATT_TRACE_COLLECTION: {
|
||||
printf("Enabling ATT Tracing\n");
|
||||
rocprofiler_filter_id_t filter_id;
|
||||
|
||||
std::vector<const char*> kernel_names_c;
|
||||
for (auto& name : kernel_names) kernel_names_c.push_back(name.data());
|
||||
|
||||
rocprofiler_filter_property_t property = {};
|
||||
property.kind = ROCPROFILER_FILTER_KERNEL_NAMES;
|
||||
property.data_count = kernel_names_c.size();
|
||||
property.name_regex = kernel_names_c.data();
|
||||
|
||||
CHECK_ROCMTOOLS(
|
||||
rocprofiler_create_filter(session_id, ROCPROFILER_ATT_TRACE_COLLECTION,
|
||||
rocprofiler_filter_data_t{.att_parameters = ¶meters[0]},
|
||||
parameters.size(), &filter_id, property));
|
||||
CHECK_ROCMTOOLS(rocprofiler_set_filter_buffer(session_id, filter_id, buffer_id_1));
|
||||
filter_ids.emplace_back(filter_id);
|
||||
break;
|
||||
}
|
||||
case ROCPROFILER_PC_SAMPLING_COLLECTION: {
|
||||
puts("Enabling PC sampling");
|
||||
rocprofiler_filter_id_t filter_id;
|
||||
|
||||
@@ -185,6 +185,12 @@ target_link_libraries ( profiler_api_test ${ROCPROFILER_TARGET} ${ROCPROFILER_TA
|
||||
target_include_directories(profiler_api_test PRIVATE ${TEST_DIR} ${ROOT_DIR} ${HSA_RUNTIME_INC_PATH} ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/tests/featuretests/profiler)
|
||||
add_dependencies(tests profiler_api_test)
|
||||
|
||||
set_source_files_properties(discretetests/api/att_test.cpp PROPERTIES HIP_SOURCE_PROPERTY_FORMAT 1)
|
||||
hip_add_executable ( profiler_api_att_test discretetests/api/att_test.cpp utils/test_utils.cpp )
|
||||
target_link_libraries ( profiler_api_att_test ${ROCPROFILER_TARGET} ${ROCPROFILER_TARGET} hsa-runtime64::hsa-runtime64 Threads::Threads dl stdc++fs )
|
||||
target_include_directories(profiler_api_att_test PRIVATE ${TEST_DIR} ${ROOT_DIR} ${HSA_RUNTIME_INC_PATH} ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/tests/featuretests/profiler)
|
||||
add_dependencies(tests profiler_api_att_test)
|
||||
|
||||
set_source_files_properties(discretetests/api/spm_test.cpp PROPERTIES HIP_SOURCE_PROPERTY_FORMAT 1)
|
||||
hip_add_executable ( profiler_api_spm_test discretetests/api/spm_test.cpp utils/test_utils.cpp )
|
||||
target_link_libraries ( profiler_api_spm_test ${ROCPROFILER_TARGET} ${ROCPROFILER_TARGET} hsa-runtime64::hsa-runtime64 Threads::Threads dl stdc++fs )
|
||||
|
||||
+259
@@ -0,0 +1,259 @@
|
||||
/******************************************************************************
|
||||
Copyright (c) 2018 Advanced Micro Devices, Inc. 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 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 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 <hip/hip_runtime.h>
|
||||
#include <rocprofiler.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/test_utils.h"
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define HIP_ASSERT(x) x
|
||||
#else
|
||||
#define HIP_ASSERT(x) (assert((x)==hipSuccess))
|
||||
#endif
|
||||
|
||||
|
||||
#define WIDTH 1024
|
||||
#define HEIGHT 1024
|
||||
|
||||
#define NUM (WIDTH*HEIGHT)
|
||||
|
||||
#define THREADS_PER_BLOCK_X 16
|
||||
#define THREADS_PER_BLOCK_Y 16
|
||||
#define THREADS_PER_BLOCK_Z 1
|
||||
|
||||
|
||||
|
||||
/** \mainpage ROC Profiler API Test
|
||||
*
|
||||
* \section introduction Introduction
|
||||
*
|
||||
* The goal of this test is to test ROCmTools APIs to collect ATT traces.
|
||||
*
|
||||
* A simple vectoradd_float kernel is launched and the trace results are printed
|
||||
* as console output
|
||||
*/
|
||||
|
||||
|
||||
// function to check att tracing API status
|
||||
auto CheckApi = [](rocprofiler_status_t status) {
|
||||
if (status != ROCPROFILER_STATUS_SUCCESS) {
|
||||
std::cout << "ROCmTools API Error" << std::endl;
|
||||
}
|
||||
assert(status == ROCPROFILER_STATUS_SUCCESS);
|
||||
};
|
||||
|
||||
|
||||
// callback function to dump att tracing data
|
||||
void FlushCallback(const rocprofiler_record_header_t* record,
|
||||
const rocprofiler_record_header_t* end_record, rocprofiler_session_id_t session_id,
|
||||
rocprofiler_buffer_id_t buffer_id) {
|
||||
while (record < end_record) {
|
||||
if (!record) break;
|
||||
else if (record->kind == ROCPROFILER_ATT_TRACER_RECORD){
|
||||
const rocprofiler_record_att_tracer_t* att_tracer_record =
|
||||
reinterpret_cast<const rocprofiler_record_att_tracer_t*>(record);
|
||||
size_t name_length;
|
||||
CheckApi(rocprofiler_query_kernel_info_size(ROCPROFILER_KERNEL_NAME, att_tracer_record->kernel_id,
|
||||
&name_length));
|
||||
const char* kernel_name_c = static_cast<const char*>(malloc(name_length * sizeof(char)));
|
||||
CheckApi(rocprofiler_query_kernel_info(ROCPROFILER_KERNEL_NAME, att_tracer_record->kernel_id,
|
||||
&kernel_name_c));
|
||||
int gpu_index = att_tracer_record->gpu_id.handle;
|
||||
printf(
|
||||
"Kernel Info:\n\tGPU Index: %d\n\tKernel Name: %s\n",
|
||||
gpu_index, kernel_name_c);
|
||||
|
||||
// Get the number of shader engine traces
|
||||
int se_num = att_tracer_record->shader_engine_data_count;
|
||||
|
||||
// iterate over each shader engine att trace
|
||||
for (int i = 0; i < se_num; i++){
|
||||
|
||||
printf("\n\n-------------- shader_engine %d --------------\n\n", i);
|
||||
rocprofiler_record_se_att_data_t* se_att_trace = &att_tracer_record->shader_engine_data[i];
|
||||
uint32_t size = se_att_trace->buffer_size;
|
||||
const unsigned short* data_buffer_ptr = reinterpret_cast<const unsigned short*>(se_att_trace->buffer_ptr);
|
||||
|
||||
// Print the buffer in terms of shorts (16 bits)
|
||||
for (uint32_t j = 0; j < (size / sizeof(short)); j++)
|
||||
printf("%04x\n", data_buffer_ptr[j]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
CheckApi(rocprofiler_next_record(record, &record, session_id, buffer_id));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
__global__ void
|
||||
vectoradd_float(float* __restrict__ a, const float* __restrict__ b, const float* __restrict__ c, int width, int height)
|
||||
|
||||
{
|
||||
|
||||
int x = hipBlockDim_x * hipBlockIdx_x + hipThreadIdx_x;
|
||||
int y = hipBlockDim_y * hipBlockIdx_y + hipThreadIdx_y;
|
||||
|
||||
int i = y * width + x;
|
||||
if ( i < (width * height)) {
|
||||
a[i] = b[i] + c[i];
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
int LaunchVectorAddKernel() {
|
||||
|
||||
float* hostA;
|
||||
float* hostB;
|
||||
float* hostC;
|
||||
|
||||
float* deviceA;
|
||||
float* deviceB;
|
||||
float* deviceC;
|
||||
|
||||
hipDeviceProp_t devProp;
|
||||
hipGetDeviceProperties(&devProp, 0);
|
||||
std::cout << " System minor " << devProp.minor << std::endl;
|
||||
std::cout << " System major " << devProp.major << std::endl;
|
||||
std::cout << " agent prop name " << devProp.name << std::endl;
|
||||
|
||||
|
||||
|
||||
std::cout << "hip Device prop succeeded " << std::endl ;
|
||||
|
||||
|
||||
int i;
|
||||
int errors;
|
||||
|
||||
hostA = (float*)malloc(NUM * sizeof(float));
|
||||
hostB = (float*)malloc(NUM * sizeof(float));
|
||||
hostC = (float*)malloc(NUM * sizeof(float));
|
||||
|
||||
// initialize the input data
|
||||
for (i = 0; i < NUM; i++) {
|
||||
hostB[i] = (float)i;
|
||||
hostC[i] = (float)i*100.0f;
|
||||
}
|
||||
|
||||
HIP_ASSERT(hipMalloc((void**)&deviceA, NUM * sizeof(float)));
|
||||
HIP_ASSERT(hipMalloc((void**)&deviceB, NUM * sizeof(float)));
|
||||
HIP_ASSERT(hipMalloc((void**)&deviceC, NUM * sizeof(float)));
|
||||
|
||||
HIP_ASSERT(hipMemcpy(deviceB, hostB, NUM*sizeof(float), hipMemcpyHostToDevice));
|
||||
HIP_ASSERT(hipMemcpy(deviceC, hostC, NUM*sizeof(float), hipMemcpyHostToDevice));
|
||||
|
||||
|
||||
hipLaunchKernelGGL(vectoradd_float,
|
||||
dim3(WIDTH/THREADS_PER_BLOCK_X, HEIGHT/THREADS_PER_BLOCK_Y),
|
||||
dim3(THREADS_PER_BLOCK_X, THREADS_PER_BLOCK_Y),
|
||||
0, 0,
|
||||
deviceA ,deviceB ,deviceC ,WIDTH ,HEIGHT);
|
||||
|
||||
|
||||
HIP_ASSERT(hipMemcpy(hostA, deviceA, NUM*sizeof(float), hipMemcpyDeviceToHost));
|
||||
|
||||
// verify the results
|
||||
errors = 0;
|
||||
for (i = 0; i < NUM; i++) {
|
||||
if (hostA[i] != (hostB[i] + hostC[i])) {
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if (errors!=0) {
|
||||
printf("FAILED: %d errors\n",errors);
|
||||
} else {
|
||||
printf ("PASSED!\n");
|
||||
}
|
||||
|
||||
HIP_ASSERT(hipFree(deviceA));
|
||||
HIP_ASSERT(hipFree(deviceB));
|
||||
HIP_ASSERT(hipFree(deviceC));
|
||||
|
||||
free(hostA);
|
||||
free(hostB);
|
||||
free(hostC);
|
||||
|
||||
//hipResetDefaultAccelerator();
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
// inititalize rocmtools
|
||||
CheckApi(rocprofiler_initialize());
|
||||
|
||||
// Att trace collection parameters
|
||||
rocprofiler_session_id_t session_id;
|
||||
std::vector<rocprofiler_att_parameter_t> parameters;
|
||||
parameters.emplace_back(rocprofiler_att_parameter_t{ROCPROFILER_ATT_COMPUTE_UNIT_TARGET, 0});
|
||||
parameters.emplace_back(rocprofiler_att_parameter_t{ROCPROFILER_ATT_MASK, 0x0F00});
|
||||
parameters.emplace_back(rocprofiler_att_parameter_t{ROCPROFILER_ATT_TOKEN_MASK, 0x344B});
|
||||
parameters.emplace_back(rocprofiler_att_parameter_t{ROCPROFILER_ATT_TOKEN_MASK2, 0xFFFF});
|
||||
|
||||
// create a session
|
||||
CheckApi(rocprofiler_create_session(ROCPROFILER_KERNEL_REPLAY_MODE, &session_id));
|
||||
|
||||
// create a buffer to hold att trace records for each kernel launch
|
||||
rocprofiler_buffer_id_t buffer_id;
|
||||
CheckApi(rocprofiler_create_buffer(session_id, FlushCallback, 0x9999, &buffer_id));
|
||||
|
||||
// create a filter for collecting att traces
|
||||
rocprofiler_filter_id_t filter_id;
|
||||
rocprofiler_filter_property_t property = {};
|
||||
CheckApi(rocprofiler_create_filter(session_id, ROCPROFILER_ATT_TRACE_COLLECTION,
|
||||
rocprofiler_filter_data_t{.att_parameters = ¶meters[0]},
|
||||
parameters.size(), &filter_id, property));
|
||||
|
||||
// set buffer for the filter
|
||||
CheckApi(rocprofiler_set_filter_buffer(session_id, filter_id, buffer_id));
|
||||
|
||||
// activating att tracing session
|
||||
CheckApi(rocprofiler_start_session(session_id));
|
||||
|
||||
// Launch a kernel
|
||||
LaunchVectorAddKernel();
|
||||
|
||||
// deactivate att tracing session
|
||||
CheckApi(rocprofiler_terminate_session(session_id));
|
||||
|
||||
// dump att tracing data
|
||||
CheckApi(rocprofiler_flush_data(session_id, buffer_id));
|
||||
|
||||
// destroy session
|
||||
CheckApi(rocprofiler_destroy_session(session_id));
|
||||
|
||||
// finalize att tracing by destroying rocmtool object
|
||||
CheckApi(rocprofiler_finalize());
|
||||
return 0;
|
||||
}
|
||||
@@ -43,10 +43,11 @@ file(GLOB ROCPROFILER_SRC_API_FILES ${PROJECT_SOURCE_DIR}/src/api/*.cpp)
|
||||
file(GLOB ROCPROFILER_SRC_PROFILER_FILES ${PROJECT_SOURCE_DIR}/src/core/session/profiler/profiler.cpp)
|
||||
file(GLOB ROCPROFILER_TRACER_SRC_FILES ${PROJECT_SOURCE_DIR}/src/core/session/tracer/*.cpp)
|
||||
file(GLOB ROCPROFILER_ROCTRACER_SRC_FILES ${PROJECT_SOURCE_DIR}/src/core/session/tracer/src/*.cpp)
|
||||
file(GLOB ROCPROFILER_ATT_SRC_FILES ${PROJECT_SOURCE_DIR}/src/core/session/att/att.cpp)
|
||||
file(GLOB ROCPROFILER_SRC_CLASS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rocmtool.cpp)
|
||||
file(GLOB ROCPROFILER_SPM_SRC_FILES ${PROJECT_SOURCE_DIR}/src/core/session/spm/spm.cpp)
|
||||
|
||||
set(ROCPROFILER_SRC_FILES ${ROCPROFILER_SRC_API_FILES} ${ROCPROFILER_SRC_CLASS_FILES} ${ROCPROFILER_SRC_PROFILER_FILES})
|
||||
set(ROCPROFILER_SRC_FILES ${ROCPROFILER_SRC_API_FILES} ${ROCPROFILER_SRC_CLASS_FILES} ${ROCPROFILER_SRC_PROFILER_FILES} ${ROCPROFILER_ATT_SRC_FILES})
|
||||
|
||||
set(CORE_HSA_DIR ${PROJECT_SOURCE_DIR}/src/core/hsa)
|
||||
file(GLOB CORE_HSA_SRC_FILES ${CORE_HSA_DIR}/*.cpp)
|
||||
|
||||
@@ -31,11 +31,12 @@ file(GLOB CORE_COUNTERS_SRC_FILES ${PROJECT_BINARY_DIR}/src/api/*_counter.cpp)
|
||||
file(GLOB ROCPROFILER_SRC_PROFILER_FILES ${PROJECT_SOURCE_DIR}/src/core/session/profiler/profiler.cpp)
|
||||
file(GLOB ROCPROFILER_TRACER_SRC_FILES ${PROJECT_SOURCE_DIR}/src/core/session/tracer/*.cpp)
|
||||
file(GLOB ROCPROFILER_ROCTRACER_SRC_FILES ${PROJECT_SOURCE_DIR}/src/core/session/tracer/src/*.cpp)
|
||||
file(GLOB ROCPROFILER_ATT_SRC_FILES ${PROJECT_SOURCE_DIR}/src/core/session/att/att.cpp)
|
||||
file(GLOB ROCPROFILER_SRC_CLASS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rocmtool.cpp)
|
||||
file(GLOB ROCPROFILER_SPM_SRC_FILES ${PROJECT_SOURCE_DIR}/src/core/session/spm/spm.cpp)
|
||||
file(GLOB ROCPROFILER_SRC_API_FILES ${PROJECT_SOURCE_DIR}/src/api/*.cpp)
|
||||
|
||||
set(ROCPROFILER_SRC_FILES ${ROCPROFILER_SRC_API_FILES} ${ROCPROFILER_SRC_CLASS_FILES} ${ROCPROFILER_SRC_PROFILER_FILES})
|
||||
set(ROCPROFILER_SRC_FILES ${ROCPROFILER_SRC_API_FILES} ${ROCPROFILER_SRC_CLASS_FILES} ${ROCPROFILER_SRC_PROFILER_FILES} ${ROCPROFILER_ATT_SRC_FILES})
|
||||
|
||||
set(CORE_HSA_DIR ${PROJECT_SOURCE_DIR}/src/core/hsa)
|
||||
file(GLOB CORE_HSA_SRC_FILES ${CORE_HSA_DIR}/*.cpp)
|
||||
|
||||
Ссылка в новой задаче
Block a user