Making ATT work with Profilerv2
Change-Id: Ic9334aa80e40faaaf5c1a79ba37dbe52e8d31253
This commit is contained in:
@@ -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;
|
||||
}
|
||||
Executable
+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)
|
||||
Executable
+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.")
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
|
After Width: | Height: | Size: 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;
|
||||
}
|
||||
Reference in New Issue
Block a user